AI Initiative logoAI Initiative
Reading room / Manthan

Audit D-318 — Cultural and reserved-sigil conformance vectors regenerated

Audit D-318 — Cultural and reserved-sigil conformance vectors regenerated. Covers Result; Why regeneration was necessary; What changed (file-level summary); `domain_separation_tag_origin` field.

Historical audit / evidence record
This is the retained source text, not a new validation of its claims. Numerical results and comparative claims require the accompanying source review before public reuse.

Read the connected case study or article →

worker-glossary-par-17 · 2026-05-05

Provenance, authorship and editorial notes

Audit D-318 — Cultural and reserved-sigil conformance vectors regenerated

Id

manthan-herald-protocol-audits-conformance-vectors-regen

Project

Manthan

Source path

manthan/herald-protocol/audits/conformance-vectors-regen.md

Source sha256

876850e36f3f1e59ec1eb6e226602c680100a7d3e2cef5ca95f14c5803110e6a

Local copy sha256

876850e36f3f1e59ec1eb6e226602c680100a7d3e2cef5ca95f14c5803110e6a

Repo head

3a94084024a3434cef331fecac91c2c3b43f0313

Date

2026-05-05

Date basis

Explicit document metadata

Author

worker-glossary-par-17

Author basis

Worker

Last source commit

8b75d1b0157c20a0a463f0e31008ef9f73099beb

Last source commit date

2026-06-08T07:40:14Z

Document status

Historical audit / evidence record

Summary

Audit D-318 — Cultural and reserved-sigil conformance vectors regenerated. Covers Result; Why regeneration was necessary; What changed (file-level summary); `domain_separation_tag_origin` field.

Topics
  • Adversarial review and case studies
  • Result
  • Why regeneration was necessary
  • What changed (file-level summary)
Theme

Adversarial review and case studies

Priority

reference

Related ids
  • manthan-herald-protocol-audits-manthan-cohort1-postmortem
Evidence concerns
  • Recovered source text is preserved verbatim. Assertions, comparisons, commands and results belong to its original context; they were not re-executed or externally re-verified during this corpus review.
  • Historical record: current deployment, task completion and test status must not be inferred from this date-bound document.
Word count

1590

Bytes

14543

Source relative

herald-protocol/audits/conformance-vectors-regen.md

Remote mirror

manthan/herald-protocol/audits/conformance-vectors-regen.md

Full text preserved

True

Audit D-318 — Cultural and reserved-sigil conformance vectors regenerated

Worker: worker-glossary-par-17
Date: 2026-05-05
Closes: D-317 follow-on (audits/t001-t003-applied.md "Patches NOT applied" §3).


Result

Regenerated against the post-D-317 reference library (lib/herald-core-ts/src/):

FileVector countConformance categoryResult against post-D-317 lib
tests/conformance/cultural/vectors/cultural-vectors.json14cultural-attestation14 pass / 0 fail
tests/conformance/reserved-sigils/vectors/reserved-sigil-vectors.json8reserved-sigil8 pass / 0 fail

Total: 22/22 pass. (The brief said "9 entries" for reserved-sigils;
the actual T-026 SPECS array has always defined 8 — see Notes §1.)

The regenerated JSONs live in this sandbox at:

The reviewer copies them in-place during promotion (sandbox discipline:
no edits outside manthan/state/findings/D-318/).


Why regeneration was necessary

D-316 / D-317 changed two things in the reference library:

1. Origin domain-separation tag. ORIGIN_DOMAIN was renamed from
"herald.sig.origin.v1" to "herald.envelope.v1"
(lib/herald-core-ts/src/envelope.ts:6 and
lib/herald-core-ts/src/sign.ts:10). The old string is now a
documentation-only synonym and MUST NOT appear on the wire.
2. Opaque-value encoding (SPEC §3.5a, added by D-316). The fields
id, parent, trace, nonce are now CBOR byte strings
(major type 2) when canonically encoded; the previous
implementation encoded them as CBOR text strings of their hex
representation. The conversion lives in bodyForSigning() at
lib/herald-core-ts/src/envelope.ts:182-190.

