open-standards/joulecontract/conformance/README.md
Transaction Science 429dc59a83 joulecontract v0.8: the implementability amendment — round five seals the pack
Round five turned the adversarial method on the published artifacts
themselves: a clean-room auditor, forbidden from reading joulecontract-rs,
attempted to build a conformant validator from SPEC + conformance pack
alone. Verdict: receipt-local yes, composed no. Seventeen findings
(provenance/joulecontract-diff-v0.7-pack.md) — the bundle construction
was recoverable only by brute force, the negative vectors demanded
composed verdicts while omitting their sealed contexts, the key-log
event model showed one variant of two, the spec's literal quorum MUST
failed the golden vector, and RFC 8785 (the canonicalization any honest
implementer reaches for) produces the wrong digest.

SPEC v0.8.0 amends v0.7.0 (archived byte-exact; seven verified anchors):
bundle address = digest of LF-joined sorted member addresses; canonical
JSON defined precisely (float-ness preserved — deliberately not JCS);
DSSE PAE in the spec text; quorum scope stated (receipt-scoped k≥2 at
JR-3, per-obligation at JR-4); obligation matching exact with the frame
synthesis rule; the pack declared the normative wire form; timestamps
integer seconds; the KeyLog Added/Revoked enum on the wire.

Pack expands 13 → 22 vectors: evidence-bundle.json ships every member's
bytes (incl. the transition record), every negative embeds its sealed
context, four new mutation negatives (engagement_undisclosed,
recourse_undeclared, static_only_frame, unterminated_chain), three
context-variant vectors (timestamp_stale, breach_unamended,
verifier_revoked_window), and a JR-4 receipt making per-obligation
quorum visible. The EnB object is now sealed evidence and resolved by
the composed validator. Conformance README rewritten as an
implementer's guide; remaining unvectored behaviors stated explicitly.

Also: joule-code pre-existing clippy warnings fixed (workspace now
zero), binding emits 0.8.0.

76 joulecontract tests + 39 joule-code tests green, clippy zero on both
workspaces. Site: Round 5 card + seven-anchor chain, redeployed.

The round's lesson in the standard's own grammar: the pack was making
composed claims whose evidence was not sealed alongside — it was
running evidence:external. v0.8 seals the pack.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 16:21:44 -04:00

