Andres Massello
1/0
Complete documentation · instantiation in Claude Code and Codex

Uscha: you bring the idea, the method builds the rest.

A spec-driven, tool-agnostic methodology that starts before the SPEC: from a vague idea + reference material, the assistant proposes the shape of the system, you decide, and only then is it specified, built, and moved forward with evidence alone. This doc covers the instantiation in Claude Code and Codex with the uscha-kit.

Idea → Discovery → Ready → SPEC → ADR? → Build → Verify → Evidence → Human gate

Convention in this doc: in the kit already implemented · new added in this version · proposal design agreed, not yet in code · evaluated — deferred design on the record, decided against for now (dated in ISSUES-DEFERRED.md). No smoke: whatever doesn't exist is flagged.

map first, then the territory

The system map.

The whole territory in one diagram: the flow line, its inner loop (converge without chasing zero), the frontier of the outer loop, and the CONSTITUTION no station may violate. Map first; then the doc walks it station by station.

System map — the flow, its inner loop, and the frontierhuman owns the terminus
CONSTITUTION — invariants no station may violate Idea01 Discovery02 Ready03 SPEC / ADR04 Build05 Verify06 Evidence07 Human gate08 inner loop · converge, don't chase zero outer loop · heartbeat (deferred 2026-09-02) — human still owns merge
station evidence gate human-owned inner loop outer loop
visual overview

The specification, at a glance.

The evidence engine at the center, the flow's phases on the left, the six verification layers on the right, the principles in the strip, and the agent's pieces that hold it up at the bottom.

Uscha Evidence engine orchestrates · builds · verifies and proves with real evidence 1 Discovery From the idea to the system's shape: it proposes, you decide. 2 SPEC What must happen: verifiable, testable behavior. 3 ADR · CONSTITUTION Why this shape · what is never violated. 4 Build Builds against the plan, commit by commit. 5 Verify Evidence produced by execution, not narrated. Functional Does it meet the SPEC and acceptance? Technical Compiles, tests, standards, no bugs? Regression Did it break what already worked? Contract Did it break APIs, schemas, events? Security No new HIGH/CRITICAL findings? Operational Does it deploy, observe, and roll back? THE FLOW (what gets done) THE 6 LAYERS OF TRUTH (how it's verified) Evidence, not trust Asserted by execution (CI / script), not the author. The human approves Merge and release are decided by a person. Converge, not zero Stops when it's clean, not "perfect". Legacy-aware Freezes the old debt, blocks the new. CLAUDE.md / AGENTS.md the repo's stable protocol Skills (/command) the kit's 9 skills discovery → rubric Sub-agents QA in parallel, clean context Hooks automatic gates, real evidence Multi-repo (--add-dir) integration QA across repos qa_ledger.py measures and scores: readiness + rebuild
01 from idea to product, with evidence

The flow at a glance.

The full cycle is a single line, runnable by a person, an agent, or the CI. The tool executes; the methodology governs; the evidence decides; the human approves.

Idea Discovery Ready SPEC ADR? Build Verify Evidence Human gate