Both changes alter the bytes that get signed. A naive substitution
of the domain_separation_tag_origin field in the JSON would leave
the cached signature_hex and id_hex stale (because the old
signatures cover the old bytes). The conformance verifier would
either:

tampered (the cultural case — id derives from canonical body, so
every byte change reshuffles the hash); or

domain tag and fail with signature-invalid.

The pre-D-318 vectors fail the conformance categories under the
current library — confirmed before regeneration:

$ node --experimental-strip-types scripts/run-conformance-on-old.ts
[cultural-OLD]      0 pass / 14 fail / 14 total
[reserved-sigils-OLD]  7 pass /  1 fail /  8 total

(7/8 of reserved-sigils only "pass" by short-circuit — the policy
check fires before wire-verification, so they never exercise the
broken signature. The single wire-valid vector
role-recipient-none-valid fails as tampered.)

After regeneration, all 22 pass cleanly.


What changed (file-level summary)

domain_separation_tag_origin field

FileOLD count of herald.sig.origin.v1NEW count of herald.sig.origin.v1NEW count of herald.envelope.v1
cultural-vectors.json15015
reserved-sigil-vectors.json909

Each per-vector entry in the JSON also embeds the domain tag in a
domain_separation_tag field; that's the source of the per-vector
+1 count above the file-level header. All references swept.

Signature and id changes (sample: cultural / mood-valid-precise)

OLD id_hex:        4bb408c30d6118336af1e4f3ae35eb78b5a523874f4c7dc174e8626a83da1d3f
NEW id_hex:        65567c1da28b30d3ff1badaa1f8b86e74edbf5b0c7ee6aeda86e73750891f60d

OLD signature_hex: 1ffba9e4a03b38107b687a97114563efe89bc6b0764c7f45f039e46ef3763813
                   dd574ac101fb3ca9b63758a82a5172a184558ce53c60296dcd366298d6f4a808
NEW signature_hex: 0f0bb0a6fdbc843d55add82d76189e5d77f981854523534f98a5e8bf010fcfc5
                   70f7d47552a962d1753f59cc262c09cd86ffc75ee9c5e1ce25650c54cca64e0d

Every single signature and every single id in both files differs from
the pre-D-318 file. That is correct: under SPEC §3.5a the nonce
field alone moves from a 32-byte ASCII-hex CBOR text-string to a
16-byte CBOR byte-string, which changes the signed canonical body
even before the new domain tag is mixed in.

CBOR canonical-body shape (sample: cultural / mood-valid-precise)

The first divergence between OLD and NEW canonical bodies is at
byte offset 67, immediately after the field name nonce (CBOR
text string 656e6f6e6365):

OLD: ... 6e 6f 6e 63 65 | 78 20 [32 hex ASCII bytes of the nonce]
NEW: ... 6e 6f 6e 63 65 | 50 [16 raw bytes of the nonce]

78 20 = CBOR text-string major-type-3 with 32-byte length. 50 =
CBOR byte-string major-type-2 with 16-byte length (0x40 | 0x10).
This is exactly the encoding rule SPEC §3.5a (added by D-316) now
mandates. The OLD canonical body is 201 bytes; the NEW is 184 bytes
(saving 17 bytes per vector — the 32 ASCII characters + length-prefix
overhead reduce to 16 raw bytes + 1-byte tag).

For parent: null genesis vectors the parent and trace fields
hit the parent === null short-circuit in bodyForSigning, so the
hex→bytes conversion only fires for nonce here. (id is excluded
from canonical-body hashing per bodyForHash.) Reply / lineage
vectors would also see parent and trace reshape, but the
T-024 / T-026 corpora are all genesis envelopes.


Generators and regeneration procedure

Original generators (kept in their T-024 / T-026 sandboxes):

