We all use Claude Code, and we are all productive. The problem does not appear while you are coding — it appears when you pick up someone else’s work. This is a story we have already lived through, the method that prevents it, and what using that method feels like on an ordinary day.
Uscha · spec-driven, tool-agnostic methodology · ← → to navigate
Each person configured Claude Code using their best judgment. And each person’s judgment is sound — but it remains their own.
It lives in each session’s chat: what was decided, why, and what was left out. The chat gets compacted, deleted, lost.
A different CLAUDE.md (or none), memory prompts, different skills. The same request produces different results depending on who handles it.
“The agent said it’s ready and the tests pass.” Which tests? Do they assert what matters? Nobody measures it — we trust the narrative.
None of this hurts today. It hurts three weeks later, when someone else inherits the work.
Vale builds the coupon feature with Claude Code as usual: straight into the code, iterating in the chat. It works well. Along the way, Sales sends one detail over Slack: a coupon that expired less than 24 hours ago must still be accepted (a grace period). She explains it to the agent in the chat, the agent implements it, tests go green, merge.
Where was the grace-period rule documented? In a Slack message that will scroll into oblivion and a Claude Code chat that gets compacted. The code contains an uncommented expiredAt + 24h. No SPEC and no test explicitly asserts the rule.
He needs to add category-specific expiration rules. He opens the code and finds + 24h. He asks HIS Claude Code — with a different setup, a different CLAUDE.md, and different memory — why it is there.
Martín’s agent is not lying: it is guessing with confidence — without Vale’s context, the grace period IS indistinguishable from a bug. The tests pass because they never pinned down that rule. The following Monday, Sales reports that “coupons are broken” at the worst possible time.
The decision (a 24-hour grace period) never made it into a versioned file. A code comment? It explains, but it does not protect: nothing tests it, it cannot stop a merge, and the agent that “normalizes” the code deletes it along with the line.
Martín’s agent does not behave like Vale’s: a different CLAUDE.md, different skills, different memory. The behavior was not reproducible.
“Green tests” sounded like evidence, but nobody measured whether the tests asserted what mattered. The critical rule did not have a single test.
What about code review? The reviewer had the same context as Martín: none. The diff looked like a legitimate off-by-one fix with green tests — and it was approved for the same reason the agent proposed it. Context was missing, not diligence.
A spec-driven methodology that starts before the spec, advances only with captured evidence, and stops at a human-approved merge. We all run it the same way, over the same files, with the same Claude Code skills.
It is not a process separate from the work: it is the same day, with three new moments — let yourself be questioned before, let the loop measure during, and read the real state at the end.
Friction is placed where it is cheap (half an hour of questions at 10:00) to avoid it where it is expensive (Sales reporting broken coupons on Monday).
Before touching code comes the interrogation. The skill does not agree with everything — it keeps asking until the shape is clear: contradictions, ambiguous terms, failure modes. One question at a time.
The question that nobody asked in the original story is asked here by the method — and the answer does not die in a chat.
As decisions settle, they are written down — not at the end, not in the chat. The build reads files; CI reads files; the next developer reads files.
SPEC.mdObservable behavior, I/O, errors, the grace-period rule and its rationale, rollback.
docs/adr/*.mdOne durable decision per file: what was chosen, over which alternative, and why. Code links to it with // ADR: <slug>.
ACCEPTANCE.mdCriteria as testable checkboxes — “coupon expired less than 24h ago → accepted”. This feeds readiness.
CONTEXT.mdThe domain glossary: it eliminates ambiguous language before it reaches the code.
CONSTITUTION.mdWhat is NEVER acceptable, regardless of which trade-off wins. A violation is recorded as a BLOCKER (flag-blocker) and stops everything until a human decides.
RISKS · HANDOFFResidual risk and what to read before coding — a letter to the next developer, written while the context is fresh.
The orchestrator takes the SPEC + ACCEPTANCE, builds, and runs a QA loop that measures instead of believing. BLOCKING results come from real artifacts parsed by qa_ledger.py — tests, coverage, linters, fact gates. What the agent reports about itself is recorded separately as narrative — and a measured red always vetoes a narrated green.
Coverage, tests, and linter findings parsed from the actual XML. Self-reported results are recorded separately: narrative, not data.
gate-check (does the change weaken tests or thresholds?) and the other gates are persisted with log-gate: one red result blocks convergence.
The loop opens the PR, shows readiness (a 0–100 KPI) with its breakdown, and stops. A person merges it. Always.
The grace-period rule now has a criterion in ACCEPTANCE.md and a test that explicitly asserts it. It is no longer a mysterious + 24h: it is specified, pinned-down behavior.
The key point: the score is not negotiable. You may have completed 90 points’ worth of work — if one test is red, the cap is 35.
This answers failure 3 in the story: “done” was a narrative. In the method, narrative is retained — but it never decides. Parsed artifacts decide: the Surefire XML, the JaCoCo report, the diff structure, the golden-file bytes.
Three weeks later, Martín picks up coupons. His agent — using the same shared setup and the same skills — reads the same files the method produced: SPEC, ADRs, ACCEPTANCE.
Two layers of defense: the intent is written where the agent reads it (versioned files), and even if an agent tried to “fix” the rule, the test asserting it would turn red and gate-check would catch any attempt to delete or disable it — a BLOCKER that convergence cannot pass (weakened assertions are flagged for review; --strict gates them).
A worked example of the method — a minimal feature, applyDiscount(monto, %), taken from start to finish. The methodology does not promise you will never deviate: it promises every deviation will have a gate that catches it.
Look at step 7: the agent lowered a threshold to pass — and the gate that caught it exists because agents do exactly that. The method does not assume good behavior: it verifies it.
A gate that reads a FACT (bytes, XML, diff structure) can stop the work. A gate that guesses from prose can only whisper — because a gate with false positives gets disabled, and a dead gate is worse than none.
| Gate | Reads | |
|---|---|---|
| gate-check | diff structure: tests deleted/disabled, thresholds lowered or removed | BLOCKS |
| golden-diff | bytes vs .approved (migrations — the only artifact the agent cannot write: a PreToolUse hook blocks it) | BLOCKS |
| simplicity-check | diff budget: size, nesting, hunks (OVERBUILT = trim it) | BLOCKS |
| structural spec-check | is there an out-of-scope section? are there acceptance criteria? (present or absent) | BLOCKS |
| prose spec-check | heuristic: vague criteria with no metric | ADVISES |
| readiness | 0–100 state KPI (with hard caps: red tests ≤35, open BLOCKER/CRITICAL ≤65) | REPORTS |
And the rule that closes the loop on Vale and Martín’s story: measured evidence beats narrative — a red test snapshot vetoes any “green tests” claim from any agent.
The opening question for every change: what can this break, and what would that failure cost? The answer determines the size of the process — we do not drag the entire machine behind a configuration tweak.
| Profile | Example | Minimum gates |
|---|---|---|
| A · Low | minor UI / config | build + relevant test — nothing more |
| B · Normal | local feature / bug fix | tests + static analysis + review |
| C · Critical | payments / security | unit + integration + security + rollback |
| D · Multi-system | public API / events | contract tests + versioning |
| E · Legacy | refactor / migration | golden + regression protection |
process heuristic — not automated
WE apply the table when classifying the change (there is no --profile flag that selects gates automatically). The coupon feature was B; if it touched payment collection, it would be C — and discovery asks that question.
/uscha-discovery (new idea) or /uscha-adr-refine (known feature). Let yourself be questioned./uscha-devloop measures with the ledger; fact gates are recorded with log-gate.When you touch old code that nobody fully understands, the risk is not breaking what you know it does — it is losing behavior nobody knew was intentional (someone else’s five-year-old “24h grace period”).
/uscha-characterize runs the ORIGINAL code against a real corpus and emits .received fixtures — observed behavior, not inferred behavior. AND STOPS.
A human reviews and establishes them as .approved. The agent cannot write them: a PreToolUse hook blocks the write. It is the only artifact beyond the agent’s reach — and that is why it exists.
Every pass runs golden-diff: byte-for-byte against the approved files. DIVERGE = stop. No fixtures = NOT-RUN, never “passed.”
Rigor scales with the blast radius. A UI fix runs build+test and nothing more. The full machine is for changes that can break expensive things — and there, ceremony costs less than the coupon incident.
It slows you down for 30 minutes at the start — where friction is cheap — to spare you the expensive failure: a confidently wrong build. Martín lost MORE debugging on Monday than Vale spent on the entire discovery.
It works in isolation. It breaks at handoff — and nobody here works alone. The method does not replace your judgment: it makes that judgment legible to whoever comes next. You, three months from now, are also “whoever comes next.”
Adopting the method “because it feels better” would be exactly the flaw the method fights. Define criteria BEFORE running it, make them measurable at closeout — and allow them to say NO:
At the end, another team member extends the feature by reading ONLY the files in the repo. If they need to ask the author, the method failed its central promise — record that as a finding; do not excuse it.
Did any gate stop a real problem that would have slipped through without the method (a lowered threshold, a weakened test, a vague criterion)? If no gate catches anything throughout the pilot, the machinery did not earn its cost — that is data too.
Record every false positive and every step that got in the way without adding value. A method that receives only praise is not being tested. Use this evidence to adjust budgets and thresholds.
PR readiness with its breakdown (and which cap limited it, if any) + churn reported separately. Not to reward the number: to see whether the KPI tells the true story of the work’s state.
if the pilot fails the criteria, adjust the method or discard it — that is also the method working.
Everyone keeps using Claude Code — with all its power. What changes is where truth lives: in versioned files that any agent and any person can read, with evidence measured instead of narrated, and with a human owning every merge.
Uscha · instantiated in Claude Code via uscha-kit 1.50.0 · questions → now