# Word Of Clout — ASTRA-R3 Public Artifact Set

Round-three reply to Astra, shipped as a public artifact set. Everything a
third party needs to independently verify Word Of Clout signed records: a
synthetic conformance fixture (never a customer), the LIVE production record
(mo-dental-013494@2, signed by int1), the issuer trust stores, the exact
canonicalization recipe, a frozen hash-chained evidence export, and one
standalone verifier that runs every check — including the eight negative
cases — with no network and no dependencies.

- **Requirements:** Node.js ≥ 20. No network. No dependencies. Reads only the
  files beside it.
- **Generation freeze:** repo state `bd4afcfe` (the live boundary commit of
  the R2 boundary work), frozen 2026-09-13T05:23:16Z. The shipping commit is
  named in the cover note.
- **Integrity:** verify every file first — `sha256sum -c SHA256SUMS`.

## Files

| file | what it is |
|---|---|
| `README.md` | this file — inventory, commands, results |
| `fixture.json` | synthetic conformance record — Example Dental, LLC; invented subject, invented values; `record_class: conformance-fixture`. WoC is never subject, source, or signer of the same record. |
| `fixture.sig` | detached Ed25519 signature over `fixture.json`'s canonical form (fixture key `woc-fixture-2026-09`) |
| `record-mo-dental-013494@2.json` | the LIVE production record `mo-dental-013494@2` in canonical-form scope — 13 propositions (four-state verdicts only), 1 candidate relation carrying NO verdict, signed `dependency_manifest_sha256` (`bf102ea8…`), `supersedes: ["mo-dental-013494"]` |
| `record-mo-dental-013494@2.sig` | detached Ed25519 signature over its canonical form (int1 — the production signing authority) |
| `issuer-trust.json` | the issuer trust stores as enforced live: PRODUCTION = int1 only (`woc-int1-2026-09`); FIXTURE store separate and labeled (fixture + preview keys; a fixture key never authorizes a production record) |
| `canonicalization.md` | the exact v1.0 recipe + algorithm that produces the bytes every signature covers, with the cross-repo implementation pin |
| `export.jsonl` | frozen evidence export — 4 hash-chained lines (fixture freeze · production record freeze · trust store freeze · canonicalization freeze); each line's `prev_sha256` is the SHA-256 of the previous line's exact bytes |
| `export.manifest.json` | whole-file SHA-256 of `export.jsonl` + line count + chain head + the signed-snapshot reference (the int1-signed root-held host snapshot, sha256 `0e84e739e235b0941051de93935e9dd4af9dcc0fbcf8cd70bed09a0031b7839c`, OBSERVED at freeze) |
| `verifier.mjs` | the standalone verifier — commit id embedded; runs everything below |
| `SHA256SUMS` | SHA-256 over every file in this directory (except itself) |

## Quickstart

```
sha256sum -c SHA256SUMS      # integrity of the set itself
node verifier.mjs            # full run: 4 positives + all 8 negative cases
```

Expected full-run outcome (my self-run, frozen into this set):
12 passed | 0 failed | 0 blocked — every positive verifies, every attack
correctly rejected. Exit 0.

## Verify the LIVE production record against /.well-known yourself

```
curl -sS https://www.wordofclout.ai/.well-known/woc-issuer-keys.json > well-known.json
node verifier.mjs --record record-mo-dental-013494@2.json \
                  --sig record-mo-dental-013494@2.sig \
                  --well-known well-known.json
```

This checks the signature (Ed25519 over SHA-256 of the canonical form) AND
that the record's embedded key is the production issuer named in the live
well-known list — the same tool, the same recipe, the live trust anchor.
It reports the canonical SHA-256 (`9be5b7503f8105da5362c130814f3bc014da9a5f13f820cf5cacfa79b18b7ee8`)
so you can compare independently.

## The eight negative cases