Both import from ../../../../../T-003/src/index.ts — the pre-D-316
reference library. The single change required to retarget them at the
post-D-317 library was the import path:

- } from "../../../../../T-003/src/index.ts";
+ } from "../../../../../lib/herald-core-ts/src/index.ts";

Updated generators in this sandbox:

All SPECS arrays, deterministic seeds (alpha = 0x01\32),
nonce derivations (sha256("herald.t02{4,6}...nonce.<vector-name>")[0:16]),
and timestamps (BASE_TS = 1746518400 cultural, 1746604800
reserved-sigil) are preserved verbatim. The signature change is
entirely* a consequence of swapping the library, not of any spec
change.

To regenerate from this sandbox:

cd learning/herald-protocol/manthan/state/findings/D-318/scripts
node --experimental-strip-types build-cultural-vectors.ts
node --experimental-strip-types build-reserved-sigil-vectors.ts

Output lands in vectors/{cultural,reserved-sigil}-vectors.json
under the D-318 sandbox.


Verification protocol

scripts/verify-vectors.ts — wire-layer only: reconstructs each
expected: valid vector and runs verifyEnvelope from
lib/herald-core-ts/src/envelope.ts. 9 cultural + 1 reserved-sigil
wire-valid vectors all pass.

scripts/run-conformance-categories.ts — full conformance: imports
sandbox copies of cultural-category.ts and
reserved-sigil-category.ts (with their stale
../../../../../T-017/src/... imports rewritten to
../../../../../../tests/conformance/src/..., since the runner has
been promoted but those category files still hold the old paths —
flagged separately, see Notes §2). Drives the actual category
dispatcher over the regenerated JSONs:

=== cultural ===
  PASS  mood-valid-precise           expected=valid          observed=valid
  PASS  mood-shape-invalid           expected=shape-invalid  observed=shape-invalid
  PASS  flinch-valid                 expected=valid          observed=valid
  PASS  flinch-shape-invalid         expected=shape-invalid  observed=shape-invalid
  PASS  tilt-valid                   expected=valid          observed=valid
  PASS  tilt-out-of-range            expected=shape-invalid  observed=shape-invalid
  PASS  weariness-valid              expected=valid          observed=valid
  PASS  weariness-negative           expected=shape-invalid  observed=shape-invalid
  PASS  dread-valid                  expected=valid          observed=valid
  PASS  aphasia-valid                expected=valid          observed=valid
  PASS  vibe-freeform                expected=valid          observed=valid
  PASS  haiku-three-lines            expected=valid          observed=valid
  PASS  haiku-not-three              expected=shape-invalid  observed=shape-invalid
  PASS  mixed-multiple-attestations  expected=valid          observed=valid
[cultural] 14 pass / 0 fail / 14 total

=== reserved-sigils ===
  PASS  role-recipient-none-valid              expected=valid                          observed=valid
  PASS  role-sender-crier-rejected             expected=reserved-sigil-sender          observed=reserved-sigil-sender
  PASS  role-signature-by-scribe-rejected      expected=reserved-sigil-signer          observed=reserved-sigil-signer
  PASS  example-recipient-production-rejected  expected=reserved-sigil-production      observed=reserved-sigil-production
  PASS  test-sender-production-rejected        expected=reserved-sigil-production      observed=reserved-sigil-production
  PASS  future-reserved-recipient-unknown      expected=unknown-sigil                  observed=unknown-sigil
  PASS  lineage-parent-none-rejected           expected=reserved-sigil-lineage-parent  observed=reserved-sigil-lineage-parent
  PASS  claim-sigil-dreamer-rejected           expected=reserved-sigil-claim           observed=reserved-sigil-claim
[reserved-sigils] 8 pass / 0 fail / 8 total

FINAL: 22/22 conformance vectors pass under the post-D-317 library.

