When provenance capture refuses
Reading a TVO-PROV error, and why almost all of them keep your commit.
Written By Dustin
Last updated About 3 hours ago
Provenance capture has its own error family, TVO-PROV-*. Before the individual codes, there is one rule that decides what a capture failure actually costs you:
If nobody asked for the transcript, a failure drops the session and your commit lands. If you named a transcript, a failure refuses the command.
You count as having named one if you passed --session-from, set TOVIO_OBSERVED_TRANSCRIPT, or configured provenance.observed_from. That last one matters: a durable setting makes every subsequent capture failure a commit failure, without you typing a flag.
Both halves are deliberate. Failing a commit over a capture nobody requested would make the feature radioactive, and a gate people disable protects nothing. But silently skipping a capture you explicitly asked for would leave you believing provenance was recorded when it was not, which is worse than an error.
In the refusing case, nothing partial is left behind — the capture is prepared before any object is written, so the repository is untouched. The commit simply did not happen. --no-session re-runs it without the capture; commit, resolve, and land all accept the flag.
Refusals when a run record is captured
Every row below drops the session on the discovered path and refuses the command on the explicit one, unless the row says otherwise.
TVO-PROV-008 also has a Forge-side form: a push carrying an observed record into a repository that pins observed capture off is rejected the same way TVO-PROV-006 rejects an attested one. The two policies are independent on purpose — "mandate attested sessions, forbid host-scraped ones" is a coherent posture, and one shared refusal would misreport which mandate you crossed.
Discovery quietly finding nothing usable is the normal case and stays silent.
Why a rejected transcript is not a false alarm
TVO-PROV-009's different-project case is the one worth understanding, because it looks pedantic and is not. Agent runtimes name their per-project directories from the working-directory path, and the encoding is lossy — several genuinely different paths collapse onto the same name. Attaching the wrong project's transcript would record another team's session as this commit's provenance, and nobody notices provenance that merely looks plausible. So the transcript's self-reported directory is checked, and a mismatch is refused rather than guessed at.
Refusals when a record is read or exported
TVO-PROV-004 applies to the attested tier only. An observed record has no prompt bind at all, so the check does not exist for it.
Two you should report rather than work around
TVO-PROV-010— an observed, self-reported record was offered where an attested one is required. No configuration makes an observed session attestable; that is precisely the property the two-class design guarantees. It is a producer bug.TVO-PROV-011— a commit carries more than one run record. Also a producer bug.tovio fsckfinds any already-stored commits in this state; a stored conflict resolves toward the attested record, so no reader is ever shown self-reported data labelled as attested.
Backfill refusals
TVO-PROV-012— the change already carries a commit-time record, whose link is covered by the commit's own address. A backfilled link is only asserted, so attaching one would replace a stronger claim with a weaker one without saying so. Read the existing record first.TVO-PROV-013— no signing identity, so the assertion could not be signed. The signature is the feature: an unsigned association records neither who claimed it nor whether it has changed since. Runtovio identity initand retry.TVO-PROV-014— the change touched a protected path, and a backfilled record has no sealed form. Capture at commit time instead, where the record seals to the touched policies' recipients.
And one from the rationale side
TVO-PROV-001 is the same shape as TVO-PROV-003, one object over: a rationale supplied to a resolve is malformed or oversized.
Before you ask for help
The full entry for every code — cause, remediation, and exit code — is in the error catalog in the developer documentation. If you need to share a failure, share the code and the one-line title. Do not paste the transcript, the prompt, the turn content, or repository paths: a capture that failed the secret scan by definition contains something credential-shaped, and a transcript is the last file you want in a support thread.
Never through the portal
If what you have found is a way to make an unattested record read as attested, or to read a sealed record you are not cleared for, that is a security report. Send it privately to security@tovio.dev — never on a public board and never through the feedback portal.