Repository navigation
Description
Split out of #14, which carried this as acceptance criterion 5.
Problem
A disclosure written on export does not stay written. An ffmpeg re-encode
produces a new file carrying none of the original container tags, stream tags,
C2PA manifest or XMP — and this repository's own video preview rendition path
goes through ffmpeg, so the loss is not hypothetical and not confined to what a
user does downstream.
So a file that was marked can stop being marked, and nothing today can put the
mark back.
Why it is restored from the database rather than from the file
The disclosure is derived from stored state, not from the file: the record is
built from what the row knows, and the outcome is already persisted to the
asset's extra._trace. Restoring from whatever metadata survived in the file
would be a different operation with a different failure mode — a stripped file
has nothing to read, and a partially stripped one is worse, because what
remains may disagree with the row.
Reading what a file already claims, and judging it, is #18. That separation is
deliberate and this issue does not touch it. Re-stamping asks nothing of the
file except that it exists.
What already exists
JobKind::DisclosureStamp (crates/asterism-core/src/domain/job.rs), whose
payload is {"asset_id": "..."}, and a handler that runs the disclosure
service over it (crates/asterism-infra/src/jobs/mod.rs).
It is enqueued from exactly one place — the dispatch handler chain, and only
for an asset a dispatch produced. There is no surface a person can ask for it
from: /asterism/jobs/* is stats, depth and log, and the only job-shaped
command on the contract is CancelJobCommand.
What this needs
- A command on
asterism-contract, in the shape the existing commands take.
DeclareProvenanceCommandis not a candidate to extend: that verb writes
a derived-from claim intodomain::provenance, the claim graph, which is a
different model fromdomain::disclosureand keeps the word for that reason. - HTTP and Tauri IPC routes, and the regenerated
bindings.ts. - A place in the UI a person reaches it from.
- A decision this issue is expected to make: whether the verb takes one asset,
a selection, or a query.
Not in scope
- Reading what a file already carries and judging it — Model what a file already discloses, and judge it separately from whether its signer is trusted #18.
- Signing configuration — Write AI-disclosure provenance on export: IPTC 2025.1 and C2PA, including video #14's step 5, landed. Re-stamping works with no
certificate configured: it rewrites the IPTC/XMP half and reports the
manifest half as skipped, exactly as an export does. The two share a writer
and nothing else.
Open — to be settled while implementing
- Whether the same verb backfills assets that were never stamped. The
operation is identical; only the target set differs. Article 50 does not
require content generated before 2026-08-02 to be labelled retroactively, so
this is a choice rather than an obligation — but it is the same button, and
deciding it separately from this issue would mean deciding it twice. Inherited
from Write AI-disclosure provenance on export: IPTC 2025.1 and C2PA, including video #14, which carried it as an open question.
Acceptance criteria
- A person can ask for an asset's disclosure to be written again, from a
surface the UI reaches. - What is written comes from stored state. The file's existing metadata is not
read. - The outcome is reported on the same terms an export's is — both halves
accounted for, recorded on the row — so a re-stamp that half-landed is not
recorded as a success. - With no signing identity configured, a re-stamp writes the XMP half and
reports the manifest half as skipped rather than as a failure. - A re-stamped MP4 or MOV gets the manifest and reports the XMP half as one
the container cannot carry.
Activity