Decide the SynthID proxy in the verdict, where both extractors meet

A full-corpus audit of the record path against the file path found 75 of 48,905
images disagreeing, and 74 were one gap: the SynthID byte scan for containers whose
manifest no parser reaches lived in `get_ai_metadata`, an extractor the record path
does not run. The record silently reported no SynthID for images `identify` flagged.

Moving the scan into `identify_from_evidence` fixes it by construction rather than by
copying the rule into a second extractor -- the same shape `soft_binding` already
uses. Its byte checks mirror `metadata.synthid_source` literally instead of reusing
the broader `has_c2pa` / `c2pa_source_kind` derived above, so the file path's answers
do not move: verdicts over a 4,000-image sample are byte-identical.

`scripts/record_parity_audit.py` is the audit itself, now repeatable. It walks a
dataset, judges every image through both seams with the record round-tripped through
JSON, and reports disagreements by field and by signal. The rule in
`.claude/rules/development.md` says to re-run both sides of this seam after changing
either; this is what to run.

Both timing and audit scripts now put the package's OWN `src` on the path. From a
worktree an editable install resolves to the main checkout, so the audit imported a
different tree than the one under test -- the failure the same rules file warns about,
reproduced within an hour of writing it down.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Victor Kuznetsov
2026-08-05 21:10:38 -07:00
co-authored by Claude Opus 5
parent 2668f1302d
commit bebff368fc
5 changed files with 299 additions and 4 deletions
+7 -1
View File
@@ -391,7 +391,13 @@ metadata extraction from verdict logic:
metadata record into the same evidence type without file access. Diagnostic
values under `error` and `kind` are excluded from evidence while nested raw
bytes remain available through encoded binary fields.
- `identify_from_evidence` evaluates that evidence without reopening the source.
- `identify_from_evidence` evaluates that evidence without reopening the source. Rules
that decide a verdict live here, not in extraction: extraction has two
implementations, and a rule in only one of them is a rule the other lacks. The
SynthID proxy is the worked example — its structured form comes from the manifest,
and the byte-scan fallback for containers no parser reaches runs in the verdict, so
both extractors reach the same answer. It did not, and the record path silently
reported no SynthID for images the file path flagged.
- `identify` preserves the path-based API and adds the optional registered
visible-mark and open invisible-watermark decoders after extraction.