Two things the flow guarantees: lowering the cost of entry (you don't have to design the system to be able to start — Discovery proposes that) and raising the certainty of the output (an honest state, with evidence and blockers, tells you how ready it truly is). In Claude Code all of this lives in nine callable skills (kit 1.65.0) and a measurement engine in Python.

/uscha-discovery/uscha-adr-refine/uscha-devloop/uscha-sysdoc/uscha-reverse-discovery/uscha-characterize/uscha-rubric/uscha-mirador/uscha-statusqa_ledger.py
02 the method has two conversation modes

Two fronts: discovery vs adr-refine.

The classic mistake is asking you to write entities, endpoints, and error cases from the start. But a new system begins earlier: all you know is what you want to achieve. That's why there are two fronts; you pick by starting point — and they emit different packages: /uscha-discovery writes the full spec package (CONTEXT, DOMAIN-MODEL/CONSTITUTION, SPEC, docs/adr, ACCEPTANCE, RISKS/HANDOFF); /uscha-adr-refine emits docs/adr/*.md + ACCEPTANCE.md (plus optional CONSTITUTION entries).

/uscha-discovery — "I don't know the how"

Greenfield. You bring idea + constraints + reference material. The assistant proposes the domain, the API surface, and architecture options; you react and decide. The key inversion: you don't author the structure, you approve it. One question at a time, each with its recommended answer.

/uscha-adr-refine — "I know the what, precision is missing"

A feature inside an existing system. The shape is already known; the adversarial interview paints the edges: dirty cases, errors, idempotency, inviolable constraints, out-of-scope. It emits no artifacts until it converges.

Both skills have allowed-tools: Read, Write, Glob, Grep (discovery adds WebFetch to read manuals/PDFs/URLs). Neither touches code: they generate clarity, not implementation.

The principle that defines them

Grill, don't agree. A discovery where you agreed with everything failed — an agreeable interviewer just inherits your blind spots and hands them back formatted as a plan. The value is in the questions — contradictions, fuzzy terms, missing failure modes, unspoken constraints — not in validating. The expensive failure it prevents: a confident build of the wrong shape.

03 the conversation becomes files in the repo

The document package.

The front ends up writing the package directly into the repo as decisions crystallize — it doesn't hoard everything for the end. The build reads it from the files, not from the chat.

FileWhat it contains
CONTEXT.mdDomain glossary. Created with the first resolved term; sharpens fuzzy language ("is 'account' a Customer or a User?").
DOMAIN-MODEL.mdThe proposed core entities and their relationships — the "shape" you proposed and the human approved.
SPEC.mdObjective/value, risk, scope/out-of-scope, behavior, inputs/outputs/errors, acceptance, test plan, operation, rollback.
docs/adr/*.mdOne per durable decision. Includes Implementation Plan + Verification (checkboxes) → it's an executable spec.
ACCEPTANCE.mdDefinition of Done as - [ ] + success metrics. It's the file the readiness KPI measures downstream.
RISKS.mdResidual risks, assumptions, points that need human approval.
HANDOFF.mdWhat to read before coding + hard "do not" rules + required evidence.

Why it matters even if it's all Claude Code: context resets (a new session, a /clear, or a compaction don't have the chat), sub-agents read files, a teammate or the CI builds from the repo, and the audit trail stays durable. The truth lives in versioned files.

04 they work together, they answer different things

SPEC ≠ ADR.

If it describes observable behavior, it goes in SPEC. If it justifies a choice between alternatives, it goes in ADR. Almost every non-trivial change needs a SPEC; only some need a formal ADR.

SPEC — what must happen?

Behavior, rules, inputs/outputs/errors, acceptance criteria, tests, operation. It's the build-and-verify contract.

ADR — why this way?

A technical decision, the alternatives discarded, and the consequences. Architectural memory, not a task list.

An ADR is written with judgment

Only if the decision meets all three: hard to reverse, surprising without context, and the result of a real trade-off. Otherwise it's noise that buries the important ones.

# docs/adr/ADR-NNN-<slug>.md
## Status: Accepted            # proposed/accepted/deprecated/superseded
## Context / Forces
## Alternatives: A) … B) … C) …
## Decision
## Reasons
## Consequences (+ / -)
## Implementation Plan          # affected paths · patterns · tests
## Verification
- [ ] <criterion checkable by an agent>

The Implementation Plan is what makes the ADR executable: Claude Code reads it and implements it without asking again. During the build, the code links back: // ADR: <slug> — see docs/adr/ADR-NNN-<slug>.md, which makes it safe to supersede (you find everything the ADR governs).

05 above the ADRs in the kit

The CONSTITUTION layer.

The ADR chooses between alternatives. The CONSTITUTION forbids: it records the invariants that no ADR or SPEC may violate, whatever trade-off wins. It's the project's hierarchy of truth.

SPEC says what must happen. ADR says why this shape was chosen. CONSTITUTION says what is never acceptable. An ADR may choose Postgres vs Redis to cache a session token; an ADR cannot choose "store the certificate in plaintext" — the CONSTITUTION vetoes that before any alternatives are discussed.

## CONSTITUTION.md — project invariants
# Security (non-negotiable)
- Secrets never in logs or in the repo       # CWE-532 / CWE-798
- All external input validated                # CWE-20
- Parameterized SQL only, never concat        # CWE-89
# Domain (example — fill per project)
- Mandatory idempotency on critical operations
- Business invariants that must never break
- Never two effects for the same requestId
# Operation
- No destructive migration without explicit rollback
- No merge without a human gate

Real state in the kit in the kit

It's a layer of its own: templates/CONSTITUTION.md, versioned, with invariants mapped to CWE. /uscha-discovery and /uscha-adr-refine write/extend it (an ADR cannot contradict it: it escalates, it isn't approved); /uscha-devloop reads it in Phase 0 and consults it before touching governed areas. A breach must be logged by the agent via flag-blocker --kind constitution; once logged it caps readiness ≤65 and blocks convergence until a human clears it with --resolve. The engine does not read CONSTITUTION.md itself — detection is the agent/human's duty; enforcement-after-logging is the engine's.

Why it's the right pattern

It's not a loose add-on: it's where the SOTA landed. Spec Kit has /speckit.constitution; the OSS dpolivaev/Uscha (same name as yours) defines its rules in CONSTITUTION.md with human-approval gates. Formalizing it aligns you with the field's convergence.

06 not every change weighs the same process heuristic — not mechanized

Risk-based workflow.

Opening question: what can this break, and how much does it cost if it breaks? Risk scales the apparatus — profile A doesn't drag along the whole machinery. The profiles are a process heuristic you apply by hand: no profile concept exists in code or config, and no profile selects gates automatically.

ProfileExampleDocumentsMinimum gates
A · Lowminor UI, non-critical configSPEC minibuild + relevant test
B · Normallocal feature, bugfixSPEC + acceptancetests + static + review
C · Criticalpayments, billing, securityformal SPEC + ADRunit+integration+security+rollback
D · Multi-systempublic API, eventsSPEC + contracts + ADRcontract tests + versioning
E · Large legacyrefactor, migrationincremental SPEC + baselinecharacterization + no regression
07 the orchestrator in the kit

/uscha-devloop phase by phase.

The uscha-devloop is a multi-repo, spec-driven orchestrator. It takes the ADR set + ACCEPTANCE.md as input, builds, and runs a severity-gated review loop that converges instead of looping forever, with the tests as a guardrail between steps. It stops at the merge gate. Three non-negotiable principles govern it: converge, don't chase zero; tests are a guardrail, not the finale; generating tests is not running tests.

  1. Setup. qa_ledger.py init --config uscha.config.json. The config lists each repo and its type (maven/flutter/python/node/go/rust/dotnet/cpp/gradle/swift). In multi-repo, the other repos are mounted with --add-dir.
  2. Phase 0 — Plan (ADR-first). The ADR set + ACCEPTANCE are the input. If acceptance criteria are missing, stop and run /uscha-adr-refine first. The acceptance criteria become the contract tests of phase 1.
  3. Phase 1 — Coverage gate → conditional characterization (per repo). snapshot --phase pre + check-coverage. If coverage ≥ threshold, the existing suite is the guardrail. If below (or no report): you write characterization/contract tests at the edge (public API, endpoints) — and let the human review them before trusting them.
  4. Phase 2 — Build. You implement per the plan, one commit per logical step (conventional commits). Apply ADR discipline: consult before touching governed areas; stop and propose an ADR on a new dependency, a new pattern, a non-obvious alternative, or a contradiction of an accepted ADR.
  5. Phase 3 — QA loop (per repo). Run the tools in qa_tools_order (default: code-review → judgment-day → improve). One pass of all of them = one cycle. After each tool: apply only fixes ≥ severity gate (the rest to ISSUES-DEFERRED.md), run the tests, log with log-step, ingest the static gate with ingest-gate. The agent runs the fact gates inline (simplicity-check / gate-check / golden-diff — exit 0/1) and persists each verdict with log-gate; a failing fact gate blocks convergence. waste-check (reuse-first, 1.26.0) runs over the diff to catch Type-1/2 clones against the repo — advisory unless --gate. End-of-cycle advisory checks: converged and oscillation.
  6. Phase 4 — Integration / contract (multi-repo). With all repos mounted, run the cross-repo contract tests. Contract breaks are gated findings. It's logged under --repo integration. It's the second layer of the QA architecture: per-repo green doesn't mean the seams are green.
  7. Phase 5 — Verify (coverage, once). With stable code, /improve test writes the fine-grained coverage you deferred. Full suite green + coverage ≥ threshold before moving on.
  8. Phase 6 — PR (stops at the merge). You open the PR, confirm CI green, and stop. The human does the merge.
  9. Phase 7 — Smoke list. You produce a manual smoke checklist (real routes, endpoints, device flows).
  10. Phase 8 — Docs + retrospective. summary + readiness; /uscha-sysdoc is optional reporting, on request — not a mandatory pipeline phase. Retrospective pulled from the ledger.
08 the anti-hallucination core

Evidence captured, not narrated.

The crack the method closes: if the same agent that makes the change writes the ledger, it can put exit_code: 0 without running anything. The guarantee only holds if the evidence is produced by execution — the qa_ledger.py parses real artifacts (JaCoCo XML, Surefire XML, the linters' reports), it doesn't transcribe what the agent says.

# the ledger does NOT trust the agent: it parses files
coverage  ← target/site/jacoco/jacoco.xml   (LINE counter)
tests     ← target/surefire-reports/TEST-*.xml
static    ← checkstyle-result.xml · pmd.xml · spotbugsXml.xml
LOC       ← its own count (prod vs test), pure stdlib

Hard rule

Absent = no evidence, never "OK". A linter report that exists but is empty credits the fix; an absent report is not treated as clean (it means the gate didn't run). A tool that didn't run is never invented as green — a lint-capable repo whose static gate never ran scores UNMEASURED (0.0) on that dimension, never a perfect 1.0.

09 the measurement engine in the kit

qa_ledger.py — command reference.

Pure stdlib, Python 3.8+, no dependencies. It owns everything that must be exact and reproducible. The judgments (did it converge? is it oscillating? do we escalate?) are made by the skill reading this data; the script only exposes deterministic advisory helpers.

Exact current parser surface: 56 subcommands; the list below mirrors build_parser(), including dashboard, waste-check, and spec-change-request.

SubcommandWhat it does
doctorInstallation diagnosis (flutter-doctor spirit): python/git, the 9 skills next to the engine, INV-GOLDEN-01 hook registered, project config/ACCEPTANCE/ledger and per-type toolchains. Exit 1 only on errors (1.22.0).
initCreates the ledger from uscha.config.json (repos, thresholds, commands).
snapshotMeasures coverage / tests / LOC of a repo (--phase pre|post).
check-coverageExit 0 if ≥ threshold, 1 if below. It's the phase 1 gate.
log-stepRecords a pass of a QA tool: reported / gated-reported / fixed / deferred / suppressed / tests-passed / files-changed / fingerprint.
ingest-gateParses Checkstyle/PMD/SpotBugs/FindSecBugs, normalizes severities, and computes the real fixed by diffing finding-IDs against the previous pass.
convergedAdvisory. Exit 0 = converged (latest agent step of every tool in qa_tools_order clean + every linter clean + every persisted fact gate clean). A red measured snapshot vetoes a narrated green — padding the window doesn't help.
oscillationAdvisory. Detects that a tool's findings fingerprint repeats with period 2 (pass N == pass N-2).
log-gatePersists a fact-gate verdict: --kind golden-diff|gate-check|pit-check|simplicity|regression --verdict pass|fail|not-run. A failing gate blocks convergence and caps readiness ≤65; a not-run is recorded but is never green.
corpus-runRuns a REAL-INPUT corpus (JSONL: input / expected per line, fed to the command on stdin) and persists gate:corpus with the hit percentage. Field truth for greenfield, where every test payload was invented by the agent that wrote the code. ADVISORY while no threshold is declared (--threshold, else repos[R].corpus_threshold, else defaults.corpus_threshold); with one, a run under it caps readiness ≤65 and blocks convergence. A missing, empty or malformed corpus is exit 2 naming the line, never a scored 0 %. --ac closes a criterion MEASURED on a green run (ADR-046, 2.2.0).
smoke-ingestIngests the smoke run as the FACT it is: a report the PROJECT's tool writes ({"checks": [{"name", "ok", "status", "latency_ms", "evidence"}]}), persisted as gate:smoke. Phase 7 stops being prose — "the jar served /admin" believed on an agent's word is the failure this removes (a field team shipped an empty list reported as verified). A failed check caps readiness ≤65 and blocks convergence; a missing, malformed or EMPTY report is exit 2 naming the offending check or field, never a scored run. A FACT kind: --verdict advisory is refused, because ok is binary. A check named AC-nn ... closes that criterion MEASURED on a passing report, and a failed one VETOES it (ADR-047, 2.2.0).
flag-blockerLogs a blocker (--kind constitution for CONSTITUTION breaches): caps readiness ≤65 and blocks convergence until a human clears it with --resolve.
escalateRecords a human-escalation event with a reason.
resolve-escalationResolves a recorded escalation — lifts the ≤75 readiness cap.
summaryRetrospective metrics (--json is consumed by /uscha-sysdoc). Includes first-time yield (FTY, 1.27.0): % of repos that cleared QA on the first cycle, no rework or escalation — an informational Lean metric, never gates.
readinessThe project-state KPI: score 0–100 with weights and hard caps. Single-verdict (anti-ceremony, 1.25.0): the default is ONE screen — verdict + a collapsed --- gates: line; --verbose expands the dimensions and by-repo detail.
rebuildThe rebuild test: SPEC completeness. --mode baseline signs the system; --mode compare scores the regeneration (COVERS/PARTIAL/DIVERGE).
regression-checkFind Bugs Once (1.16.0): findings closed with no new test line = NARRATED — advises; --strict gates; persisted via log-gate --kind regression.
waste-checkReuse-first (1.26.0): deterministic Type-1/2 clone detection of the diff against the repository — the duplication simplicity-check can't see (it scores the diff in isolation). Each flag names the file:line to reuse. Advisory unless --gate or defaults.waste.gate. Roots: Lean muda (Poppendieck) + GitClear's +81% duplication finding.
phaseWorkflow state DERIVED from the ledger (plan/build/qa/escalated/pr-ready), never self-declared. --require pr-ready gates the PR and vetoes spike/* branches (1.18.0–1.19.0).
rubric-ingestIngests rubric grader JSON.
production-findingRecords production feedback.
spec-doubtRecords SPEC doubts.
spec-change-requestRecords SPEC/ADR change requests.
fastpath-evalMeasured fast-path verdict (ADR-003): ALLOW/DENY from the real diff against the merge-base; --intent records it, without it the call is a dry-run. Fail-closed (1.57.0).
spec-driftAdvisory spec-vs-code drift from git commit dates (ADR-005). Never gates; exit 0 always (1.58.0).
golden-coverageRecords the MEASURED source files a golden's harness exercises, by running it under coverage.py (ADR-006). Feeds the opt-in golden-touched veto (1.60.0).
cleanroomRuns a caller-supplied command against a CLEAN worktree of one commit; opt-in pr-ready gate (ADR-008, 1.63.0).
curation-checkThe INV-CURATION-01 gate: candidates, verdicts, append-only behavior ledger (ADR-009/010, 1.64.0).
roundtripAdvisory: which promoted candidates are traceable in code via uscha-spec ids (1.65.0).
factsDerives SYSTEM-FACTS.json from the artifacts and checks published claims against it (ADR-012, 1.68.0).
discoverEmits discovery/CANDIDATE-DELTA.json: typed observations with content-addressed OBS ids, measured/static/narrated (ADR-013, 1.69.0).
curateRecords ONE human verdict per observation as an append-only ledger object; no batch path (ADR-013, 1.69.0).
promoteMoves preserve-verdict observations into the canonical package with derived_from lineage; refuses over uncurated OBS (ADR-013, 1.69.0).
fidelityThe fidelity vector: 5 measured dimensions plus an advisory quarantine that can never gate (ADR-014, 1.69.0).
ir-extractExtracts the canonical package into a typed graph (ir/IR.json); what cannot be typed deterministically is UNTYPED, counted, never guessed (ADR-015, 1.72.0).
ir-renderRegenerates the human view (ir/IR.md) from the graph; round-trip content-stable for the structured parts (ADR-015, 1.72.0).
compile-validateValidates a COMPILATION.json (the LLM-compiler output contract) against a reference IR: unknown manifest ids, unit hash mismatches, a stale ir_hash and a broken seal each gate; degeneracy stats are advisory and never block (ADR-016, 1.73.0).
compile-ingestRecords a validated compilation into the ledger: by-construction unexplained_code plus each unresolved_intent as an append-only, content-addressed UINT object mirrored into ISSUES-DEFERRED.md — the compiler's output generates the backlog for the representation (ADR-016, 1.73.0).
bootstrap-oracleRuns a WITHHELD oracle suite against a compiled implementation and exits 0 iff every case matches its expected exit — the maker≠checker wall made executable; a measured behavioural fact about whether an independent compilation is the same system (ADR-017, 1.74.0).
bootstrap-varianceStructural metrics (LOC, AST nodes, functions, imports) and pairwise divergence proving independent compilations of the same canonical package genuinely differ; advisory evidence, never a gate (ADR-017, 1.74.0).
benchThe Diamond Bench: a per-archetype verdict table (PASS / PARTIAL / FAIL / PENDING) over a set of bounded systems, aggregating compile-validate + bootstrap-oracle + bootstrap-variance and writing DIAMOND-BENCH.md; oracle-discrimination is a gate, model identities are anonymized in the headline; deterministic, no LLM (ADR-018, 1.75.0). With --fidelity, appends the per-compiler fidelity descriptor — the M1 static extractor over each compiled source, trace coverage, oracle pass-rate, curation UNMEASURED where no human verdict exists and judged/total where one does; advisory, never changes a verdict (ADR-022, 1.79.0; ADR-023, 1.80.0). Since 1.85.0 (ADR-028) entries may be JavaScript: the oracle runner is routed by extension (node for .js), structural metrics for JS are honestly 2-dimensional (no stdlib JS AST), and the static surface is the module's own exports as listed by Node; a JS entry without node on PATH reads PENDING/UNMEASURED, never a fake pass. Since 1.85.0 (ADR-029) entries may be multi-unit: the oracle runs the entry unit (cli.*) with the compilation dir as cwd, the fidelity surface and curation cover every unit, and the first such entry carries the bench's first IR with edges (a seam ADR in the canonical package).
bench-curateONE human verdict (preserve|fix|undefined) for ONE observation of ONE bench compilation, appended to BENCH-CURATION.json; the curable set is the same M1 static-extractor observations static_surface publishes, re-extracted at verdict time (a fixture edit invalidates the old id and reports STALE); batch input, an unknown obs or a malformed store refuse with exit 2 (ADR-023, INV-CURATION-01, 1.80.0). --dir is the compilation subdir (e.g. c-opus); --compilation is an alias for the same --dir, to avoid confusion with bench's own --dir, which is the bench root (1.82.0).
bench-r2Intra-model variance (ADR-027): for every bench entry with an r2/ second blind run of the same model on the same canonical package, the structural distance between run 1 and run 2 via the SAME _struct_distance the bench uses between compilers, plus behavioural stability against the oracle; a per-entry SIGNAL/NOISY/NOISE class from intra/inter (the noise floor under every variance claim the program makes); advisory, never changes a bench verdict; writes DIAMOND-BENCH-R2.md (ADR-027, 1.84.0).
bench-roundtripRound-trip recoverability (ADR-030): for every bench compilation, how much of the human-pinned IR the mechanical reverse organs already in the engine can anchor — static footing (an id literally referenced in a source unit or a static observation) and behaviour footing (a withheld-oracle case tagged with the AC id passes; UNMEASURED where no case carries that tag). The compiler's trace_manifest footing is reported APART as claimed and never counts as recovered — it is what the compiler CLAIMED (and the blind prompt handed it the ids), so counting it would be tautological: the first run of this instrument read 1.000 on every entry for exactly that reason. It regenerates no IR from code and infers no spec (ADR-013): a MEASURED coverage over the human-authored IR, never an IR′. The honest number today: mean recoverability 0.815 across 12 entries, with the behaviour dimension MEASURED in all 12 — it read 0.828 while three compilers were judged and 0.815 once a fourth, from a second vendor, joined (ADR-042), because an entry's recoverability is the mean over its compilations. ledger-lite's edges_recovered_mean moved 1.00 → 0.75 the same way: that field is a mean COUNT of edges recovered per compilation, not a ratio — only one arm anchors all three edges, so the value is 3/N and N went from 3 to 4. It read 0.062 with behaviour UNMEASURED everywhere until the 12 bench oracles were curated with a per-case ac tag list (ADR-030 amended, 1.90.0) — a named absence, not a zero, and what moved the number was the tagging: payloads and expectations are untouched. Advisory, never changes a verdict; writes DIAMOND-ROUNDTRIP.md (ADR-030, 1.85.0/1.90.0).
lang-compareThe controlled-language arm: compares a free-prose canonical package against an EARS+STE rewrite of it, judged by one shared withheld oracle (behaviour held fixed), and computes a behaviour-first verdict — REDUCED / IMPROVED / MIXED / NO EFFECT / WORSE — over inter-compiler variance, mean oracle pass-rate and unresolved_intent; reduced variance with a behavioural regression reads MIXED, never REDUCED, and a null result is first-class; IMPROVED (ADR-026, 1.83.0): behaviour improved while variance did not fall — the mirror of MIXED; two compilers converging on the same bug read as low variance; deterministic, no LLM (ADR-019, 1.76.0). Replicated deconfounded across 5 archetypes: REDUCED in 1, IMPROVED in 1, NO EFFECT in 2, WORSE in 1 -- the guard's positive did not generalize to the simple systems on its own, the transformer read WORSE (an oracle-green lost), and a second decision-dense archetype (scheduler) landed IMPROVED, strengthening the dense/simple split (ADR-024/ADR-025/ADR-026, 1.81.0-1.83.0).
topRead-only projection of the ledger for uscha top (board, feed, verdicts, drift, rerun; ADR-031..037, 1.86.0-1.91.0).
check-terminadoINV-T1 (ADR-038, 1.92.0): is TERMINADO sealed to the code state on disk? Recomputes the same seal top --json publishes -- clean tree, no source-relevant change since the last snapshot's commit (a non-source difference seals with a note; ADR-039, 1.93.0), every ingested report still hashing to its recorded sha256. Exit 0 sealed, 1 broken, 2 unmeasured. Reads only.
execution-policyPrints execution routing.
dashboardEmits Mirador data contract.
simplicity-checkScores diff minimality.
pit-checkScores test effectiveness.
gate-checkDetects weakened gates or secrets.
spec-checkValidates SPEC/ACCEPTANCE; lifecycle dimension (ADR-040): compares the end-of-support dates cited in the ADRs' lifecycle: blocks against the SPEC's go_live. Advisory: never gates.
golden-diffByte-compares received/approved.
operabilityMeasures the repo’s operability as FACTS in the tree (ADR-048, 2.2.0): a workflow step running the configured test command, a workflow that publishes a release asset, a RUNBOOK.md naming start/config/rollback/smoke, and a declared seed_command whose script exists. Exit 0 always; persists gate:operability — advisory on risk profiles A/B, a BLOCKER on C/D/E via defaults.operability.gate.
# a typical pass of the loop
QL=./.claude/skills/uscha-devloop/qa_ledger.py
python3 $QL init --config uscha.config.json
python3 $QL snapshot --repo backend-api --phase pre
python3 $QL check-coverage --repo backend-api          # exit 0/1
# ...build + one QA tool...
python3 $QL log-step --repo backend-api --tool code-review --iteration 1 \
  --reported 12 --gated-reported 4 --fixed 9 --deferred 2 --suppressed 1 \
  --tests-passed true --files-changed 7 --fingerprint a,b,c
python3 $QL ingest-gate --repo backend-api --iteration 1
python3 $QL converged --repo backend-api --tools-per-cycle 3
10 java-qa-gate, normalized to one scale

Static gate + ingest.

The static gate (your java-qa-gate: Checkstyle/PMD/SpotBugs/FindSecBugs) is not counted by hand. You run the gate so it writes its XML, and ingest-gate parses them, normalizes to a common severity scale, separates FindSecBugs from SpotBugs, and computes the real fixed by diffing IDs.

LinterNative severity → common scale
Checkstyleerror → HIGH · warning → MEDIUM · info → INFO
PMDpriority 1 → BLOCKER · 2 → CRITICAL · 3 → HIGH · 4 → MEDIUM · 5 → LOW
SpotBugspriority 1 → HIGH · 2 → MEDIUM · 3 → LOW
FindSecBugsSECURITY-category findings → floor HIGH (separated under the tool findsecbugs)

Full scale, lowest to highest: INFO · LOW · MEDIUM · HIGH · CRITICAL · BLOCKER. The default severity gate blocks at BLOCKER / CRITICAL / HIGH; everything below goes to ISSUES-DEFERRED.md, never into the loop. Finding-ID granularity is configurable (file or line) for the fixed diffing and oscillation.

Hosted alternative: SonarQube plugin

The local java-qa-gate is self-sufficient (stdlib + linters, zero server). If the team already runs SonarQube, the plugin sonarqube@claude-plugins-official exposes the same role (issues, coverage, quality-gate) as MCP tools — same gate, different ingest. Normalize its severity to this same common scale.

11 state rules; the number is derived in the kit

Readiness KPI.

It measures the state of the result, never the effort. A weighted 0–100 score with hard caps that override the average. It reports (always exit 0) — it is not a pass/fail gate; rebuild is the one that exits 1 unless COVERS. Cycles/regressions are churn (process health) and are reported separately — they never raise readiness. Show it after any task, not just complete runs.

88/100
RELEASE CANDIDATE
acceptance (measured)
30
static gate
20
adr (narrative)
15
coverage
15
convergence
10
integration
10
cap active if: tests red → ≤35 · BLOCKER/CRITICAL open → ≤65 · unresolved escalation → ≤75 — each cap states its provenance: requirement (config) or kit-default opinion (1.17.0)

Dimensions and weights (kit 1.10.0+)

  • acceptance — 30, the dominant one: AC-n criteria closed by a MEASURED green testcase in the JUnit reports, not by checkbox (a [x] with no test = narrated_only, does not close)
  • static gate — 20 (hits 0 with 10 gated findings open)
  • ADR / checkbox completion — 15 (the narrative, demoted)
  • coverage — 15 (vs threshold, default 60%)
  • convergence — 10 · integration — 10 (weight redistributed if disabled)

Bands and caps

  • <50 NOT READY · 50–79 IN PROGRESS · 80–94 RELEASE CANDIDATE · 95–100 READY
  • cap tests red → ≤35
  • cap BLOCKER/CRITICAL open → ≤65
  • cap unresolved escalation → ≤75 (until resolve-escalation)
  • acceptance not found → ≤65 (and the ADR dimension = 0)
  • two advisories (1.14.0, never gate): stall — gated findings flat/rising for 3 cycles → go back to the ADR; stop-signal — everything converged and zero blocking facts → PR candidate

Single-verdict (anti-ceremony, 1.25.0): by default readiness is ONE screen — the verdict + a collapsed --- gates: line; the dimension breakdown you see above, plus acceptance, churn, and by-repo detail, live behind --verbose. A meta-invariant in the CONSTITUTION governs that future gates stay quiet-by-default and collapse into readiness. The blockers that cap it always speak (conditional: "speak only when it matters"). No formula, no number: that would be the numerology the method avoids.

12 is the SPEC enough to rebuild? in the kit

The rebuild test.

The ledger proves correctness (this build passed). The rebuild test proves completeness (the SPEC is sufficient to regenerate the system). Two different questions. It's the completeness benchmark being standardized in the SOTA.

The mechanic: on a clean tree, a fresh session points only at the package (SPEC/ADR/ACCEPTANCE — not the chat) and regenerates. If it rebuilds and passes acceptance + tests → the SPEC covers. If it diverges → the SPEC has gaps: almost always implicit decisions (error codes, cache strategy, library choice) that lived in your head and never made it into the SPEC.

# rebuild test — real subcommand (kit 1.4.0+)
# 1) ORIGINAL tree: capture the signature
$ python3 $QL rebuild --mode baseline --config uscha.config.json
  → REBUILD-BASELINE.json
# 2) CLEAN tree / fresh session: regenerate ONLY production from
#    SPEC/ADR/ACCEPTANCE, PRESERVING the tests, and run the suite
# 3) score the regenerated tree against the baseline
$ python3 $QL rebuild --mode compare --baseline REBUILD-BASELINE.json
  REBUILD: 72.2/100 — PARTIAL
  ! 1 test(s) fail on regenerated code — behavior the SPEC left implicit
  ! coverage 45.0% vs baseline 80.0% (tolerance 5)

Real state in the kit in the kit

Implemented and tested (kit 1.4.0+). Weights: tests 60 · acceptance 20 · coverage 15 · surface 5. Verdicts: COVERS ≥90 · PARTIAL ≥70 · DIVERGE <70 (exit 0 only if COVERS; --json is consumed by /uscha-sysdoc). The dominant signal is the preserved suite: a test that passed and now fails on the regenerated code = behavior the SPEC left implicit. When to run it: profile C+ and E, or on a periodic cadence (process rule — the kit ships no CI workflow) — it's the QA of the Discovery output.

13 loops need limits in the kit

Change budget + escalation.

Don't clean everything; don't make anything worse. Legacy debt is frozen, new debt is blocked. And the loop has a ceiling: exceeding it isn't going on alone, it's escalating.

Legacy baseline

  • 0 new HIGH/CRITICAL findings
  • 0 regressions in existing tests
  • touched files: no new warnings
  • out-of-scope debt → backlog
  • refactor only with characterization

Change budget (config)

  • max_iterations: 5 · tools_per_cycle: 3
  • 0 schema changes without an ADR
  • 0 new dependencies without approval

Escalation contract — stop and ask when

Escalating is not failing: it's that a human decision showed up. The process detected that it should not go on alone. Never auto-merge, never silently exceed the cap, never fix below the gate to make the number look better.

reduce as a gate, not as philosophy in the kit

The SIMPLICITY invariant.

Maeda's Laws of Simplicity are design philosophy, not a dev cycle. Mapping the 10 laws to gates is tempting — and that's the trap: building 13 checks to "make things simple" violates Law 1 (Reduce). The framework refutes itself. Of the whole combo, only one piece has teeth — and that piece is really two things under one coat. Separate them, or you rebuild the same mix, smaller:

WhatDeterministic?Already have it?
Numeric budgets: +lines (400 default), net growth, files changed, nesting depth, largest hunkYES — measurable, enforcedNO — the only new thing
"Was this abstraction necessary? Is it speculative?"NO — checker's judgmentYES — it's simplify + maker≠checker

What IS built

  • SIMPLICITY invariant in the CONSTITUTION: a complexity budget with hard caps.
  • A qa_ledger.py simplicity-check subcommand that scores — deterministic, zero opinion — and, since 2.1.0, is advisory by default (exit 0): it stops the loop only where the project declares its own budgets and defaults.simplicity.gate. A heavy dimension >1.5× budget floors the verdict to OVERBUILT — cheap dimensions can't average it away.
  • Normalized to the same severity scale as the static gate. No "+deps" cap and no cyclomatic-complexity/method-length cap — abstraction count/density is advisory.

What is NOT built

  • The mapping of the 10 laws → invariants: branding, not enforcement. ~70% renames what the CONSTITUTION + uscha-devloop already do.
  • A subjective "simplicity-check": it's already simplify (official skill, post-diff) + the separate checker.
# the invariant as an objective gate, not as philosophy
$ python3 .claude/skills/uscha-devloop/qa_ledger.py simplicity-check --diff HEAD
  # budgets: +lines (400 default) · net growth · files changed · nesting depth · largest hunk
  # abstraction count/density: advisory, deliberately unweighted
  SIMPLICITY: PASS · +47 lines / budget 400 · nesting 2 · largest hunk 31L

Maeda, where it pays off: one line, not a framework

Law 10 is worth more than the other nine combined. It goes as a north star atop the CONSTITUTION, not as a checklist:

"Simplicity is about subtracting the obvious and adding the meaningful."

sensors for agents (Böckeler) new

Sensors: feedback the agent can read.

A sensor is an automatic check that returns actionable feedback to the agent so it can self-correct — before human review. It's your "evidence captured, not narrated" under another name. They're ordered by when they run and by what evaluates them:

TimingNatureExamples
During the session (fast)computationaltype-check, linters, layer rules, tests, secret-scan
Pipeline (confirmation)computationalthe same, on clean infra
Scheduled reviews (drift)inferential (LLM)modularity, security, dependency freshness

Three findings that add teeth to your kit:

1 · Coverage lies → mutation testing

100% coverage with 13 live mutants: code that runs but that no test asserts on. Coverage measures execution, not verification. It plugs a hole in your rebuild test: if the preserved tests don't assert, the rebuild passes into the void. Java tool: PIT. Expensive → scheduled tier, not the inner loop.

2 · Messages that teach

The agent refactored complexity only when the message told it how and when. A bare pass/fail doesn't change behavior. Add the documented escape hatch: suppress with justification, not a binary wall. Your simplicity-check flags already go this way.

3 · Computational inside the file, inferential cross-file

Deterministic metrics win at the file level (length, complexity, args); for the cross-cutting stuff (coupling), raw metrics are noisy — the LLM review that reads the code beats them. Design rule: file caps are a gate; the "is this over-architected?" judgment goes to the inferential checker, not to a regex. (This is exactly why new_abstractions gives false positives with records/DTOs in Java.)

Careful: the false-safety bias

A pile of sensors can create an illusion of quality by covering the semantic stuff that static analysis can't see. More sensors ≠ more quality. And running an inferential review twice yields different issues: a single pass isn't enough.

protect the apparatus that measures (Osmani) in the kit

Anti gate-gaming.

Your kit measures everything — but nothing checked that the change didn't WEAKEN the measurement. A maker running as an optimizer takes the cheapest path to "green", and editing the gate is often the cheapest. Three guards close the most direct exploit of an automatic gate: modifying the gate.

1 · Gate integrity in the kit

A diff that removes tests (including whole-file deletions), disables tests, or lowers/deletes thresholds (matched cross-hunk) is a BLOCKER — qa_ledger.py gate-check, deterministic, exit 1. Lint suppressions, rewritten asserts, and a measured executed-test-count drop (--repo) are soft REVIEW signals, gated with --strict. The apparatus that measures correctness is not modified by the change it measures.

2 · Uncorrelated checker

Sharpens maker ≠ checker: for high-blast-radius changes the checker should have different blind spots — a different agent family, or at least a different profile. This is process discipline, not enforced by code. Data point: 93.4% of defects were caught by exactly 1 of 4 tools. The loop that produced the change is not its only approver.

3 · Read test diffs more strictly than production diffs

A cheap heuristic BEFORE the pit-check: prioritize test-file hunks and flag mass rewrites of existing asserts — the safety net edited to accept what's broken. Mutation testing remains the authority on whether a test would detect the defect.

Honest credit

Osmani (Agentic Code Review) enumerates these red flags for human reviewers; the automatic detector and the principle "the apparatus is immutable by the change it measures" are a synthesis of the kit, not his recommendation. The 93.4% data point (1 of 4 tools) is from the article.

the arbiter the agent does not author in the kit

Golden testing.

In the Uscha the agent authors almost everything (discovery, ADRs, spec, code, tests). The golden suite is the ONLY piece the agent cannot author — and that is its reason to exist. If the agent writes the test that judges it, it encodes the same blind spot that already lost logic once.

The hard rule

The golden is captured by running the ORIGINAL code with real inputs, mechanically, by a script. The .approved files are field truth: a HUMAN approves them, never the agent. qa_ledger.py golden-diff byte-compares .received vs .approved — a fact, not a judgment. Exit 0 CLEAN · 1 DIVERGE · 2 NOT-RUN (zero fixtures = NOT-RUN, never CLEAN). Any non-match = DIVERGE, cuts the chain.

INV-GOLDEN-01 (CWE-440)

No module enters migration/modernization without a golden captured and committed BEFORE touching it. The migration spec is written against that golden.

Determinism or the diff lies

Freeze the clock, seeds, map ordering, GUIDs, and above all the target locale (decimal separator, date format — high risk across machines with a different locale). The snapshot comes out byte-for-byte identical when the behavior is identical.

Directly applicable to any migration of a legacy system with critical paths (byte-equivalence), where the silent loss of logic is the real risk. Already in the kit: brownfield front uscha-reverse-discovery (map + facts), uscha-characterize skill (capture), golden-diff gate, hook block-approved-writes.py (blocks the agent from touching an .approved), and .gitattributes.

so it isn't a useless diamond guiding principle

Facts vs prose.

A kit full of gates can turn into a diamond: beautiful and impractical. The principle that avoids it — your Böckeler rule (computational vs inferential) applied to the methodology itself:

Gates that read FACTS block; those that GUESS over prose advise.

GateReads
golden-diffbyte-comparison vs .approved; declared volatiles in golden.scrub.json mask with VISIBLE masking, human-approved (1.15.0)BLOCKS
pit-checkPIT XML (mutation testing) — scheduled tier; a failing report is persisted via log-gateBLOCKS
gate-checkdiff structure: deleted/disabled tests, lowered thresholds, added secrets (PEM/AKIA/tokens/key containers — 1.12.0)BLOCKS
rebuildbaseline vs regeneration; exit 1 unless COVERSBLOCKS
phase --require pr-readyworkflow state DERIVED from the ledger (converged + green tests + 0 BLOCKER/CRITICAL), never self-declared; a spike/* branch never passes (1.18.0–1.19.0)BLOCKS
readinessreports (0–100 KPI, always exit 0) with hard capsREPORTS
simplicity · budgets+lines / net growth / files / nesting / largest hunk — test trees stay OUT of the budget (1.11.0): writing tests never penalizesBLOCKS
spec-check · structuralmissing out-of-scope · absent/empty acceptance criteria · zero traceable AC-n IDs or duplicatesBLOCKS
regression-checkfindings closed with no new test line = NARRATED (Find Bugs Once, 1.16.0) — --strict gates itADVISES
waste-checkType-1/2 clones of the diff vs the repository (reuse-first, 1.26.0) — the duplication simplicity-check can't see; flags name the file:line to reuse — gates ONLY with --gate or defaults.waste.gateADVISES
rubric-ingestrubric grade: versioned qualitative criteria with mandatory evidence (1.23.0) — gates ONLY when the human declares it (defaults.rubric.gate)ADVISES
spec-check · prose · abstractionsheuristic over prose / "new types" (--strict gates them)ADVISES

A natural-language heuristic that blocks throws false positives → the dev turns it off → dead gate (the erosion gate-check fights). That's why spec-check's prose heuristics are advisory and abstractions were dropped from the score — only its two structural facts block. No CI workflow ships in the kit: in /uscha-devloop the agent runs the fact gates inline (exit 0/1), persists each verdict with log-gate, converges, and stops at the merge gate → the human reviews → ship.

The Pragmatic Programmer vs the kit — 10 of 10 in the kit

The book went through the kit.

Crossing Hunt & Thomas (20th Anniversary, 497 pp) against the method yielded a set of validations, tensions and ten actionable improvements, all shipped (kits 1.10.0 → 1.19.0, each with a fresh review and a green smoke suite). The per-item record lives in those releases' changelogs (uscha-kit/CHANGELOG-1.10.0.md1.19.0.md); the original analysis document was retired in the docs cleanup.

Tip / TopicWhat landed in the engineKit
Tip 87 · Sudoku anecdoteTraceable acceptance: AC-n closes on a MEASURED green testcase, not a checkbox — the dominant readiness dimension1.10.0
Topic 51Tests outside the simplicity budget: writing tests never penalizes the gate1.11.0
Topic 43Secret-scan in gate-check: added PEM/AKIA/tokens/key containers block as facts1.12.0
Topic 34Atomic ledger: sha256 checksum + hardened load — external mutation or corrupt JSON blocks with a recovery message1.13.0
Topics 37 · 5Plateau/stop-signal (advisory): findings not dropping for 3 cycles → "go back to the ADR"; everything converged → "PR candidate"1.14.0
Topic 41Golden scrub: declared volatiles (timestamps/ids) mask with visible, human-approved masking1.15.0
Tips 94 · 31Regression-capture: closing findings with no new test = NARRATED; resolving a blocker requires an escape-analysis1.16.0
Tip 8Threshold provenance: every cap states whether it is a requirement (config) or kit-default opinion1.17.0
Topic 29Derived FSM: phase computes state from the ledger — the PR is gated on --require pr-ready1.18.0
Tip 21Formal spikes: a spike/* branch never passes the PR gate; the legitimate output is an ADR with lessons1.19.0

On the two big tensions the kit departed from the book's letter to defend its own principle: the caps keep biting (their existence is a definition, the number is an opinion — and now it says so), and the FSM is derived rather than declared — a declared FSM would be narrated state. Measured beats narrated, applied even to the book.

14 loop engineering (Jun 2026) new

Did we reach it? — convergence with the SOTA.

"Loop engineering" blew up in one week of June 2026 (Steinberger, Cherny, Osmani): "don't prompt agents; design loops that prompt them". When the front brought it down to spec-driven, it converged on these same principles. Uscha didn't fall behind: it reached the same shape independently.

Trending autonomous-loop principleUschaWhere it lives in the kit
Done-criteria that rejects open loopsACCEPTANCE.md (acceptance that can fail)
Iteration budget / hard ceilingmax_iterations: 5 · change budget
Maker ≠ checker: the writer doesn't self-gradecaptured evidence (ledger parses artifacts)
State externalized to diskQA-LEDGER.json + package in the repo
Done only with checker-pass + human sign-offphase 6: stops at the merge (human gate)
Oscillation / stuck detectionoscillation (period-2 fingerprint)
Self-scheduled outer loop (timer / routine)deliberately not — you trigger it

The 4 costs of loop engineering, neutralized

  • verification debt → evidence ledger
  • comprehension rot → repo + /uscha-sysdoc
  • token blowout → change budget + max_iterations
  • cognitive surrender → human gate

The verdict

We didn't just reach it: we arrived at the same shape independently, and on verification integrity (maker ≠ checker) we articulated it as sharply as anyone. The only difference is that a person triggers the loop, not a cron — and that's the decision, not the gap.

outer loop · when to automate new

The autonomous loop earns its cost, or costs more than it returns.

The loop-engineering playbook (Osmani / AlphaSignal, Jun 2026) puts a 4-condition test before automating anything: fail one and the loop costs more than prompting by hand. Uscha already defines "when NOT to use it"; this is the entry filter for the outer loop.

The 4 conditions

  • The task repeats (weekly+) — if not, one good prompt is cheaper.
  • Automated verification — a test/build/linter that can fail the work without you in the room.
  • The budget absorbs the waste — the loop re-reads, retries, explores: it burns tokens either way.
  • The agent has senior tools — logs, a repro environment, running what it writes.

Good vs bad first loops

Good: CI triage, dep bumps, lint-and-fix, flaky-test repro, issue→PR on well-tested code.

Bad (human in the chair): architecture, auth, payments, production deploys, fuzzy product.

Why the gated-by-design stance holds

High-blast-radius domains —regulated, financial, critical retail, safety-critical— fall on the "bad to autonomize" side. The playbook itself says: don't put the loop in charge of deciding on auth/payments/architecture. That's exactly the gated-by-design approach: the article confirms it from the other side.

outer loop · the design evaluated — deferred (2026-09-02), not on the roadmap

The Uscha outer loop: the heartbeat it lacks.

Uscha is human-triggered today: you fire it. The playbook contributes the heartbeat — what turns "one run" into a loop. The synthesis: Uscha is the ideal payload of that heartbeat, because it already brings the gate, the state, the skills, and the maker ≠ checker. Only the trigger is missing.

# outer loop = schedule + /goal, wrapping /uscha-devloop
> /loop 0 3 * * *                 # cadence: every night
  /goal  readiness ≥ 80 AND tests green in touched modules
         AND 0 CRITICAL findings   # checked by a separate model
  /guard 4-condition-test          # repetitive task + automatic verification
  > run /uscha-devloop over <machine-checkable scope>
    gate     = qa_ledger.py ingest-gate + fact gates (readiness = KPI)  # ALREADY exists
    state    = QA-LEDGER.json + package in repo         # ALREADY exists
    stop     = /goal met (fresh checker) or change budget exhausted
    on-done  = open draft PR · escalate what touches the CONSTITUTION
    human    = merge / deploy ALWAYS with approval       # human gate

The heartbeat (the new part to add)

  • /loop — re-runs on a cadence, whether or not it looks at the state.
  • /goal — keeps going until a condition is true, verified by a separate model (maker ≠ checker in the stop condition).
  • Routines / scheduled tasks — runs that survive a restart or a shut-down laptop.

Connectors (MCP) — act, not just talk

  • GitHub — branch/PR, react to webhooks (the biggest day-1 win).
  • Linear/Jira — link ticket, close on verify.
  • Slack — post triage, ping escalations.
  • Sentry — investigate live alerts, draft fixes.
outer loop · the security tax evaluated — deferred (2026-09-02), not on the roadmap

An unattended loop is an unattended attack surface.

Your security today is build-time (static gate + CONSTITUTION with CWE). When the loop runs on its own, operational risks appear that the playbook documents. They enter as an operational layer of the CONSTITUTION: invariants the outer loop cannot violate.

Unattended-loop riskOperational invariant (CONSTITUTION)
Generated code merging without reviewThe gate includes SAST + secret-scan + dependency-audit; without that, no PR.
Skills as an injection vector — a third-party skill can leak credentialsVet every skill's origin before installing; source allow-list.
Secrets in logs (verbose on long runs)Non-verbose logging in production loops; sanitize what gets logged.
Permission scope creep (a "just one write permission" nobody re-audited)Re-audit permissions every 30 days; the loop starts read-only by default.
A session that bloats on long loops and hangs — evidence lost, loop dead with no warningRotate the session before the size threshold; a hook that warns + transcript rescue (author's setup — not shipped in the kit). Session hygiene is part of the security tax.

The Ralph Wiggum loop (Huntley)

Silent failure: the agent emits the "done" token too early and the loop exits with the work half-done. The fix is the one you already have: an objective gate (test/build/linter that returns pass or fail), not an "opinionated" verifier. The gates plus the human gate close the loop — the engine doesn't close it by itself.

outer loop · verdict

Two layers, one synthesis.

The playbook and Uscha don't compete: they're different layers. The article is the outer loop (the heartbeat that triggers machine-checkable maintenance). Uscha is the rigorous inner loop + Discovery for critical systems. The convergence on principles (maker ≠ checker = Anthropic's evaluator-optimizer, Dec 2024) confirms you reached the durable stuff, not the hype.

What Uscha leads on

  • Discovery — the "idea → shape" upstream; the article assumes you already know what to build.
  • Readiness with a formula + caps + bands, vs its single metric.
  • CONSTITUTION + risk profiles — operationalizes its advice to "not autonomize auth/payments".
  • Rebuild test + executable ADRs — spec completeness; the article doesn't cover it.

What's worth stealing

  • The 4-condition test as an entry guard.
  • The heartbeat (Automations · /loop · /goal).
  • MCP connectors (GitHub/Linear/Slack/Sentry).
  • The operational security tax in the CONSTITUTION.

The metric when you autonomize

Cost per accepted change — not tokens or tasks attempted. If the accepted-change rate falls below 50%, the loop is handing you back the review work it came to take off your plate: that's where it loses. Uscha is the ideal payload of the heartbeat precisely because its gate raises that rate.

reverse discovery, under a withheld oracle

The Diamond, measured.

Twelve bounded archetypes, a withheld oracle (M4), four blind compilers from two vendors — Haiku, Sonnet, Opus and OpenAI Codex gpt-5.5 (measured September 2026). The question: how much of the system survives the round trip?

8/12
archetypes regenerate to the same system
8 PASS · 4 PARTIAL
verdict per archetype
0.815
round-trip recoverability (mean)
221
human curation verdicts

221 verdicts: 213 preserve, 8 fix, none unjudged. The cross-vendor arm is a falsification test the replaceability claim survived, not a survey: four blind compilers, two vendors, gpt-5.5 via Codex included.

dogfooding measured, not narrated

2.x: the kit under its own instruments.

The ritual is a script (ADR-041)

The release is no longer a hand-run checklist: tools/release.py runs eight invariants and refuses, naming which one failed. Dogfooding freshness is decided by git ANCESTRY, never by a clock.

The facts gate (1.97.0)

Every published claim (version, subcommands, skills, Diamond archetypes) is a derived FACT, checked against the engine. Born because the homepage said "9/12" for nine releases after the number moved — and no gate saw it.

2.0.0 — init generates, no longer copies

Risk presets had never actually taken effect: init copied the kit's reference config, and that copy outranked the profile under the "explicit wins" rule. Now init generates a minimal config.

2.1.0 — SIMPLICITY is advisory by default (ADR-043)

A gate needs an adopted budget. With none declared, the score informs but does not block.

2.2.0 — five ADRs from two field retrospectives

origin: agent (ADR-044, who decided each item), corpus-run (ADR-046, field truth with real inputs), smoke-ingest (ADR-047, the suite's own run as measured evidence), operability (ADR-048, a measured dimension), and the version marker on every installed skill (ADR-045, doctor reports whether it is outdated).

15 a mature methodology defines its edges

When NOT to use Uscha.

Spike / exploration

Throwaway code to learn. No SPEC; yes to a note of what was learned. Whatever survives gets specified later.

Throwaway prototype

A demo that won't go to production. Marked as such, isolated, with a death date.

P0 hotfix process rule

Production incident: you fix first. But the minimum evidence (what changed, how to roll it back) and the retroactive SPEC/ADR are mandatory within 24h — a process rule the team commits to, not a shipped feature. Without an escape valve, people cargo-cult the throwaways or abandon the method under pressure.

16 the generic part that works for any repo in the kit

The workbench.

The generic layer that runs the methodology: Claude Code + Python + git/gh + the skills. The stack-specific part (JDK/Maven, the database, the linters) is the project's adapter and lives in each repo's CLAUDE.md — not in the workbench.

ComponentWhat forMinimum
Claude Codethe agent / orchestratorPro / Max / Team / Enterprise / Console account
Python 3.8+runs qa_ledger.py (pure stdlib)python3 on PATH
gitversioning2.x with user.name/email
ghcreate repo / open PRoptional, recommended
kit skillsuscha-discovery, uscha-adr-refine, uscha-devloop, uscha-sysdoc, uscha-reverse-discovery, uscha-characterize, uscha-rubric, uscha-mirador, uscha-statusin ~/.claude/skills/
QA skillscode-review, judgment-day, improveyour global skills (uscha-devloop orchestrates them, doesn't bundle them)
engram (plugin)persistent memory across sessionsmarketplace Gentleman-Programming/engram
sonarqube (plugin)hosted static gate (alternative to java-qa-gate)marketplace claude-plugins-official
gentle-ai (CLI)skill-registry hook (refreshes the skills index) — optional author toolchain, not required by the kitscoop, bucket gentleman
# Claude Code (native installer — no Node required, self-updating)
curl -fsSL https://claude.ai/install.sh | bash       # macOS/Linux/WSL
irm https://claude.ai/install.ps1 | iex              # Windows PowerShell
claude                                                # OAuth login
# Kit skills (global)
cp -r uscha-kit/.claude/skills/* ~/.claude/skills/
# Optional — author's toolchain, not required by the kit (Gentleman's own bucket)
scoop bucket add gentleman https://github.com/Gentleman-Programming/scoop-bucket
scoop install gentle-ai
claude --version && claude doctor                     # verify

On Windows, WSL2 is the recommended path (you install and run claude inside WSL). For headless/server: export ANTHROPIC_API_KEY=...

17 it's not magic: they're concrete features

The agent's pieces that hold it up.

The kit installs on seven agents. What each one provides is not equal — and honesty means saying where it isn't.

AgentWhat it provides
Claude Codeskills, sub-agents, hooks — including the INV-GOLDEN-01 write hook (blocks the agent from authoring a .approved), --add-dir multi-repo.
Codex.codex-plugin + skills + AGENTS.md as the context file. No native hooks: the golden guard (INV-GOLDEN-01) is not enforced there — that is an honesty line, not a minor detail.
pi · cursor · copilot · gemini · clinethe five skill-root targets: skills only (Agent Skills standard), no plugin, no hooks.

CLAUDE.md / AGENTS.md

The repo's stable protocol: commands, no-go zones, DoD, how to record evidence. The permanent stuff lives here; the per-change stuff in SPEC/ADR.

Skills (/command)

uscha-discovery, uscha-adr-refine, uscha-devloop, uscha-sysdoc, uscha-reverse-discovery, uscha-characterize, uscha-rubric, uscha-mirador, uscha-status in .claude/skills/. Callable, versionable, shareable with the team.

Sub-agents

They parallelize the QA tools (review, security, improvements) without dirtying the main context.

Hooks

They run gates on their own: post-edit tests, pre-commit lint. Evidence is captured by execution, not narrated.

Multi-repo (--add-dir)

You mount several repos in one session for integration/contract QA (multi-repo).

Remote Control

You follow and drive the session from your phone while the loop runs. Add plan mode, settings.local.json for permissions, and ccusage to monitor usage.

Persistent memory (engram + MEMORY.md)

The truth survives the session close: engram stores LLM-oriented facts and decisions per project; MEMORY.md is the file-based auto-memory. It's the "the truth lives in files" rule extended across sessions, not just within the repo.

engram is OPTIONAL: uscha does not require it. The kit declares no dependencies at all (only Node ≥18 for the npm router and Python 3.8+ stdlib for the engine) and never names engram in a single line of what it publishes. They solve different problems: the project's truth lives in QA-LEDGER.json, versioned alongside the repo and shared by the team; engram holds the agent's memory, which is personal to each machine. Without engram the method works exactly the same — what you lose is agent context across sessions, not evidence.

Session hygiene

Long /uscha-devloop runs bloat the transcript until the app hangs — seen live: 77 MB = lost session. A hook warns by size, a traffic-light map lists the at-risk sessions, and a rescue pulls the .jsonl into readable Markdown (author's setup — not shipped in the kit). Rule: rotate the session before the threshold.

Cross-vendor honesty

Verified on Codex: installation, AGENTS.md, the portable prompts (templates/rubric-grader-prompt.md, templates/esceptico-prompt.md), the cross-vendor compilation arm (ADR-042: gpt-5.5 via codex-cli, --write-mode return, 0 shell commands), and — 2026-09-20, Codex desktop app, GPT-5.6 (ADR-049) — a full /uscha-devloop run end to end on a greenfield pilot repo: CONVERGED, the criterion closed MEASURED, stopped clean at the merge gate. Two limits remain: no native hooks on Codex, so the golden write guard (INV-GOLDEN-01) is not enforced there; and no live statusline, mitigated (kit 2.4.0) by printing the compact status readout in the visible reply on surfaces that have none.

18 the repo's permanent protocol in the kit

CLAUDE.md — the non-negotiable rules.

Permanent rules that Claude Code reads every session. The per-change stuff lives in SPEC/ADR/ACCEPTANCE, not here. (If you use other agents, copy this file as AGENTS.md.)

  1. Don't code from a vague idea. Without SPEC + ACCEPTANCE, model first (/uscha-discovery or /uscha-adr-refine).
  2. The truth lives in files, not the chat. Before touching code, read SPEC/ACCEPTANCE/ADR.
  3. Converge, don't chase zero. Only findings ≥ severity gate; the rest to ISSUES-DEFERRED.md.
  4. ADR discipline during the build. Stop and propose an ADR on a dependency/pattern/alternative/contradiction. Link // ADR: <slug>.
  5. Evidence captured, not narrated. Execution produces it. Absent = no evidence.
  6. Legacy baseline. 0 new HIGH/CRITICAL, 0 regressions, no new warnings in touched files.
  7. Change budget. Max iterations/files; 0 schema without an ADR; 0 new deps without approval. If exceeded → escalate.
  8. Never edit the SPEC/ADR to make the implementation look correct. Version it and go back to Ready.
  9. Human gate. No automatic merge or release. You stop at the PR.

Tracked-markdown protocol

Before modifying any tracked .md (CLAUDE.md, plan/delta docs, docs/adr), ask for the repo's current version first. Those files carry real progress (checkboxes, notes); never regenerate them from scratch.

19 from idea to PR, without leaving a session

One session, end to end.

A backend service (Java, Spring Boot, React, SQL), from idea to PR, all in Claude Code:

claude code · single session
$ claude
> /uscha-discovery
  1×1 grill, proposes entities/endpoints, you decide 3 things
   CONTEXT.md · DOMAIN-MODEL.md · SPEC-001 · ADR-001/2/3
   ACCEPTANCE.md · RISKS.md · HANDOFF.md
> /uscha-devloop
  plan → coverage gate → build → QA loop (sub-agents) → integration
  CONVERGED · PR opened. I stop at the merge.
> !python3 .claude/skills/uscha-devloop/qa_ledger.py readiness --acceptance ACCEPTANCE.md
  READINESS: 88/100 — RELEASE CANDIDATE
> /uscha-sysdoc                 # two-view deck from the ledger
# (you) review the PR and merge — the human gate is not automated

The tool executes. The methodology governs. The evidence decides. The human approves.

the simplest example, end to end to start seeing it

The methodology in 10 steps.

A minimal feature — applyDiscount(amount, percent) — walked end to end. 6 of the 10 steps are a failure or a refinement (marked ): the methodology is not that everything goes right the first time — it's that every deviation has a gate that catches it.

  1. Discovery. /uscha-discovery "applyDiscount(amount, percent)" → 1×1 grilling (rounding? % bounds?). Out comes SPEC-001 + ACCEPTANCE + ADR-001.
  2. ⚠ spec-check advisory. spec-check --spec SPEC-001.md → vague criterion; you rewrite it testable: "amount=100, %=20 → 80.00 (2 decimals)".
  3. ⚠ out-of-scope. spec-check asks for the section; you add "out of scope: coupons, taxes" → now there's an oracle for "scoped-but-absent".
  4. adr-refine. /uscha-adr-refine "rounding: HALF_UP or HALF_EVEN?" → ADR-002, with the alternative recorded.
  5. uscha-devloop. /uscha-devloop → plan → coverage → build → QA loop. Compiles, happy path green.
  6. ⚠ pit-check. pit-check → a mutant survives in the rounding: the test runs but doesn't assert the cent. You add assertEquals("80.00", …). Coverage was lying.
  7. ⚠ gate-check BLOCKS. gate-check --from-git → the agent lowered the coverage threshold in pom.xml to pass. Revert it, fix the test for real.
  8. ⚠ rebuild DIVERGE → amend-spec. rebuild --mode compare → the %=120 case was left implicit. You amend the SPEC (">100 or <0 → error"), regenerate, go back to Ready. You don't patch the code.
  9. ⚠ simplicity-check. simplicity-check --from-git → OVERBUILT: the diff blew its growth budget — the agent added a DiscountStrategyFactory for 3 lines (the abstraction count itself is only advisory). Trim it.
  10. readiness + human gate. readiness --acceptance ACCEPTANCE.md → 88/100 RELEASE CANDIDATE. You read the diff, approve the merge (never auto). /uscha-sysdoc builds the deck. Ship.

Migration variant (legacy → new architecture)

If instead of creating applyDiscount you were porting it from the legacy, step 1 is different: /uscha-reverse-discovery maps the old system (facts) and /uscha-characterize captures the golden of the OLD code with real inputs. Then golden-diff byte-compares the new one vs .approved — any mismatch = DIVERGE. The agent never authors the .approved.

20 same behavior on another account / another PC

Reproduce the environment on the team.

The skills are "shareable with the team" — but the behavior does NOT live in a single file. It's 7 layers + an external CLI + a path gotcha. Copying just settings.json isn't enough. Scope note: this taxonomy and the bootstrap script are the author's setup in Claude Code Desktop — not shipped in the kit; the kit itself only needs Python 3.8+, git, gh optional, the kit skills installed per agent, and per-repo config + permissions. Installing the kit on another agent needs none of this: npx --yes @andresmassello/uscha@latest install --target codex.

LayerWhat it isHow it's reproduced
Configsettings.json · CLAUDE.md · output-style · themecopy (+ fix paths)
Pluginsengram · sonarqubeinstall from marketplace
Skills~/.claude/skills/ (uscha-discovery, uscha-devloop, QA...)copy the whole folder
Agents + Commandsthe sdd-*copy verbatim
Hooksgates + session hygiene (.ps1)copy (they use $env:USERPROFILE, portable)
External CLIgentle-ai (skill-registry hook)scoop, Gentleman's bucket
MCP serverscomputer-use, chrome, preview...free with Claude Code Desktop

Gotcha #1 — hardcoded paths

settings.json carries the literal username (C:\Users\...). On another account it all breaks. The bootstrap tokenizes the path on export and replaces it with the local user on import.

Optional — gentle-ai (author's toolchain, not required by the kit)

It's not in scoop's main bucket. Add Gentleman's own bucket first, otherwise install fails with "couldn't find manifest".

# bootstrap: one command per side
# on YOUR machine — build the bundle (no secrets, no memory):
bootstrap-claude-setup.ps1 -Mode export -Bundle D:\claude-bundle
# on the NEW machine (bundle already copied there):
bootstrap-claude-setup.ps1 -Mode import -Bundle D:\claude-bundle
# manual: gentle-ai (own bucket) + the 2 plugins via /plugin
scoop bucket add gentleman https://github.com/Gentleman-Programming/scoop-bucket
scoop install gentle-ai

Memory is NOT shared. engram + MEMORY.md are personal to each machine and build themselves as you work. Behavior is replicated; memory is earned.

§ appendix · quick reference

Glossary of terms.

To check on the fly when a term shows up in the slides. Not linear reading: jump here when you need it (End takes you to the end).

Artifacts — the truth in files

SPECWhat must happen. A change's verifiable requirements.
ADRArchitecture Decision Record. Why this shape and not another; a decision with its alternatives.
CONSTITUTIONInvariants that no ADR or SPEC may violate. What is never acceptable.
ACCEPTANCEA change's verifiable "done" criteria.
CONTEXT · DOMAIN-MODEL · RISKS · HANDOFFDocument package that /uscha-discovery produces: context, domain model, risks, handoff.
ISSUES-DEFERRED.mdFindings below the severity gate; they don't block, they're deferred.
LEARNINGS.mdCorrections compiled into principles (learnings loop).

Phases and commands

/uscha-discoveryIdea→shape mode (greenfield): 1×1 grill, proposes entities/endpoints.
/uscha-reverse-discoveryBrownfield front: extracts FACTS from the old system (map + golden), doesn't propose shape. The human infers the SPEC.
/uscha-characterizeCaptures the golden of the ORIGINAL code with real inputs; stops at human approval. The agent doesn't author the .approved.
/uscha-adr-refineMode for polishing architectural decisions.
/uscha-devloopThe orchestrator: plan → coverage gate → build → QA loop → integration.
/uscha-sysdocGenerates the two-view deck from the ledger.
Human gateThe human approves the merge/release; never automatic.

Gates and measurement

qa_ledger.pyMeasurement engine (stdlib): readiness, rebuild, simplicity-check, waste-check, pit-check, gate-check, spec-check, golden-diff, log-gate, flag-blocker, resolve-escalation.
golden-diff / .approvedGolden-testing gate: byte-compares .received vs .approved (field truth, human-approved). The agent doesn't author it.
facts vs proseGuiding principle: gates that read facts block; those that guess over prose (spec-check's prose heuristics, abstractions) advise. spec-check's two structural checks are facts and block.
static gate (java-qa-gate)Checkstyle / PMD / SpotBugs / FindSecBugs over the code.
ingest-gateParses the static gate's XML and normalizes it to a common severity scale.
severity gateThreshold that blocks convergence: BLOCKER / CRITICAL / HIGH.
Readiness (KPI)Score derived from state (tests / acceptance / coverage), with hard caps. Reports (always exit 0); not a pass/fail gate.
rebuild testIs the SPEC enough to regenerate the system? Bands COVERS / PARTIAL / DIVERGE; exit 1 unless COVERS.
change budgetMax iterations / files / deps. Exceed it → escalation.
SIMPLICITY (Reduce)Invariant: the diff's complexity budget. Bands SIMPLE / ACCEPTABLE / OVERBUILT.
maker ≠ checkerThe one who makes doesn't graduate; a checker in fresh context validates (evaluator-optimizer).
captured evidenceExecution produces it (reports), not narration. Absent = no evidence.

Loops

inner loopThe rigorous per-change cycle (Uscha).
outer loopThe heartbeat that triggers machine-checkable maintenance.
heartbeatThe outer loop's trigger (Automations · /loop · /goal).
Ralph Wiggum loopSilent failure: the agent emits the "done" token too early.

Memory and hygiene

engramPersistent LLM-oriented memory, per project, across sessions.
MEMORY.mdFile-based auto-memory; a distilled index of facts.
session hygieneRotate the session before the transcript bloats and hangs it.

External reference

CWECommon Weakness Enumeration: standard catalog of security weaknesses.
YAGNI"You Aren't Gonna Need It": don't build what wasn't asked for.
progressive disclosureShow the minimum first; defer the detail until it's needed.
§ appendix · where the ideas came from

References and credit.

As a matter of principle: the ideas in this document didn't come from nowhere. The concept/idea I developed was later enriched with the following documentary contributions:

Person / sourceContribution to this methodology
Birgitta Böckeler · martinfowler.com"Maintainability sensors for coding agents" — the sensor framework (timing × nature), coverage vs mutation testing, computational vs inferential.
Addy Osmani"The New SDLC", "Agentic Code Review", "Loop Engineering" — anti gate-gaming (red flags), uncorrelated checker (93.4% = 1 of 4 tools), reading test diffs more strictly, isolation via git worktree, fan-out ≤ review bandwidth.
Martin FowlerTechnical Debt Quadrant (inadvertent vs deliberate debt); his site is the home of much of these ideas.
Vlad KhononovLearning Domain-Driven Design — the modularity framework that grounds the modularity review.
Dave Thomas & Andy HuntThe Pragmatic Programmer (20th Anniversary Ed.) — convergence verified against the full book: "Don’t Assume It — Prove It" (measured beats narrated), Design by Contract (CONSTITUTION), blackboards (the ledger), Crash Early (fail-closed design); "Find Bugs Once" and tracer bullets feed the 2.0 backlog (uscha-kit/CHANGELOG-1.10.0.md … 1.19.0.md).
Andrej Karpathy"Simplicity First" — KISS operationalized (minimum code, surgical changes, goal-driven).
John MaedaThe Laws of Simplicity — Law 1 (Reduce), the north star of the SIMPLICITY invariant.
Geoffrey HuntleyThe "Ralph Wiggum loop": the silent failure of the premature "done" token.
AnthropicEvaluator-optimizer (maker ≠ checker, Dec 2024); Claude Code; the simplify skill.
Gentleman ProgrammingEnvironment tooling: engram (persistent memory) and gentle-ai.

Honest credit: the mutation testing technique is popularized by Stryker (JS) / PIT (Java); "Simplicity First" was operationalized publicly in Forrest Chang's repo (Jan 2026), Karpathy didn't endorse it. Under-attributing impoverishes; over-attributing lies.

← → navigate · Home start · End end