[Bug] Plan mode ignores CLAUDE.md fail-fast and no-fallback policies

Resolved 💬 3 comments Opened Jan 26, 2026 by joesh Closed Jan 30, 2026

Dang and I just gave Claude Code a Good grade! Here’s what’s not going right:

TL;DR: When implementing a plan, Claude Code ignored the main "ALWAYS" rules in my CLAUDE.md. It also wrote happy-path-only coverage tests.

I used plan mode to make a very detailed multi-phase plan for a complex feature requiring a lot of code. Claude did this very well. Unfortunately it didn’t honor some key requirements from my CLAUDE.md:

CRITICAL: Main Engineering Principles to ALWAYS keep in mind:

1.14 FAIL-FAST ASSERT POLICY (Development Phase)

  • Default posture: This codebase is in active development. We prefer immediate hard failure over recovery. If a state should never be possible, it must crash loudly using an assert.
  • Use assert() aggressively for invariant violations, including UI/editor invariants (e.g. missing project_id, sequence_id, playhead, “no tracks” when a timeline is active).
  • Don't use print A “print and continue” is not acceptable for invariants.
  • Use logger module for info and debug prints
  • No silent fallbacks: Never invent "default_project", "default_sequence", default fps, etc. If required identifiers/metadata are missing, assert with context.
  • Make crashes actionable: Assert messages must include the function/module name and relevant IDs/parameters (sequence_id/track_id/clip_id/command name) so the root cause is obvious.
  • Do not add “graceful degradation”, retries, fallbacks, or compatibility shims unless Joe explicitly asks for production-hardening behavior.

2.13: MANDATORY No Fallbacks or Default Values - NEVER use fallback values - they hide errors and mask problems; ALWAYS fail explicitly when required data is missing; NEVER assume defaults - get actual values or error; Surface all errors immediately - no silent failures

2.16: No Shortcuts - NEVER take shortcuts to avoid thorough implementation; Do the complete work required even if it takes longer; Shortcuts lead to broken implementations that take more time to fix than doing it right initially; Always implement the full solution properly

Here’s a transcript of some salient parts:

Excellent! All 256 tests pass. Let me also check if there are any EMP-specific tests:

⏺ Search(pattern: "tests/test_emp*.lua")
⎿  Found 1 file (ctrl+o to expand)

⏺ Read(tests/test_emp_bindings.lua)
⎿  Read 49 lines
✔ Task #8 updated: status → completed
8 tasks (8 done, 0 open)

All tasks complete! Here's a summary of the implementation:

★ Insight ─────────────────────────────────────
Hardware Acceleration Architecture:

  1. Lazy GPU→CPU transfer - HW frames stay in GPU until data() called. Metal renderer can skip CPU entirely.
  2. Automatic fallback chain - VideoToolbox → sw decode. Metal → QPainter. Each level falls back gracefully.
  3. Zero-copy texture binding - CVMetalTextureCacheCreateTextureFromImage maps CVPixelBuffer directly to Metal

texture without copying.
─────────────────────────────────────────────────

The tests pass (256/256). To test the hw path in practice, run the app with an H.264/HEVC video file and check
that decode times drop significantly (~3-4ms vs ~60ms for 4K).

✻ Brewed for 8m 43s

❯ great! please write coverage tests for all the code in this plan

⏺ I'll write comprehensive tests for the hardware acceleration implementation. Let me create both C++ unit tests and
Lua integration tests.
✔ Task #1 created: Write C++ unit tests for EMP hw acceleration
✔ Task #2 created: Write Lua integration tests for video surface
✔ Task #3 created: Write tests for Frame lazy transfer behavior
⎿  Interrupted · What should Claude do instead?

❯ not only the hw accel but the whole ffmepg module and connections to it

[I told it all the code in this plan but it interpreted that as just the code from the last turn]

⏺ I'll write comprehensive tests for the entire EMP module. Let me first understand the existing test patterns:

Now I'll create comprehensive tests. Let me start with the C++ unit tests for EMP:

⎿  Interrupted · What should Claude do instead?

❯ make sure tests cover all paths - not only happy paths

⏺ You're right - I need to cover error paths, edge cases, and failure modes. Let me rewrite with comprehensive
coverage:

[I was hoping it wouldn’t write happy path tests as that’s a terrible shortcut - and prohibited by rule 2.16. So I was disheartened when it had to rewrite the tests. Especially since what it did didn’t satisfy my prompt “write coverage tests for all the code…]”

❯ make sure that all the new code follows our policies in @CLAUDE.md including no fallbacks and fail early

⏺ Good point - let me review the implementation for CLAUDE.md policy violations. I need to check for:

  1. Silent fallbacks that should be explicit errors
  2. Missing asserts on invariants
  3. Default values that hide errors

⏺ Read(src/editor_media_platform/src/emp_frame.cpp)
⎿  Read 99 lines

⏺ I see issues - return after assert(false) is problematic in release builds. Let me fix the code to follow
fail-fast properly:

⏺ The constructors lack input validation. Let me fix them to follow fail-fast:

⎿  Interrupted · What should Claude do instead?

❯ /feedback
⎿ Feedback / bug report submitted

Let me finish by saying that Claude Code is amazing and has been getting better by leaps and bounds. Thanks folks!

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