# JouleContract round five — the clean-room implementability audit **Target:** the published artifacts alone — SPEC v0.7, the conformance pack, the READMEs. The auditor was forbidden from reading `joulecontract-rs`. **Question:** can a third party build a conformant validator without reading the reference code? **Verdict:** **half.** A conformant *receipt-local* validator plus the DSSE edge is buildable clean-room (the auditor reproduced the contract's content address by experiment, verified the DSSE envelope from the published test seed, and verified the amendment chain byte-exact). A conformant **composed** validator — the part that distinguishes the standard — was not buildable: its inputs and one of its MUSTs were resolvable only by reading the code. Seventeen findings (P1–P17); the repair is roughly six normative sentences and a dozen vectors, folded as **v0.8 — the implementability amendment**. --- ## The two blockers **P1 — the evidence bundle existed only in code.** The conformant vector's composed verdict depends on a bundle address whose construction no document states and whose member *bytes* are published nowhere. The auditor recovered the algorithm by brute force — sixteen guesses to find `sha256(LF-joined sorted member addresses)` — and discovered along the way that the bundle's fourth member is the *contract's* ceiling-derivation attestation, which the pack's own note misdescribes (P15). §5.1.3's load-bearing operation, resolution within sealed evidence, was unexercisable against real bytes. *Closed in v0.8:* the bundle construction is one normative paragraph in §5.1.3, and the pack ships every member's bytes (`evidence-bundle.json`). **P2 — the negative vectors demanded composed verdicts but omitted the composed inputs.** Every `negative-*.json` carried `expected_composed` and no `sealed_context`; the verdicts were literally uncomputable from the files. *Closed in v0.8:* every negative vector embeds its sealed context. ## The spec-vs-vector contradiction **P3 — quorum.** §6's literal text ("k ≥ 2 at JR-3+", per-obligation discharge model) fails the golden vector, which reaches JR-3 with one verifier per entry. The implementation's actual rule — receipt-level quorum (≥ 2 distinct party-disjoint verifier entities across the discharge log) at JR-3, **per-obligation** quorum only at JR-4 — was knowable only from the code. *Closed in v0.8:* the scope is one sentence in §10, and the pack gains a JR-4 vector so per-obligation grading is visible. ## The silent-divergence class (serious) - **P4 — canonical JSON was named, never defined — and it is not RFC 8785.** JCS serializes `3.0` as `3`; this standard's canonical form keeps the float's decimal point. An honest implementer reaching for the obvious RFC produced the wrong digest. *Closed:* §7 defines the rules (UTF-8, code-point-sorted keys, no whitespace, shortest-round-trip numbers with float-ness preserved, explicitly NOT JCS), and the pack gains a canonicalization vector with the trap cases. - **P5 — three wire shapes, none declared normative** (§5.1's field list vs Appendix A vs the vectors). *Closed:* the vector pack is declared the normative wire form; Appendix A's field names aligned; the §5.1↔wire mapping stated. - **P6 — obligation matching** (exact `(kind, text)` equality; the frame array collapses to one obligation `"frame: " + join("+")`) was vector-archaeology. *Closed:* one sentence in §5.1. - **P7 — demotion order/multiplicity** (ordered multiset, one entry per affected discharge, snake_case wire tokens vs §15 display tokens). *Closed:* one sentence in the pack README. - **P8 — the gate logic** was derivable only by joint inference across seven vectors. *Closed:* the JR predicate summary in §10 plus the new vectors pin the untested boundaries. - **P9 — the KeyLog event model** (only `Added` was observable; revocation's two-timestamp shape was unrecoverable). *Closed:* §6.4 documents the event enum; a `verifier_revoked_window` vector exercises it. - **P10/P11 — the amendment record and transition record** had no wire form. *Closed for the transition:* its bytes ship in the pack. *Named for the amendment:* the contract-amendment wire object remains future work, stated rather than implied. - **P12 — the missing-vector census:** 7 of ~22 demoted states had vectors. *Closed:* the pack grows to cover the cheap single-mutation states (stale/unanchored timestamps, revoked window, undisclosed engagement, undeclared recourse, static-only frame, open breach, unterminated chain) plus the JR-4 receipt; composition/ratchet/re-anchoring vectors are named future work. ## What held Content addressing reproduced (once the float rule was found); the DSSE envelope verified structurally and cryptographically from the published seed; the MANIFEST checked out completely; the amendment chain verified byte-exact; the seven-obligation derivation and most of the demotion logic were reconstructible. The pack was honest — it was *incomplete*, and the incompleteness was invisible from inside. **The round's lesson, in the standard's own grammar:** the conformance pack made claims (`expected_composed`) whose evidence (the sealed context, the bundle bytes) was not sealed alongside — the pack itself was running `evidence:external` against the reference implementation. v0.8 seals the pack. *Prior rounds: `joulecontract-diff-v0.3-global.md` (semantic), `joulecontract-diff-v0.4-self.md` (binding), `joulecontract-diff-v0.5-self.md` (time/party/incentive), `joulecontract-diff-v0.6-impl.md` (implementation).*