Following one rule turned a passing gate into 16 failures. Both rules were right.
Two policies, each locally correct, sharing one assumption nobody owned.
TL;DR
Two rules in the same codebase. Each one sensible, each enforced by its own tooling, each written by someone who was right.
Obey the first and the second fails — naming a requirement that is demonstrably still satisfied. Not a bug in either rule. They shared an assumption that neither of them stated, and because no one owned the assumption, no one was wrong when it broke.
249 components were exposed. 32 were already failing. Nobody had made a mistake.
The case this post is about
Rule one — keep the executable spine short. A command's runtime file must stay under 200 lines. Past that, a cohesive block moves out to a shared sub-module and leaves a pointer:
> Load layers/<area>/commands/_shared/<name>.md
A pre-write hook enforces it. Try to save a 201-line runtime and the write is refused, with the remedy spelled out. Good rule: it keeps an executable file executable instead of letting it silt up into documentation.
Rule two — every command proves its own contract. Each command has a verify script asserting its runtime contains the clauses the contract requires — the halt classes, the account resolution, the prohibition on passing a secret on the command line. Also a good rule: it is the difference between a documented guarantee and an actual one.
Both have been in place for months. Both have their own enforcement. Neither mentions the other.

The symptom
I had a runtime at exactly 200 lines. Every edit I attempted was refused by the hook, correctly,
so I did what the rule says: moved one cohesive block — a step with its commands, its halt and
its own two > Load lines — verbatim into a sub-module, leaving the heading and a pointer.
Then I ran the command's verify script:
idea-medium-post: 16 failure(s)
MP-9 no halt class for skipping the visual-asset step
MP-9 runtime does not dispatch the Stitch producer
MP-9b runtime does not require the art_source field
MP-10 runtime does not pass the brief by file (--intent-file)
MP-10 runtime does not pass a project palette
…
Sixteen failures. Every one naming a clause that was still there, one file along, exactly where the other rule had just required me to put it.
I had complied with a policy and been punished by a gate, and neither the policy nor the gate was wrong.
Why the obvious fix failed
"Put the content back." The hook refuses the write. The two rules are not merely in tension; in that state they are mutually unsatisfiable — there is no arrangement of that file which passes both.
"The gate is too strict, relax it." The clauses it checks are load-bearing: a missing halt
class means a step can be skipped silently, a missing --intent-file means a brief gets mangled
by the shell. Deleting the assertion to clear the failure would remove a real guarantee to fix a
reporting defect — the costliest trade in the catalogue.
"The slim rule is overreach." Also no. The runtime is read and executed; the 200-line ceiling is what stops it collecting prose until nobody can find the steps.
"Whoever broke it should fix it." Nobody broke it. Both rules shipped working. Both were tested — against their own concern. That is what makes this class hard: there is no commit to revert and no author to ask.
The actual mechanism
The gate asserted on a file. The slim rule moves content between files. Both are reasonable in isolation, and together they encode a shared premise that neither one writes down:
the runtime is one file.

