What a published annotation row contains¶
One product ships: scene_report.declared.v1, produced by the reference
annotator. A run names its annotator by import path, so any domain can ship its
own; this page describes the row shape they all publish into.
Two halves, produced separately¶
A row’s values carries exactly two keys, and they come from different places.
key |
written by |
verified |
|---|---|---|
|
the provider, verbatim |
no |
|
|
exact by construction |
The provider is asked for prose and returns prose. Every value under claims is
projected from the evidence this process already holds, in this process, before
any request goes out — so no number on that side was ever authored by a model,
and none can be. Nothing joins the two: no citation links a sentence to a claim.
For the reference annotator, output is {"expert_summary": [string, ...]} and
claims is a SceneClaimsV1: scene quantities, receiver acquisition
settings, a signals list, an optional interactions list, and the names of
anything the evidence could not resolve.
The prose is not checked¶
No automated check asserts that the prose reflects the claims beside it, and none is planned. There is no reliable way to check a text description: a model can restate a value in a different unit, name a different quantity, invert a relation, or invent a property, and nothing mechanical over the text sees any of it. A caption may therefore contradict the claims in its own row.
Every row says so, in provenance.prose_verification, which is always
not_performed. Failed rows carry it too, so a reader never has to infer
verification status from an absence.
What this buys is that the machine-readable half is exact for every row however badly the prose reads, and that a contradiction, when it happens, sits in the open next to the truth rather than alone in a corpus. Verification of prose, where it is wanted, is ad hoc analysis with a stronger model, outside this pipeline — and it is cheap, because the judge needs only the row.
What is rejected¶
A reply that is not valid JSON, or that does not match the response schema the annotator itself declared, fails that record’s row. Core holds no table of reply shapes: the only authority on a reply is the annotator that asked for it.
A record whose annotator raises RecordNotAnnotatable publishes SKIPPED and
is never sent to a provider — a quiet epoch is a fact about the corpus, not an
outage. Any other preparation failure publishes FAILED. The set stays dense
either way.
Naming¶
A product is <annotation_type>.<variant>.v<N>. Core checks that shape and
nothing else: it holds no closed list of annotation types, so a sensing domain
producing an occupancy_report names its own output without editing anything
shared. The vN is the contract — the evidence consumed and the reply asked
for. Prompt wording carries its own revision, declared in the Markdown file’s
front matter and on the class that claims it.
annotation_type is derived from template_id and is not authored separately.
Versioning and provenance¶
An annotation set is identified by (annotation_set, publication_id) and is
published atomically. A new run appends an overlay and never rewrites generation
bytes; publishing different content under an existing publication id collides
rather than overwriting.
Each row records the annotator’s identity, import path, origin and installed
distribution; the prompt id and revision; the backend, provider and resolved
model id; token usage; the evidence model that produced it; the projection the
run configured; and prose_verification.
The projection fields are named configured_* deliberately. Core hands
build_evidence the record itself, so whether those settings bounded the
request is the annotator’s doing and not something core can attest to.
Hosted model text is intentionally not expected to be byte-identical across calls.