scripts/run-conformance-on-old.ts — same harness but pointed at
the un-regenerated files in tests/conformance/.../vectors/. Used
to demonstrate the old vectors fail (results above in §"Why
regeneration was necessary").


Cross-references (signature-derivation sites)

FileLine(s)Purpose
lib/herald-core-ts/src/envelope.ts6ORIGIN_DOMAIN = "herald.envelope.v1"
lib/herald-core-ts/src/envelope.ts106buildEnvelope signs via signingBytes(...)
lib/herald-core-ts/src/envelope.ts165-167signingBytes = `domain_tagcanonicalBody`
lib/herald-core-ts/src/envelope.ts182-190bodyForSigning hex→bytes conversion (the SPEC §3.5a fix)
lib/herald-core-ts/src/sign.ts4-22DOMAIN_TAGS.origin = "herald.envelope.v1"
lib/herald-core-ts/src/sign.ts37-39signWithDomainTag (lower-level signing primitive)
manthan/state/findings/D-318/scripts/build-cultural-vectors.ts35-42regen import (post-D-317 lib)
manthan/state/findings/D-318/scripts/build-cultural-vectors.ts67-77buildEnvelope(...) call → signature derivation
manthan/state/findings/D-318/scripts/build-reserved-sigil-vectors.ts18-25regen import (post-D-317 lib)
manthan/state/findings/D-318/scripts/build-reserved-sigil-vectors.ts44-58buildEnvelope(...) call → signature derivation
SPEC.md§3.5aopaque-value encoding rule (added by D-316)
SPEC.md§3.6origin domain tag table
EXT.md§6.3origin scope mapping
EXT.md§12domain-separation registry

What I did NOT do

live under manthan/state/findings/D-318/vectors/, not in
tests/conformance/.../vectors/. The reviewer promotes them in
place.

sandbox and changed only the library import path. The originals at
manthan/state/findings/T-{024,026}/tests/conformance/... are
untouched.

tests/conformance/{cultural,reserved-sigils}/src/.ts.* Those
files still import from a non-existent
../../../../../T-017/src/... location (they were written before
T-017 was promoted to tests/conformance/). The regen task does
not require fixing them — only the JSON files. Flagged as a
follow-on, see Notes §2.

D-316 / D-317.

(build-vectors.ts); there is no parallel Python generator for
these conformance categories. The Python lib at
lib/herald-core-py/ was already updated by D-317.


Cross-implementation interop check

Not run for these two files. The cultural and reserved-sigil
generators only exist in TypeScript; the cross-language interop
fixture lives in lib/herald-core-py/tests/test_envelope.py and
uses the T-001 envelope-core vectors only. Adding cross-language
interop for cultural / reserved-sigil corpora is a separate
follow-on (would require a Python build_vectors.py mirror of
T-024 and T-026).


Follow-ons noted

1. *Fix stale T-017 import paths in
tests/conformance/{cultural,reserved-sigils}/src/
.ts.* Six
files import from ../../../../../T-017/src/..., which doesn't
exist post-promotion of T-017. The cultural and reserved-sigil
conformance categories therefore can't actually be invoked from
the deployed location — they only run via the sandbox shim built
here. This is independent of D-318 (the JSONs
can* be promoted
even if the test runner is broken; the JSONs would then be
exercised once those imports are fixed).

2. *Add a top-level npm task that runs the cultural and
reserved-sigil conformance categories
* alongside envelope-core.
Today only tests/conformance/test/runner.test.ts is in the
default npm test for the conformance package; the per-category
tests in tests/conformance/{cultural,reserved-sigils}/test/
have separate package.json files but aren't aggregated.

3. *Document the regen procedure in
tests/conformance/cultural/README.md and
tests/conformance/reserved-sigils/README.md.
Currently the
READMEs reference the T-024/T-026 generator paths, which still
work but produce
pre-D-316* signatures. Should at minimum point
readers at the post-D-317 procedure (or, better, move the
generators into tests/conformance/.../src/build-vectors.ts
with corrected imports — same pattern as the T-017 promotion).

Continue exploring