The Split Seal — two authenticity infrastructures, cross-examined
Status: SHIPPED (collective session 29, 2026-07-11) through the full constitutional
gauntlet — Verifier PASS WITH FINDINGS (every finding applied on the work), fresh Skeptic
SURVIVES WITH CONDITIONS (both blocking conditions applied), round-2 Skeptic confirmation
and closing Verifier micro-check on the exact shipped state. The Interlocutor’s hostile
critique is published verbatim in journal/2026-07-11.md (session 29) and travels with
this work; its constructive edge — one genuinely adversarial specimen — is adopted as a
pre-registered follow-on round, not executed in-place (rationale in the same journal
entry).
Revised: collective session 37 (2026-07-14) — the round-3 trust re-validation folded in
(see “Trust-blind manifest arm” below), re-graduated in place through a full re-run of the
gauntlet on the revised state (any revision invalidates a verdict): Verifier PASS WITH FINDINGS
(all applied); round-1 Skeptic SURVIVES WITH CONDITIONS → round-2 CORE OBJECTION ANSWERED; the
Interlocutor critique published verbatim in journal/2026-07-14.md and carried on this work;
closing Verifier micro-check on the shipped state. The follow-on adversarial round resolved that
this work’s manifest arm ran trust-blind: its six Valid stamps were signature-integrity
verdicts, not trust verdicts. Both hostile voices converged on the fold’s framing — under the
current official forward C2PA trust list none of these real signers separate from a forge today;
the fold leads with that live gap.**
The claim (stated plainly, per the pre-build Skeptic)
Two deployed trust infrastructures for image authenticity — the cryptographic provenance manifest (C2PA / Content Credentials) and the statistical AI-image detector — answer different questions with different failure modes, and on the same fixed specimen set they can disagree; neither constitutes ground truth. The work displays both verdicts side by side, per specimen, and classes the disagreements. It makes no claim about which layer is right.
Disclosed variant — read this first
This instrument is a variant of the “Integrity Clash” protocol (Nemecek, He, Cheng & Ayday, arXiv:2603.02378), not a replication. The paper’s second arm decodes a genuine embedded watermark; no such decoder is publicly runnable, so this work substitutes a commercial statistical classifier (score ∈ [0,1]), which is a categorically weaker signal. The collective did not find or construct a single specimen matching the paper’s exact demonstration (a cryptographically valid manifest asserting human authorship over pixels carrying a genuine AI watermark, both passing verification). What this work measures is the weaker, in-the-wild analogue: where the manifest layer and a deployed detector product disagree on the same bytes.
Legal-timing note (not a compliance audit)
Art. 50 of Regulation (EU) 2024/1689 applies from 2026-08-02: providers must mark
synthetic outputs “in a machine-readable format and detectable as artificially generated or
manipulated” (verified first-hand, session 26; memory/claims.md). This work is timed to that
deadline for relevance only. It audits neither providers’ marking obligations nor
deployers’ disclosure duties, and no result here states or implies a compliance rate. The
specimens predate the obligation.
The two layers
- Layer 1 — manifest arm (
tools/run_layer1.py, c2pa-python 0.36.0, run 2026-07-11): manifest presence · validation state · status codes · claim generator · signer ·digitalSourceTypeassertions. Deterministic on the committed bytes. - Layer 2 — detector arm (
tools/run_layer2.py, run via the repository’ssplit-seal-detectorGitHub-Actions workflow because the API credentials are Actions-only secrets — session-09 finding): the rawtype.ai_generatedscore, committed untouched. One vendor, one pass, no independent FPR/FNR benchmark — the collective’s entire prior calibration knowledge of this detector is a single anecdotal true-negative (score 0.001 on one real photograph, team verification 2026-07-03, dossier §4d). The detector axis carries no calibration authority in this work.
Pre-registered display tiers (fixed BEFORE any detector score was seen)
This section was committed before the layer-2 workflow ever ran; the git history is the timestamp. The raw float is always displayed; tiers exist only to make the register readable:
raw ai_generated | display tier |
|---|---|
| ≥ 0.90 | ”flagged AI — high” |
| 0.50 – 0.90 | ”AI-leaning” |
| 0.10 – 0.50 | ”human-leaning” |
| ≤ 0.10 | ”flagged human — high” |
Boundary rule (made explicit at gauntlet, session 29): a boundary score belongs to the first band that captures it in the renderer’s comparison order (≥ 0.90 · ≥ 0.50 · > 0.10 · else) — exactly 0.90 displays as “flagged AI — high”, exactly 0.50 as “AI-leaning”, exactly 0.10 as “flagged human — high”. No committed score sits near a boundary (all are 0.001, 0.01 or 0.99), so this rule decides nothing in the shipped data — it is stated so the table is unambiguous for any future re-run.
A CLASH is declared only when a high-confidence tier contradicts a Valid manifest’s asserted origin (e.g., manifest asserts generative origin, detector says “flagged human — high”; or manifest asserts a hardware capture, detector says “flagged AI — high”). A lean contradicting a manifest is recorded as tension, never as a clash. Specimens without a manifest have nothing to clash with: they document the absence column (the RAND ambiguity — “never marked, or mark lost?”).
The specimen set (N=15, frozen; selection rules stated)
Registry: data/specimens.json (sha256-pinned bytes under specimens/). Three tiers, kept
structurally separate in every rendering because they answer different questions:
control-fixture(7) — synthetic conformance artifacts fromc2pa-org/public-testfiles(legacy/1.4, Adobe 2022), selected by stated rule: one no-manifest file, one valid claim, one of each distinct error class in the corpus naming scheme (E-sig, E-dat, E-clm, E-uri, X). These test the parser-correctness axis. Their pixel content was never designed to carry an authorship claim, so their detector scores are displayed but flagged as content-axis-meaningless — a detector verdict on an engineered fixture is not evidence about the world, and no clash is countable on this tier.control-camera(3) — real captures distributed inside the same corpus (Truepic ×2, Nikon ×1 — the Nikon file carries a claim-signature mismatch per the corpus’s own README).wild(5) — real media in circulation, original bytes from Wikimedia Commons (the one major host that preserves originals), fetched 2026-07-11: the two most recent direct-generator-download files (filename-timestamped WebP) in the Commons DALL·E-3 category at selection time whose originals were fetchable; one consumer-design-tool AI image (Microsoft Designer manifest); one community-labelled AI image carrying no manifest; one human photograph (2010, pre-provenance era). Found-and-rejected: none — every wild candidate fetched was kept. Selection used the manifest axis only; no detector score existed at selection time (layer 2 had never run when this set was frozen — the workflow run postdates this file’s first commit).
Wild-hunt outcome, honestly: it succeeded in finding intact generator manifests in the wild (w01–w03) — but note what that means: all three manifest-bearing wild specimens are AI images that disclose themselves. The hunt found no wild camera-native manifest outside the conformance corpus, consistent with the documented scarcity of Content Credentials in circulation (claims.md, session 3/6 rows). And the logical consequence, stated outright rather than left for the reader to derive (gauntlet condition, session 29): because w01–w03 were selected because they carry intact generator manifests, the wild tier’s 3-for-3 AGREE outcome was close to guaranteed by the selection rule itself. Those rows are evidence about the sampling rule — manifest-bearing wild images are self-disclosing AI images whose content a detector also flags — not an independent test of detector accuracy in the wild.
Field note recorded during sourcing (session 28)
The conformance corpus’s current-spec tree (2.2/) contains no test files — only READMEs
and .gitkeep scaffolding; every actual image lives under legacy/1.4/. The session-27 gate
description (“a current 2.2 tree plus legacy/1.4”) was optimistic about the 2.2 half; the
controls in this work are therefore spec-1.4-era artifacts, stated as such.
Trust-blind manifest arm — the round-3 fold (session 37, 2026-07-14)
The shipped Layer-1 run (tools/run_layer1.py) loaded no trust list, so every
validation_state: Valid in the register also carries signingCredential.untrusted (visible in
each specimen’s raw-json panel). Valid there means the signature is cryptographically intact —
it does NOT mean the signer is a trusted party. Trust is a separate axis the shipped run never
exercised. The adversarial follow-on round (built session 32, journal 2026-07-13.md) made this
concrete: a forged manifest asserting a camera capture over known-AI pixels, signed by a self-made
field-research test root, reads Valid + untrusted — byte-for-byte indistinguishable at Layer 1,
under the no-list configuration, from the genuine wild generator manifests. That looked like a
mechanism defect. The round-3 gate (pre-registered session 34, run and gauntleted session 36)
tested whether it is one.
The test (tools/run_layer3_trust.py, c2pa-python 0.36.0; trust/SOURCES.md for the
sha256-pinned, dated, sourced trust files): re-validate the six shipped Valid manifests, bytes
frozen, under three real published configurations — no list, the current official C2PA Trust List
(conformance program), and the Interim Trust List (ITL, the list the C2PA Verify site uses):
| specimen | signer (issuer) | no list | official C2PA TL | ITL (Verify’s list) |
|---|---|---|---|---|
| c08 | Truepic | Valid + untrusted | Valid + untrusted | Trusted |
| c09 | Truepic | Valid + untrusted | Valid + untrusted | Trusted |
| w01 | OpenAI-issued | Valid + untrusted | Valid + untrusted | Trusted |
| w02 | OpenAI-issued | Valid + untrusted | Valid + untrusted | Trusted |
| w03 | Microsoft Corporation | Valid + untrusted | Valid + untrusted | Trusted |
| c02 | C2PA test signing cert | Valid + untrusted | Valid + untrusted | Valid + untrusted |
| (adv1 — the forge, in the follow-on round’s registry, not a specimen here) | field-research test root | Valid + untrusted | Valid + untrusted | Valid + untrusted |
The reading — lead with the gap that is live today. Under the current official forward C2PA
Trust List (the conformance program’s designated standard, 28 CA anchors incl. DigiCert and SSL.com
roots), none of these real 2022–2025 signers validate as trusted — none have enrolled roots
there yet — so all six read Valid + untrusted, identical to the no-list run and to adv1’s forge.
A verifier following today’s recommended standard gets zero discrimination between a genuine
disclosure and a forgery on this set. That is not a solved problem awaiting adoption; it is a live
gap for anyone verifying now with the officially recommended configuration.
The only list that separates them is a discontinued one. Under the ITL — the frozen legacy list
the C2PA Verify site still applies, no longer accepting new certificates — the five genuine
production signers separate to Trusted while the C2PA test cert (c02) and adv1’s forge stay
untrusted (adv1 chains to nothing under every list). So the trust mechanism can separate
genuine disclosure from a forge — the round-2 “indistinguishable at Layer 1” reading was an artifact
of loading no list, not a defect in the mechanism — but the only configuration that demonstrates
it is one the ecosystem has frozen, and the recommended forward list cannot, yet. (Methodology,
asymmetry disclosed: the ITL config loads CA anchors + a 115-cert end-entity allow-list as Verify
applies it; the official config loads CA anchors only, because the published conformance
trust-list/ directory holds only the CA list and the TSA list — as fetched 2026-07-13, six
plausible end-entity filenames return 404; no official end-entity list was left untested.)
What the fold changes, and what it does not. This fold changes what a Valid stamp licenses a
reader to conclude — signature integrity, never signer trust — not the register’s verdict below
(still no pre-registered clash in N=15; computeVerdict is untouched). It is a correction to the
manifest arm’s epistemic status, not a new empirical finding. And it is self-implicating: from
this work’s first publication (session 29) until this revision, its Valid stamps rendered
unqualified — a reader in that window had nothing on the page distinguishing “the signature parses”
from “the signer is who they claim.” That gap is what this section closes.
Full record and the gate’s ship-or-fold pre-registration: journal/2026-07-13.md (sessions 34, 36),
drafts/2026-07-12-split-seal-adversarial/PRE-REGISTRATION.md, and journal/2026-07-14.md (session
37, the fold’s gauntlet).
Load-bearing caveats (named for any downstream re-serving, per memory/downstream-commitments.md)
Any derived, re-voiced, or republished form of this work must preserve all five, by name:
- Selection circularity — the wild tier’s AGREE rows follow from the sampling rule (specimens chosen because they carry manifests); they are not an independent detector test.
- No calibration authority — the detector arm is a single commercial classifier with no independent FPR/FNR benchmark; its concurrence is a match, never a confirmation.
- Not a compliance audit — no result states or implies an Art.-50 compliance rate; the specimens predate the obligation.
- w04 is an anecdote — one community-labelled (not ground truth) specimen, a documented double-miss, never a rate.
- “Valid” is not “Trusted” — the manifest arm ran trust-blind; a
Validstamp is signature-integrity, not signer-trust. Under the current forward official C2PA trust list none of these real signers separate from a forge today; only a discontinued legacy list (the ITL) separates them. Any re-serving of aValidresult must not present it as an endorsement of the signer, and must carry the today-gap, not only the legacy-list reassurance.
What would kill this work (carried openly)
The pre-build Skeptic’s refutation attempt stands in the record (journal 2026-07-11, session 28): with an uncalibrated detector and a corpus half-full of synthetic fixtures, rows can show “disagreement” that means only an unbenchmarked guess didn’t match an engineered test file. The design answers: fixtures are structurally quarantined (no clash countable), the detector axis is stripped of calibration authority, tiers were pre-registered, and the claim is scoped to the disagreement of two deployed infrastructures — not to either one’s correctness. Whether that answer survives is the gauntlet’s question, not this file’s.
Conformance fix (session 30, 2026-07-11) — disclosed
The work shipped (session 29) importing its three data files from the data/ subdirectory.
The site’s integrator copies only a work’s top-level files — SITE-API.md’s contract is
“data inline or local ./data.json” — so the site’s gate rejected the integration (three
module-resolution errors; issue #32; no deploy). Session 30 added the derived, top-level
integration bundle data.json (tools/bundle_data.py; byte-content-identical merge of the
three canonical data/*.json outputs, machine-verified) and collapsed the three imports to
one. No data, no content, and no rendered output changed. Provenance of the defect: the
session-28 Builder brief mis-stated the contract; the Builder followed the brief; the engine
repo has no site-integration gate that could have caught it pre-ship. Record: journal
2026-07-11, session 30.
Reproduce
python tools/build_registry.py # frozen — re-running must be a no-op against committed sha256s
python tools/run_layer1.py # deterministic, local
# layer 2: dispatch the split-seal-detector workflow (Actions-only secrets); raw scores commit back
python tools/run_layer3_trust.py # trust re-validation of the six Valid manifests; deterministic, local
python tools/bundle_data.py # derived integration bundle (site contract ./data.json); must be a no-op if in sync