Each case tampers IN MEMORY with the shipped artifacts and asserts the
attack is REJECTED. PASS = the attack was caught. Exact command for each
(and my self-run result, OBSERVED on this frozen set):

| # | case | exact command | result |
|---|---|---|---|
| 1 | issuer substitution — a different key claimed as issuer | `node verifier.mjs --case 1` | **PASS** — signature does not verify AND the key is not in the trust store — rejected |
| 2 | wrong subject/predicate mutation | `node verifier.mjs --case 2` | **PASS** — mutated subject changes the canonical form; signature does not verify — rejected |
| 3 | signed-field mutation (proposition state changed after signing) | `node verifier.mjs --case 3` | **PASS** — signature does not verify — rejected |
| 4 | dependency mutation (manifest digest changed, signature stale) | `node verifier.mjs --case 4` | **PASS** — `dependency_manifest_sha256` is INSIDE the signed scope — rejected |
| 5 | missing last record (truncated export) | `node verifier.mjs --case 5` | **PASS** — truncated export's whole-file SHA-256 does not match the manifest — omission detected |
| 6 | replay of older export (stale/edited line passes as current) | `node verifier.mjs --case 6` | **PASS** — breaks both the whole-file digest AND the `prev_sha256` chain — detected |
| 7 | deadline / clock / revocation | `node verifier.mjs --case 7` | **PASS** — revoked key refused; key with future `valid_from` refused |
| 8 | missing authorization (key absent from the trust store) | `node verifier.mjs --case 8` | **PASS** — refused authorization before eligibility |

`node verifier.mjs` (no flags) runs all of these in sequence. Exit 0 iff
every positive check passes and every attack is rejected.

## Self-run receipt (frozen into this set)

```
ASTRA-R3 — full verification (positives + eight negative cases)
  PASS  P1 fixture verifies (synthetic, Example Dental, LLC) — fixture store · key_id=woc-fixture-2026-09 · canonical sha256 ac7d2ccf1e009938…
  PASS  P2 production record verifies (int1, production store) — supersedes mo-dental-013494 · 13 propositions (four-state only) · 1 candidate relation(s), no verdict · manifest bf102ea848af3a4c…
  PASS  P3 export chain + manifest — 4 lines chained · whole-file sha256 + chain head match manifest
  PASS  P4 SHA256SUMS coverage — every file covered, every hash matches
  PASS  NEG-1 … NEG-8 (see table above)
12 passed | 0 failed | 0 blocked | 12 total
```

## Retractions (2026-09-13, count +3 — Tani, from the Astra R3 receipts)

Three case labels in the table above were OVERSTATED — the labels claimed
more than the cases actually tested. The shipped bytes and the observed
results are unchanged; the labels were wrong about scope:

- **NEG-6** was labeled "replay of older export" — the case tested
  TAMPERING detection (an edited line breaks both the whole-file digest and
  the `prev_sha256` chain). It did not test an INTACT older bundle
  replaying as current. Relabeled: **tampering**. The intact-replay case
  ships in r4 as NEG-9 (current mode).
- **NEG-7** was labeled "deadline / clock / revocation" — the case tested
  KEY STATUS only (revocation and validity window via a modified trust
  config). No record-deadline or clock evaluation ran. Relabeled: **key
  status**. The deadline-expiry case ships in r4 as NEG-10 (current mode).
- **NEG-8** was labeled "missing authorization" — the case tested an
  UNKNOWN KEY being refused trust-store recognition, not an authorization
  flow. Relabeled: **unknown key**. The wrong-scope authorization case
  ships in r4 as NEG-11.

Retraction count for this README: 0 + 3 = **3**. The two reviewer P0s
found against this verifier (I01: revoked key → exit 0 on the `--record`
path; I12: export tail removed with metadata recomputed → self-run still
12/12) are fixed in the r4 verifier, not here — this bundle is frozen
history; r4 ships as `/verify/astra-r4/`.