Standards-track rules
These five are not style preferences. Each one exists because breaking it destroys a property the project is built on.
1. Frozen release directories are immutable
standards/ver/1.0.0/ and standards/ver/1.0.1/ are published, frozen artifact sets. Never modify, replace or delete anything under them — not to fix a typo, not to correct a digest, not to fix a defect you have proven is real. 1.0.0 is frozen with its defects, catalogued in `docs/standards/VER-1.0-errata.md`.
spec/ and lexicons/ are the published historical locations of the 1.0.0 artifacts and stay exactly where they are: the freeze copies, it never moves, because running code and published prose reference those paths.
A correction ships as a new release directory, under the publication checklist in `VERSIONING.md` §3.3 — the commit, the annotated ver/<release> tag, the recorded digests, the example validating against its own schema. From 1.1 onward a release must also clear the six-condition publication bar in §3.4. Publishing is a checklist, not a habit.
Corollary: a normative change is only ever made in a new release directory or in the current draft (standards/ver/1.1-draft/, unratified — do not implement against it for production). Editing prose in place to mean something new is the one thing this project cannot do.
2. The error-code registry is append-only
VERxxx conformance codes are a stable public registry (ADR-0003). Never renumber a code. Never reuse a retired number. Never change what an existing code means. A tool, a fixture or a downstream policy file may be pinning any of them.
Adding a code is fine: take the next free number in the right stage band, add it to the registry, add its fixture (rule 3), and update the counts in packages/ver-validator/README.md and conformance/README.md. Retiring one means marking it retired, not freeing the number.
Changing a code's severity is a compatibility event, not an edit: it changes the standards result for records already in circulation. It goes in `COMPATIBILITY.md` with the rest.
3. Conformance fixtures: one per code, real digests, manifest-first
The corpus in conformance/ is executable, not illustrative. Its full contract is `conformance/README.md`; the parts that get missed:
- Exactly one fixture per active code, or an explicit
coverage_exemptionsentry saying why it cannot have one. A code with neither, or two fixtures claiming the same code, is a corpus defect andtests/test_conformance_fixtures.pywill say so. - One seeded defect per fixture, in an otherwise complete and self-consistent record. A fixture wrong in two ways cannot tell you which rule fired.
expect_codesis an exact set, not a floor. Where a defect provably drags another code with it, list both and explain the coupling innotes.- Every digest, length and byte string is computed, never invented. No hand-typed hex. Where the true input is not carried by the record, the value is a real digest of a documented preimage (
sha256("ver-conformance-corpus/1.0.1 <purpose>"); 1.1-draft fixtures use thever-conformance-corpus/1.1-draftprefix), which anyone can recompute. Per annex E26 those stand in for measured values and MUST NOT be cited as interoperability evidence. manifest.jsonis the contract. A fixture that is not in the manifest is not in the corpus. Name the file after its code, and re-run the corpus after any edit — editing a signed fixture invalidates its signature.
4. Decisions go in an ADR
Anything that constrains the standard's future — a field's meaning, a requirement level, a versioning rule, a validator's strictness — is decided in `docs/adr/` before it is implemented, as ADR-NNNN-kebab-slug.md with the existing sections: Status, Context, Options (with the ones rejected, and why), Decision, Consequences.
Status is Proposed, Accepted, Rejected or Superseded by ADR-NNNN, with the date and — where one exists — a pointer to where the decision is implemented. An acceptance may be qualified, and the qualification belongs in the status line rather than buried in the prose: the existing ADRs carry Accepted — conditionally (conditions enumerated and tracked), Accepted — principle adopted, construction revised, and similar. An accepted ADR is not edited into a different decision later; it is superseded by a new one.
Do not resolve an open ADR by implementation. Shipping code that assumes an answer is how a decision gets made without being decided.
5. The ledger records everything
Every finding — patched, deferred, or knowingly left alone — is a row in `docs/standards/VER-1.0-errata.md` with a disposition. documented — not patched is a legitimate outcome; an undocumented absence is not. Record-affecting changes also get a row in `COMPATIBILITY.md`, and shipped changes go in `CHANGELOG.md`.
Before changing anything under standards/, packages/ver-validator/ or conformance/, read the errata ledger and COMPATIBILITY.md first. Most surprising-looking behaviour there is deliberate and already has a row.
