# 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. Public keys embedded in evidence are never trust anchors. Production verification additionally requires `--trusted-key-registry <external.json>` whose repository/deployment-owned security and owner Ed25519 SHA-256 fingerprints are outside the evidence bundle; any self-supplied unknown key is rejected even when its signatures are valid. Fixture mode accepts only the exact built-in fixture key fingerprints plus exact `environment.json.fixture_environment` metadata. Production rejects those fingerprints regardless of owner labels, including when labels are stripped. The verifier prefers Python `cryptography`, admits it only after the RFC 8032 known-vector positive and corrupted-signature negative checks pass, and does not invoke OpenSSL on that path. If `cryptography` is unavailable (or the self-test explicitly forces fallback), it capability-probes `/usr/bin/openssl pkeyutl` with the same checks. It reports typed `ed25519-validator-unavailable` only when no selected backend passes capability; a signature rejected by a capable backend remains distinct `invalid-ed25519-signature`. 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> \
  --trusted-key-registry /deployment/trust/platform-auth-ed25519-fingerprints.json
```

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 immutable repository-owned `oracle-registry.json`, keyed by `(route, phase, category, crash_seam, oracle_id)`, and the verifier's registered identity set. Generated cases retain observations only; producers cannot rewrite expected outcomes or effects inside evidence. 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`. Every retained path is inspected with `lstat`; symlinks, multiply linked or aliased inodes, non-regular payloads, path escapes, and unlisted files are rejected. Publication equality includes file type and exact bytes. Every trace/evidence payload is independently scanned for cookie, password, CSRF, refresh/access/reset token, authorization, and request/response-body secrets; sink rows are not trusted as proof of absence. `forms_searched` must be exactly four unique values: `raw`, `url`, `base64`, and `hex`. 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 210 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.
