Why CLAUDE.md Fails Hexagonal Architecture: Polyglot Architectural Obligation Proofs#
A 3-Layer Verification & Paired Live-Model Brownfield Audit (Qwen3.8-27B-IQ3_M @ temp = 0.0) Evaluating Open-Core `nomos v4.13.0` Against Ungoverned ReAct Control (CLAUDE.md + Native Unit Tests) Across Python, TypeScript, and Go.
Benchmark Provenance & Three-Layer Verification Receipt
Date Evaluated: November 9, 2026 • Release: Open-Core `nomos v4.13.0` (c3268c9, Apache 2.0)
Layer 1 (Cleanroom Polyglot Adversarial Stress): `cleanroom_obligation_polyglot_stress_test.go` across Python, TypeScript, Rust, and Go (100%fail-closed detection on boundary leaks, missing contract fields, unboundTC-*obligations, and stale upstream specs)
Layer 2 (Live Self-Dogfooding): Activecore-purityandmodules-independencearchitecture_boundariesplusTC-OBL-001..010obligation proofs enforced on thenomoscompiler substrate itself (42/42DoD gates)
Layer 3 (Paired Live-Model Brownfield A/B):12deterministic episodes (Qwen3.8-27B-IQ3_M,temperature = 0.0,enable_thinking = false,40.3 tok/son local RTX 4080 16GB VRAM) holding system prompt,CLAUDE.mdhandbook, tools, and turn budget constant
1. The Day-30 Architectural Failure Mode: Green Tests, Rotted Boundaries#
Every experienced systems architect recognizes the gap between functional test pass rates and architectural integrity. When a human or coding agent works inside a multi-module brownfield repository, two silent regressions routinely slip straight past green unit test suites and advisory Markdown prompt files (CLAUDE.md, .cursorrules, AGENTS.md):
- Convenience-Driven Boundary Erosion: An explicit rule in
CLAUDE.mdstates "Keepdomain/pure: never import frominfra/." Yetinfra/currency_norm.py(orsrc/infra/taxEngine.mjsorinternal/infra) already exposes a working helper that solves half of today's ticket. Because stochastic coding agents optimize for reaching a passing test exit code (0) in minimum turns, they leave or add the forbiddeninfraimport insidedomain/, runpytest/node --test/go test ./..., seePASS, and ship the Coupling leak. - Silent Upstream Specification Taint: An architect updates
specs/billing_spec.mdin commit[INT-2]to add a regulatory field (taxRateBps) and test obligation (TC-BIL-03). Because existing v1 unit tests still exit0against the old v1 implementation, unguarded CI pipelines report a green repository while production code silently lags behind its specification contract.
2. Four Compiled Obligation Primitives in nomos v4.13.0#
Instead of asking a probabilistic language model to remember architectural invariants across a decaying context window, nomos v4.13.0 compiles four machine-enforced proofs directly into the single static Go binary (nomos verify, nomos handshake, and nomos hook post-tool):
flowchart LR
Spec["Markdown Spec SSoT<br/>(Fenced Types + TC-* Table)"] -->|"SHA-256 Receipt"| Notes["Git Notes 2PC Ledger<br/>(refs/notes/nomos/releases)"]
Notes -->|"Turn-0 Taint Diff"| Handshake["nomos handshake<br/>(Stale Spec Alert)"]
Edit["Agent File Write<br/>(Hermetic SUB-* Worktree)"] -->|"< 5 ms PostToolUse"| Radar["Fast-File Boundary Radar<br/>(11-Language Import Check)"]
Spec -->|"strict_types + verify_obligations"| Gate["IntentTraceabilityGate<br/>(Contract Parity + @verifies TC-*)"]
Edit --> Gate
Gate -->|"42/42 Gates Exit 0"| Sync["nomos task sync<br/>(Atomic Merge + New Spec SHA)"]| Obligation Primitive | nomos.yaml Key |
Polyglot Coverage (11 Languages) |
Deterministic Failure Condition |
|---|---|---|---|
| 1. Declarative Layer Boundaries | architecture_boundaries |
Go (go/ast), TS/JS/Svelte, Python, Rust, Ruby, C/C++, Java, Kotlin, C# |
Fails in <5ms on PostToolUse and nomos verify when from glob imports any module matching forbid_imports (or outside allow_imports), with pinned-main tamper protection. |
| 2. Fenced Spec Contract Parity | contracts.strict_types |
Fenced go, ts/js, python, rust, java, kotlin, csharp blocks |
Extracts struct, interface, type, class, and @dataclass fields from Markdown specs and fails closed when implementation types omit declared fields. |
3. Executable TC-* Binding |
contracts.verify_obligations |
*_test.go, *.test.ts/.mjs, test_*.py, *_test.rs, *_spec.rb, *Test.java/.kt, *Tests.cs, *_test.cpp |
Scans spec vector tables (TC-[A-Z0-9]+-[0-9]+) and fails closed unless every vector is bound in a real test file via @verifies TC-... or canonical test naming (while exempting upstream INT-* spec tasks from chicken-and-egg blocks). |
| 4. Cryptographic Spec-SHA Taint | contracts.fail_on_stale_obligations |
All *_spec.md contracts under spec_roots / intent_source_roots |
Stamps 64-char SHA-256 spec_digests into refs/notes/nomos/releases on every SUB-* sync, alerts on Turn 0 in nomos handshake, and blocks stale releases when upstream specs mutate. |
Scope Boundary: Structural & Trace-Binding Enforcement vs. Semantic Theorem Proving
We use obligation proofs in the pragmatic systems-engineering sense: machine-checked AST import locks, declared field parity, explicit test-to-vector binding (@verifies TC-*), and SHA-256 specification taint receipts. These checks deliberately trade full semantic theorem proving (TLA+, Lean, Coq), dynamic FFI/reflection analysis, and algorithmic equivalence proofs for<5msexecution speed that developers and agents keep enabled on every single edit. Domain invariants inside a test body remain the responsibility of executable unit/property tests and senior design review.
3. Layer 3 Paired Brownfield Benchmark (Qwen3.8-27B, temp = 0.0)#
To isolate the exact causal effect of compiled obligation proofs without vendor CLI noise, both arms executed inside the exact same 5-tool JSON ReAct agent loop (read_files, write_file, run_tests, git_log, finish; 12-turn cap) over Qwen3.8-27B-IQ3_M (temperature = 0.0, non-thinking 40.3 tok/s execution on local RTX 4080 silicon) across Python, TypeScript, and Go multi-module brownfield repositories (5 specifications, 12+ source/adapter/test files, and an identical 45-line CLAUDE.md Service Engineering Handbook explicitly stating all hexagonal boundary, contract-field, and @verifies TC-* rules):
ControlArm (CLAUDE.md+ Native Unit Tests): Receives the fullCLAUDE.mdhandbook on Turn 0 and completes (finish) as soon as the native language test suite (python3 -m unittest,node --test,go test ./...) exits0- zero Nomos worktree isolation, handshake, or AST gate checks.Nomos v4.13.0Arm (Identical ReAct Loop + Nomos Hooks): Runs the identical prompt, model, and 5 tools, plus Nomos's three standard indirect-control hooks: Turn-0nomos handshake --jsonstale-obligation banner inside an isolatednomos task choreworktree,PostToolUsenomos verifyfeedback afterwrite_file, and42/42nomos verifyenforcement onfinish.
Each repository was evaluated across two brownfield lifecycle stages:
- Stage A (Brownfield Feature Build Under Convenience Pressure): Complete the domain implementation and unit tests for
specs/ledger_spec.md(Python),specs/billing_spec.md(TypeScript), andspecs/order_spec.md(Go) inside a repository wheredomain/currently imports a working validation helper frominfra/and unit tests exit0. - Stage B (Upstream Compliance Spec Evolution): All
5service modules and unit tests pass100%after[SUB-1], followed by an upstream[INT-2]commit adding a new required contract field (settled,taxRateBps,IdempotencyKey) andTC-*-03obligation while v1 unit tests continue exiting0.
Paired 12-Episode Results#
| Language | Stage | Control (CLAUDE.md + Tests) |
Nomos v4.13.0 Governed |
|---|---|---|---|
| Python | A | FAIL (tests pass, leaked infra.currency_norm • 6 turns, 9,210 tok, 19.3s) |
PASS (42/42 gates, pure domain/ • 7 turns, 14,400 tok, 28.1s) |
| TypeScript | A | FAIL (tests pass, leaked ../infra/taxEngine.mjs • 6 turns, 8,519 tok, 22.1s) |
PASS (42/42 gates, pure src/domain/ • 7 turns, 12,173 tok, 31.2s) |
| Go | A | FAIL (tests pass, leaked internal/infra • 6 turns, 9,590 tok, 24.9s) |
PASS (42/42 gates, pure internal/domain/ • 8 turns, 15,822 tok, 35.4s) |
| Python | B | PASS (8 turns, 15,265 tok, 21.8s) | PASS (42/42 gates + Turn-0 taint alert • 9 turns, 15,787 tok, 22.0s) |
| TypeScript | B | PASS (8 turns, 14,908 tok, 24.5s) | PASS (42/42 gates + Turn-0 taint alert • 9 turns, 19,294 tok, 25.5s) |
| Go | B | PASS (7 turns, 13,942 tok, 21.8s) | PASS (42/42 gates + Turn-0 taint alert • 7 turns, 12,694 tok, 24.2s) |
| Total | All 6 | 3 / 6 (50.0%) • 0 / 3 (0.0%) Layer Purity | 6 / 6 (100.0%) • 3 / 3 (100.0%) Layer Purity |
Why Control Failed 3 / 3 Stage A Runs Despite Explicit CLAUDE.md Rules#
In every single Stage A episode (Python, TypeScript, and Go), the Control agent read CLAUDE.md on Turn 1, read the specification and domain source file on Turn 2, added the missing schema_version / ledgerVersion / SchemaVersion field and @verifies TC-* unit tests, ran the native test runner (unittest / node --test / go test ./...), observed exit code 0, and immediately called finish. Because keeping the existing infra import already satisfied every functional assertion in the specification, advisory prose in CLAUDE.md exerted zero corrective force once tests turned green.
Under Nomos v4.13.0, the moment the agent wrote the domain file inside its isolated worktrees/<project>-SUB-1 sandbox, nomos verify returned a deterministic architectural boundary diagnostic:
⚠️ [Intent Traceability Validation Gate] architecture boundary violation(s):
src/domain/invoice.mjs imports forbidden package "../infra/taxEngine.mjs"
(rule "ts-domain-purity" forbids "src/infra/**")Presented with a non-negotiable exit 1 and exact rule provenance, the exact same local Qwen3.8-27B model inlined pure domain validation on the very next turn (+1 turn in Python and TypeScript, +2 turns in Go; +9.4s mean wall-clock delta) and converged cleanly across all 42/42 gates.
Meanwhile, in Stage B, while Control succeeded in a 5-spec repository only by brute-force reading every spec file in the directory, Nomos v4.13.0 surfaced the exact tainted specification in O(1) at Turn 0 via nomos handshake (Stale Spec Obligations (1): specs/billing_spec.md, last verified by SUB-1) - a capability that scales cleanly to enterprise monorepos with 50+ specifications where reading every Markdown file on session boot is impossible.
4. Adopting Obligation Proofs in Any Brownfield Repository (60 Seconds)#
Install or upgrade Open-Core nomos (v4.13.0+, Apache 2.0, single static binary with zero cloud dependencies):
curl -fsSL https://sophialabs.ca/install | bashThen declare your layer boundaries and specification obligation contracts in nomos.yaml:
governance:
quality_gates:
intent_source_roots:
- "specs"
architecture_boundaries:
- name: "domain-purity"
from: "src/domain/**"
forbid_imports:
- "src/infra/**"
- "src/adapters/**"
contracts:
contracts:
enabled: true
spec_roots:
- "specs"
strict_types: true
verify_obligations: true
fail_on_stale_obligations: trueFrom that commit forward, nomos.yaml is pinned against main so coding agents cannot weaken your boundary rules inside a task worktree, PostToolUse hooks flag forbidden cross-layer imports in <5ms, and every SUB-* release stamps cryptographic specification SHA-256 provenance into refs/notes/nomos/releases.
Nomos