37 lines
5.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Conformance vectors — v1
Deterministic wire vectors for independent JouleContract implementations. Regenerate with:
```
cargo run -p joulecontract-conformance --bin gen_vectors
```
This pack is the **normative wire form** (SPEC §5.1): where prose and wire diverge, the wire rules. It was expanded at v0.8 after a clean-room implementability audit (round five, `../provenance/joulecontract-diff-v0.7-pack.md`) found that the composed validation path could not be built from the published artifacts alone — every input a composed verdict needs now ships in the pack.
## Reading the vectors
- **Canonical JSON** (SPEC §7): UTF-8, code-point-sorted keys, no whitespace, shortest round-trip numbers **with float-ness preserved** (`3.0` stays `3.0` — this is deliberately *not* RFC 8785/JCS, which would collapse it to `3`). Content addresses are SHA-256 over the canonical form's bytes, written `sha2-256:<hex>`.
- **Expected demotions are an ordered multiset**: per-discharge demotions appear once per affected discharge entry, in discharge order; receipt-level demotions appear once. A validator must reproduce the multiset; reproducing the exact order is RECOMMENDED but set-with-multiplicity equality is conformant.
- **Demotion wire tokens** are the snake_case forms of the SPEC §15 names (`independent_false` for `independent:false`); `undischarged` serializes as an object carrying its reason.
- **`claim` strings are informative**, not normative — match the verdict fields (`demotions`, `max_profile`, `permits_claimed_profile`), not the prose.
- **Timestamps are integer seconds.** Obligation matching is exact `(kind, text)` equality; the contract's `frame` array declares one obligation with synthesized text `"frame: "` + entries joined by `"+"` (SPEC §5.1).
- **`energy_anchor`** is the calibration-attestation reference required for `ModelBased` receipts; it is `null` on a `Metered` receipt because the meter binding plus the contract's ceiling-derivation attestation carry the anchoring there. **`recourse`** is a free-string regime identifier (`"ISAE3000"`, `"eIDAS-Art13"`, a bond reference); absence — not any particular value — is what serializes `recourse_undeclared`.
- **Verifier-key disjointness** (SPEC §5.1.1) is computed against the effective generator key set; it does **not** require the verifier key to appear in the office key log — the log governs time coordinates (revocation windows, as-of membership), not the disjointness predicate.
| Vector | What a conformant implementation must do |
|---|---|
| `contract.json` | Content-address it; derive **seven** obligations (two pre, two post, two inv, one frame). |
| `receipt-conformant.json` | Two expected verdicts: receipt-local validation caps at **JR-2** (it cannot witness the JR-3+ gates), and composed validation over the embedded `sealed_context` grades **zero demotions**, the stated max profile, and permits the claimed `⟨JR-3 · Metered · certified⟩`. |
| `receipt-jr4-conformant.json` | Grade **JR-4**: every obligation discharged twice by party-disjoint verifier entities. Quorum at JR-3 is receipt-scoped (k ≥ 2 distinct entities across the discharge log); at JR-4 it is per-obligation, expressed as multiple discharge entries per obligation (SPEC §10). |
| `evidence-bundle.json` | Recompute every member address from the published bytes, recompute the bundle address (SHA-256 over the LF-joined, lexicographically sorted member address strings — SPEC §5.1.3), and match `receipt.evidence`. The transition record's bytes are included so `receipt.transition` is checkable too. |
| `negative-*.json` (11) | Produce exactly the expected composed demotions and max profile against the **embedded** `sealed_context`. One case per load-bearing demotion: unbound meter, generator-key overlap (incl. the under-declared key set), entity-omission key-only independence, undischarged frame, stochastic-alone verdict, unattested generator, self-attested loop governance, undisclosed engagement, undeclared recourse, static-only frame, unterminated qualification chain. |
| `context-*.json` (3) | The receipt is byte-identical to the conformant one; the demotion lives in the **context**: stale anchors (`timestamp_stale`), an open unamended breach (`breach_unamended`), and a key-log revocation window spanning the start anchor (`verifier_revoked_window`, exercising the two-timestamp `Revoked` event — SPEC §6.4). |
| `malformed-missing-obligations.json` | **Reject** as malformed — an unmentioned obligation is a hole in the record, not a demotion. |
| `malformed-inflated-allowance.json` | **Reject** as malformed — `joules_allowed` binds to the contract's ceiling; an inflated allowance is residual minting, not a demotion. |
| `envelope-dsse.json` | Verify the DSSE envelope (Ed25519 over the PAE — formula in SPEC §7) with the published test key; recover the in-toto Statement; check `_type`, `predicateType`, and both subjects (in-toto digests use bare `sha256` hex; native fields keep the `sha2-256:` prefix). |
| `amendment-chain.json` | Verify each digest against the byte-exact files in [`../archive/`](../archive/) — seven anchors, v0.1 through v0.7. |
| `MANIFEST.json` | Verify every vector's content address before relying on it. |
**Not yet vectored** (stated, not implied complete): composition/decomposition (SPEC §3.3), the ratchet (§5.3), re-anchor records (§3.1), sector-equivalence claims (§10), and the contract-amendment wire object (§5.2) — the reference implementation covers these in its test suite; pack vectors are future work.
**The test key is not a trust root.** Vectors must be reproducible, so `envelope-dsse.json` is signed with a published seed (`0x2a` × 32). It attests nothing; treat any receipt signed with it as `generator_unattested` everything. The pack itself is integrity-checked by `MANIFEST.json` and, in-repo, by the conformance crate's tests on every run.