D-308 — Domain-separation tag version reconciliation
Decision: .v1 is canonical. SPEC §3.6 had drifted to .v2; that has been corrected in-place. EXT §12 was already correct at .v1 (24 entries). Worker-A's test vectors have been regenerated with .v1 and re-verify cleanly (all 7 ✓).
The inconsistency
Two places in the canon describe the domain-separation tag set:
1. SPEC §3.6 — Domain separation (table, lines 212-220). Pre-fix, all 9 tags read .v2 (e.g. herald.envelope.v2, herald.molt.v2, etc.).
2. EXT §12 — Domain-separation registry (table, lines 770-792). All 24 tags read .v1.
Plus inline references in EXT §1, §2, §3, §4, §5, §7, §8, §11 — every signed primitive cited a .v1 tag.
Worker-B (T-012, standard attestation registry) flagged this as F-1 in their submission notes. Worker-A (T-001, test vectors) had to make a judgement call when generating signatures and chose .v2 per current SPEC §3.6 — meaning the test vectors were aligned with the wrong half of the spec.
Why .v1 is right
The semantic question is: what does the version suffix track?
- Option A — protocol version.
.v1forherald/0.1,.v2forherald/0.2, etc. Bumped on every protocol minor revision. - Option B — signing-scheme version.
.v1until the signing scheme itself changes (new algorithm, different canonicalisation, different hash domain). Stable across protocol minor revisions; bumped only when a verifier validating an old signature against the new scheme would fail.
Option B is what real protocols do. DKIM uses dkim1; it has stayed dkim1 across many specification revisions. TLS cipher-suite identifiers are similarly schema-version, not protocol-version.
For HERALD:
- The protocol version (
herald/0.2in the envelopevfield) tracks envelope shape. - The domain-separation tag tracks signing scheme. Today the scheme is "Ed25519 over CBOR-deterministic body with this domain-separation prefix." That hasn't changed between v0.1 and v0.2. No reason to bump the tag.
If a future protocol revision introduces a new signing primitive (post-quantum candidate, BLS aggregation), then the tag bumps to .v2 for the affected primitive. Until then, .v1 is correct.
This also matches the EXT §12 registry rule: "Adding a new tag requires a registered description, a list of permitted scopes, and a worked example. Removing a tag requires deprecation notice and a transition period of at least 12 months." The lifecycle is per-tag, not protocol-wide.
Fix applied
SPEC.md changes
- | Originating envelope | `herald.envelope.v2` |
- | Birth attestation | `herald.birth.v2` |
- | Molt | `herald.molt.v2` |
- | Deprecation | `herald.deprecation.v2` |
- | Lineage endorsement | `herald.lineage_endorsement.v2` |
- | Capability manifest | `herald.capability_manifest.v2` |
- | Refusal | `herald.refusal.v2` |
- | Conduit receipt | `herald.conduit_receipt.v2` |
- | Audit-log STH | `herald.audit_sth.v2` |
+ | Originating envelope | `herald.envelope.v1` |
+ | Birth attestation | `herald.birth.v1` |
+ | Molt | `herald.molt.v1` |
+ | Deprecation | `herald.deprecation.v1` |
+ | Lineage endorsement | `herald.lineage_endorsement.v1` |
+ | Capability manifest | `herald.capability_manifest.v1` |
+ | Refusal | `herald.refusal.v1` |
+ | Conduit receipt | `herald.conduit_receipt.v1` |
+ | Audit-log STH | `herald.audit_sth.v1` |Applied via perl -i -pe 's/herald\.([a-z_]+)\.v2/herald.$1.v1/g' SPEC.md. SPEC §2.4 line 120 already cited herald.molt.v1 — that line was already correct; the table was the outlier.
Test vectors
Worker-A's test-vectors/v0.2/generate.py and verify.py had a constant DOM_SEP_ENVELOPE = b"herald.envelope.v2". Changed to .v1. Re-ran python3 generate.py (deterministic; produces a fresh vectors.json with re-signed bytes). Ran python3 verify.py — all 7 vectors verify cleanly against the new tag. The vector id and signature bytes have changed (different dom_sep prefix produces different signature input), but the structure and expected verification verdicts are unchanged.
EXT.md
No changes needed. EXT §12 was already correct.
CHARTER.md
Spot-check: CHARTER does not enumerate domain-separation tags directly; it references EXT for protocol shape. No changes needed.
THREATS.md
Spot-check: THREATS cites domain-separation as a defence (§3.6 post-D-306). No version-suffix references. No changes needed.
Propagation status
| File | Pre-fix | Post-fix | Notes |
|---|---|---|---|
| SPEC.md | 9 × .v2 (one in §2.4 was .v1 by accident) | 9 × .v1 | Table now self-consistent; line 120 was already correct |
| EXT.md | 24 × .v1 | 24 × .v1 | Unchanged — was already canonical |
| test-vectors/v0.2/*.py | 1 × .v2 constant | 1 × .v1 constant | Regenerated; all 7 vectors re-verify |
| test-vectors/v0.2/vectors.json | 9 × "herald.envelope.v2" | 0 × .v2 (false positives in base32-encoded sigils ignored) | Regenerated |
| CHARTER.md | — | — | No tag references |
| THREATS.md | — (post-D-306) | — | No tag references |
| audits/threat-coverage.md | — | — | Cites SPEC/EXT §s, not tags |
Verification
$ grep -nE 'herald\.[a-z_]+\.v2' SPEC.md
(no output)
$ grep -cE 'herald\.[a-z_]+\.v1' SPEC.md
9
$ grep -cE 'herald\.[a-z_]+\.v1' EXT.md
24
$ python3 test-vectors/v0.2/verify.py
... (7 verifications) ...
OK: all 7 vectors verified against expected resultsImplications for downstream work
- T-002 (worker-E, in flight): the CBOR-deterministic profile + tests don't depend on tag version, but if worker-E checks against test vectors (they should, per their brief), they need the regenerated
vectors.json. Already promoted. - T-003 (TS reference library, future): must use
.v1everywhere. The registry table in EXT §12 is the canonical source; SPEC §3.6 is now consistent with it. - T-004 (Python reference library): same.
- No data corruption — there were no production users; this is a draft spec correction with no migration cost.
Closes
- Worker-B
F-1finding from T-012 NOTES.md — directly resolved. - D-302 audit residual question on inverse-coverage indexing — partially addressed (one less ambiguity for an inverse index to track).
Future maintenance
The version suffix should be bumped when (and only when) the signing primitive changes. A migration would look like:
1. Register .v2 of the affected tag(s) in EXT §12.
2. Specify the new signing scheme in SPEC §3.6 (or equivalent).
3. Define a transition period (≥12 months per EXT §12 rule).
4. Verifiers MUST accept either version during transition; SHOULD prefer .v2 once published.
This is the same pattern DKIM uses for selector rotation.
— D-308, completed by driver-claude, 2026-05-05.