[Bug] Plan mode ignores CLAUDE.md fail-fast and no-fallback policies
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. missingproject_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:
- Lazy GPU→CPU transfer - HW frames stay in GPU until data() called. Metal renderer can skip CPU entirely.
- Automatic fallback chain - VideoToolbox → sw decode. Metal → QPainter. Each level falls back gracefully.
- 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:
- Silent fallbacks that should be explicit errors
- Missing asserts on invariants
- 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!
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