# Auth split-origin acceptance contract

Status: executable evidence contract; production/browser evidence is BLOCKED until a production-equivalent input bundle exists.

## Inputs

The harness writes a run to `quality/acceptance/auth-split-origin/input/<run_id>/` containing exactly:

- `environment.json`
- `cases.ndjson`
- `summary.json`
- `sink-inventory.json`
- `sink-search.ndjson`
- `db-assertions.ndjson`
- `crash-injection.ndjson`
- `artifact-manifest.json`
- `traces/` containing sanitized Playwright traces only
- `SHA256SUMS`

The separately signed source manifest is `quality/acceptance/auth-split-origin/input/<run_id>/auth-sensitive-data-flow.json`. `environment.json.redaction_manifest.sha256` is `sha256:` plus the SHA-256 of its exact bytes. `sink-inventory.json.manifest_sha256` is the same digest without the prefix and `sink-inventory.json.entries` must be an exact JSON value copy of the signed manifest's `entries`; the verifier rejects any projection, omission, reordering, or changed value.

The closed manifest uses exact production/mail hop-class enums, unique reciprocal graph edges, unique hop/probe IDs, and explicit disabled-hop semantics. It has exactly one root, and every hop is reachable from that root; multiple independently rooted signed components are invalid. Every enabled entry has exactly one probe and an Ed25519 owner signature; disabled entries have no probe and a nonempty reason. Owner signatures cover canonical UTF-8 JSON (object keys sorted, no insignificant whitespace, `ensure_ascii=false`) of the complete entry excluding `owner_signature`. The security-owner Ed25519 signature covers the same canonical encoding of the complete manifest excluding `security_signature`. Public keys and signatures are standard padded base64. Self-test fixture keys must be labelled visibly `NON-PRODUCTION TEST KEY`; production manifests may not use fixture keys. The verifier cryptographically verifies every signature and fails closed if Ed25519 support is absent. The sink inventory is an exact copy of entries. Every enabled hop has exactly one matching retained probe whose marker classes exactly equal that hop's declared data classes and whose marker count equals that set's cardinality.

## Command and outputs

From the repository root:

```sh
python3 quality/acceptance/auth-split-origin/verify.py \
  --input quality/acceptance/auth-split-origin/input/<run_id> \
  --manifest quality/acceptance/auth-split-origin/input/<run_id>/auth-sensitive-data-flow.json \
  --publication artifacts/platform-auth/<run_id>
```

Only a fully schema-valid, digest-valid, production-equivalent bundle whose summary and every record are PASS exits 0 and prints one sanitized `VERDICT=PASS` line. PASS is derived from exact equality with the verifier's registered route/phase/category/OPTIONS/browser/crash identity set, with exactly one record per identity; record counts cannot substitute for identities. Every case must have nonempty exact DB, sink, trace, and evidence references. The verifier recomputes the canonical observed-outcome hash and every referenced trace/evidence file hash, and rejects zero or arbitrary claimed digests. DB assertions are used exactly once, bind back to the matching case and action, equal that case's independently observed operation delta, and match its owner/session/family/generation context. Missing input, validator support, fields, files, records, signatures, digest equality, exact manifest copy, production equivalence, or any FAIL/BLOCKED record exits 2 and prints `VERDICT=BLOCKED`; the verifier never manufactures a PASS or fills evidence defaults. Schema/data faults are evidence invalidity and therefore BLOCKED, not test FAIL.

Output remains in the input run directory; verification does not rewrite evidence. `SHA256SUMS` strictly lists every retained file except itself. To avoid digest recursion, `artifact-manifest.json.files` and `summary.json.artifacts` each list the exact same payload set: every retained file except `SHA256SUMS`, `artifact-manifest.json`, and `summary.json`. All paths are closed normalized relative POSIX paths; sets, byte counts, and digests must agree. The retained publication path is `artifacts/platform-auth/<run_id>/`, must be distinct, and is revalidated byte-for-byte by the same invocation before PASS. No raw cookie, CSRF, password, reset token, auth response body, HAR body, or secret may be retained.

## Schema and public self-tests only

```sh
python3 quality/acceptance/auth-split-origin/self_test.py
```

This checks every schema with a Draft 2020-12 metaschema validator, proves an absent production bundle returns BLOCKED/exit 2, and generates deterministic, cryptographically signed fixtures in a temporary directory. The valid fixture traverses the complete verifier with exactly 209 registered identities and 32 sink classes, recomputed outcomes, trace/evidence hashes, DB/action/context/generation closure, marker coverage, artifact closure, and a distinct byte-identical publication. Negative fixtures reproduce the exact prior 102-case/32-sink fabricated-bundle attack and a fully signed but disconnected 32-sink graph; both must return BLOCKED for the intended reason.

Fixture owners are visibly labelled `NON-PRODUCTION TEST KEY`. The private `--test-fixture` verifier switch exists only so this public self-test can traverse the success path without emitting a production `VERDICT=PASS`; without it, any labelled fixture is rejected as `non-production-test-key`. These fixtures do not run or imply any production or browser case.

Reproduce any fixture deterministically with:

```sh
python3 quality/acceptance/auth-split-origin/generate_test_bundle.py \
  --out <directory> \
  --scenario valid|fabricated-minimal|disconnected-graph
```

The generator writes the input bundle to `<directory>` and its byte-identical publication to `<directory>-publication`. Both are test-only and contain no production observations or secrets.