That premise was true when each rule was authored. It stopped being true the first time a runtime crossed 200 lines — and the rule that made it stop being true is the one enforced by a hook, so the breakage arrives automatically, as a consequence of compliance.
Three properties made it invisible for months:
It only fires on compliance. Ignore the slim rule and nothing fails. The gate goes red exactly when someone does the right thing, which inverts the usual signal — the people who trigger it are the ones following policy, and their natural conclusion is that they did the move wrong.
Each rule's tests pass. The slim hook has canaries proving it blocks an oversized file. The verify has canaries proving it catches a missing clause. Neither suite contains a case where a runtime is correctly split, because that scenario belongs to both rules and therefore to neither.
The failure is articulate and wrong. "Runtime does not pass a project palette" is a specific, actionable, confidently-stated claim about a file that does pass a project palette. A vague error invites investigation. A precise false one invites you to go and add the clause that is already there.
Then the scale. One grep across the repository: 249 components had already-split runtimes
with gates that read only the runtime file, and 32 of those were red right now — reporting
requirements that were sitting one file along, in some cases for weeks. One of them wanted a
term that lives in two separate sub-modules the runtime loads.
Nobody had written a bad rule. The number was a property of the pair.
The fix
Make the gate read what the system reads. When the platform executes the command it follows the pointers, so the verification does too:
# The runtime is the runtime PLUS what it loads — one level, deliberately.
RUNTIME_RAW="$REPO_ROOT/layers/<area>/commands/<name>.md" # preflight-ignore: a path, not a secret
RUNTIME="$(bash "$REPO_ROOT/core/scripts/capsule-runtime-resolve.sh" "$RUNTIME_RAW" "$REPO_ROOT")"
[ "$RUNTIME" != "$RUNTIME_RAW" ] && trap 'rm -f "$RUNTIME"' EXIT
Three details decided whether this was a fix or a second bug.
RUNTIME_RAW survives. Some gates also assert the runtime is under 200 lines. Point that
check at the resolved text and it measures the resolution, which is deliberately larger — and
the fix would break the very rule it exists to serve. The size check reads the file; the clause
checks read the file plus its loads.
One level deep, not recursive. A recursive resolve would let a sub-module pull in half the codebase and still satisfy every assertion, which is the same false green in a longer coat.
A dangling pointer is not swallowed. If a > Load names a file that does not exist, the
resolver contributes nothing and the clause check fails honestly. Reporting it separately would
count one defect twice.
The deeper fix is the one that is not code: the shared assumption now has a name and an owner. The resolver's header states it — a runtime is a file plus what it loads — so the next rule written against runtimes inherits the corrected premise instead of the old one.
How we proved it
Not by asserting the gate now passes, which it would do if the resolver silently returned nothing.
I simulated the exact relocation the slim rule prescribes on a different command: moved every
clause its gate requires out of the runtime and into a sub-module, leaving a > Load.
clauses remaining in the runtime file: 0
gate verdict: PASS
Zero occurrences in the file the gate used to read, and it still passes — because it follows the pointer. Before the fix, that same move produced 16 failures. Runtime restored byte-for-byte afterwards.
Then the population, measured rather than estimated:
32 gates targeted · 16 now pass · 16 still fail
And the 16 survivors are the point. They name clauses that genuinely exist nowhere — one wants a library term absent from the runtime and every sub-module it loads; another sits in a sub-module the runtime never actually loads. The fix removed the failures caused by the rule conflict and left the ones caused by real defects, which is the only outcome that distinguishes a fix from a mute button.
My first attempt at the sweep, incidentally, broke 233 files — but that is its own post.

What this generalizes to
The useful question is not "which rule is wrong" — often neither is. It is what do these two rules both believe, that neither of them says?
Look for shared nouns. Both of mine used the word "runtime" and meant different things: one meant a file on disk, the other meant the instructions a command executes. The conflict lived entirely in that gap, and it was invisible because the word was the same.
Suspect any failure that appears on compliance. If doing the right thing turns something red, you are almost certainly looking at a policy pair rather than a defect. It is a distinctive signal and it is routinely misread as "I must have done the move wrong" — which is what I thought for the first ten minutes.
Test the interaction, not just the rule. Each rule had canaries. Neither suite had a case for correctly split and correctly asserted, because that case belongs to both and so was owned by neither. The scenarios that fall between two owners are the ones that reach production.
Count the exposure before you decide it is minor. My instinct was "edge case, one command". One grep said 249 exposed, 32 already failing. The instinct was not slightly wrong; it was wrong by two orders of magnitude, and the correction cost four seconds.
Give the assumption an owner. The code fix stops the current bleeding. What stops the next one is that the premise is now written down somewhere a future rule-author will read — because the real defect was never in either rule. It was in the space between them, where nobody was looking because nobody had been assigned to.
Related
- I applied my fix to 234 files at once. It broke 233 of them. — what happened when I fixed this badly
- The same rule in two files is how agent-written code drifts — one rule, two homes
- The agent that writes the check that blocks it — when a gate agrees with its author by construction
Keep reading
This is part of Architecture decisions & code review — the judgement calls that outlast the code they were made about. Follow MobileByteSensei for the rest.
One post a week, no digest
New writing when it lands. No roundups, no course pitch, no "10 tips".