Conformance-profile strictness and error-code registry stability
Status
Accepted — 23 August 2026. Implemented in `packages/ver-validator/`, profile identifier vera-profile/1.0.
Context
Appendix D #4 records that the VER 1.0 schema performs no semantic validation. The audit confirmed it empirically: against the published schema, every one of the following passes:
- an embedding whose
space_idnames no entry inspaces[]; - a
canonical_visualembedding in akind: "text"space; - an inline vector of length 3 declared against a 768-dimension space;
embedding.dim: 1against a 768-dimension descriptor;- two
spaces[]entries sharing onespace_idwith differentweights_sha256; - an
L1Record withraw: []and every availability stateunknown; - a
stripped_suspectedfamily with noavailability_basis; availability.c2pa: "present"alongsidec2pa.status: "missing".
None of these is expressible in JSON Schema 2020-12 without contortion, and several are not expressible at all — cross-object referential integrity, digest verification over base64 payloads, chronology across an array.
Two further problems are structural rather than expressive. JSON Schema 2020-12 demotes format and contentEncoding to annotations: a default validator does not assert them, so every date-time, uuid, uri, and base64 payload in the schema is unchecked (SCH-01, SCH-02). And conformance_level is optional (SCH-21), so a Record can be structurally valid while declaring no level for anything to be validated against.
So a separate conformance profile is needed. Building one raises two questions that must be answered before the first code is assigned, because both are unfixable afterwards.
Question 1: may the profile be stricter than VER 1.0? Some valuable checks have no normative basis — a warning when a visual space omits its resize policy, a size-policy warning where 1.0 states no limits. Emitting them makes the profile more useful and less honest.
Question 2: are error codes stable? Codes will appear in CI configuration, suppression lists, dashboards, and bug reports. Renumbering one silently changes what somebody's --ignore VER604 means.
Options
On strictness:
(a) Normative only. Every issue traces to a MUST or SHOULD in 1.0 or the 1.0.1 annex. Maximally defensible; loses genuinely useful signal, and pushes users toward ad-hoc private linters that nobody can compare against.
(b) Strict by default, unlabelled. Maximally useful; makes "the validator says my Record is bad" ambiguous between "you violated the standard" and "you violated our house style". Corrodes the profile's authority.
(c) Strict but labelled, with every non-normative rule identified as such and every such rule emitted at warning severity where the standard is silent.
On code stability:
(d) Codes are cosmetic and may be renumbered when stages are reorganised.
(e) Codes are a stable registry: never renumbered, never reused, retired rather than recycled.
Decision
Options (c) and (e).
Strictness. The profile validates against the published schema plus the normative content of the 1.0.1 errata annex, plus a small labelled set of profile rules. Every rule is classified in `docs/standards/VER-1.0-errata.md` §6 as normative, profile strictness, profile policy, or advisory. The rules that exceed VER 1.0 are exactly:
| Code | Rule | Why it exceeds 1.0 |
|---|---|---|
VER103, VER104 | Size caps and size policy | VER 1.0 states no size limits (Appendix D #11). The hard cap is a denial-of-service guard, configurable; the policy warning uses the 1.1 draft's unratified numbers |
VER202 | Asserting format and contentEncoding | 2020-12 makes them annotations; annex E23 requires conformance to assert them, so this is normative-by-annex but strict relative to a stock validator |
VER403 | embedding.space_id must match the descriptor pattern | The schema constrains only the descriptor's copy (SCH-06) |
VER405 | Visual preprocessing must state resize, interpolation, and crop | §6.1 enumerates them; the schema requires none (SCH-11) |
A producer failing only those is schema-conformant, and the report says so. Everything else the profile reports is a VER 1.0 or 1.0.1-annex requirement.
Severity follows the requirement level: a MUST produces error, a SHOULD or an unresolved decision produces warning. VER1002 (redaction without a salted hash) is a warning precisely because ADR-0006 is open — the validator does not get to decide an open question.
Code registry stability. Codes are assigned once and never renumbered or reused. CODES is part of the public API. A retired code stays retired. VER1303 (vector-ref-unverified) is reserved and deliberately never emitted: an unfetchable vector_ref is not a defect of the Record, and a validator that reported one would make network reachability part of conformance.
A code's severity may tighten only at a profile minor version, and only when the underlying requirement has itself become normative.
Public API. validate_record, validate_file, VeraValidationIssue, VeraValidationReport, and CODES. Exit codes: 0 clean, 1 errors, 2 usage. ok means no error-severity issue; warnings never set a non-zero exit.
Explicitly out of scope. Tenancy, privacy, and publication policy are deployment concerns, not conformance concerns: they are properties of who may see a Record, not of whether the Record is well-formed and truthful. The profile does not implement them and does not pretend to. (The VERA Studio review PRD's stage list numbers this "stage 16"; that document is not in this repository, so the scope-out is stated on its own terms here rather than by cross-reference.)
Consequences
Good.
- Appendix D #4 is closed by construction: every listed gap has a code, and
conformance/invalid/carries one fixture per code proving the code fires. - "Conformant" becomes testable rather than self-declared. The reference pipeline stamped
L1unconditionally, including when raw capture had failed (REC-01,IMPL-CONFORMANCE-SELF-DECLARED);VER302andVER303catch that class in any producer. - Stable codes make suppression safe.
--ignore VER404means the same thing in a year. - Labelling keeps the standard and the profile distinguishable. A vendor can reject the four strictness rules and still claim VER 1.0 conformance truthfully.
Bad.
- Two artifacts now define conformance, and they can drift. Mitigated by
conformance/manifest.jsonpinning expected codes per fixture, and by the ledger cross-referencing every code to the annex item or finding it enforces — but drift remains a real maintenance cost. - Warning-severity rules will be ignored.
VER404(a space descriptor with noreference) is the most consequential warning in the set — annex E13 says such a space cannot back a conformance claim — and it will be ignored because it does not fail a build. Raising it to an error would fail almost every Record in existence, including the golden example. - The stability guarantee constrains future refactoring. Stage boundaries can move; code numbers cannot follow them.
VER901already sits alone in a stage whose other checks folded intoVER303, and it stays there.
Neutral.
- The profile can validate 1.0.0 Records against the 1.0.0 schema indefinitely (
--schema 1.0.0). Freezing a release does not retire tooling support for it.
