Skip to content

feat(primitives): bring the anchor builder to byte parity with the reference implementation, including the no-identifier fallback envelope (P05b) - #41

Merged
kamescg merged 7 commits into
update/v1.1.0-alphafrom
codex/p05b-anchor-builder-parity
Oct 20, 2026
Merged

kamescg merged 7 commits into
update/v1.1.0-alphafrom
codex/p05b-anchor-builder-parity

Conversation

@jonathanprozzi

@jonathanprozzi jonathanprozzi commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

Important

@kamescg — review ready. Stacked on #39 (codex/p16d-classifications-parity); review after #39 and retarget as #39 and #36 land.

To ratify here: the no-identifier fallback envelope. The reference builds a validated P1 envelope with no identifier when no rung fires, the ladder is null, or a canonical URL exceeds 220 characters; the train used to refuse it. The anchor result's iid, scheme and class are therefore nullable and consumers must narrow.

Coordination: this PR and #40 both touch packages/primitives/src/types.ts (whichever lands second takes IdentityClass | null). One harness line changed: encode proofs register identified anchors only.

Receipt: byte parity on all 52 agreeing anchor vectors; 19 ledger entries retired (anchor proof now 52 agreements / 6 divergences / 23 OPEN); harness 1027 pass / 0 fail.

Child PR of the v1.1.0-alpha umbrella (#15). Part of the parity series: each PR in the series makes a train package behave exactly as the reference implementation's in-tree copy does today, so the published packages can replace those copies without a behaviour change.

Current (train)

@0xintuition/primitives built identity anchors whose bytes differed from the reference's for the same input in several families: raw evidence was normalized before hashing, derived recipe values (geohash, year, hashed text) were not materialized under the recipe key, sameAs was dropped from identity envelopes or kept unsorted, descriptive fields leaked into scheme envelopes, and a classification with no identifier at all was refused where the reference builds a P1 fallback envelope. The conformance harness recorded 26 anchor divergences for these.

Need

Byte parity of every anchor vector with the reference builder, the no-identifier fallback envelope as the reference builds it, and the conformance ledger moved to match.

Reconciliation

src/anchor.ts and src/types.ts:

  • Headers: declared classification context and type, then the canonical identifier; no context override table.
  • Raw evidence preserved before NORM-1 (punctuation and padding kept); finite numeric scalars stringified as the reference does.
  • Recipe order: direct-only recipes keep sorted keys; recipes with transforms keep declaration order.
  • Derived values materialized under the recipe key: geohash at the declared precision, the four-digit year from a date, keccak16 of the NORM-1 text.
  • sameAs as the last identity field: strings verbatim, exact-deduplicated, default-sorted, omitted when empty or not an array.
  • Inclusion: scheme envelopes omit descriptive fields; gen1 envelopes include only the producing rung's evidence; the identity path skips whole-map validation.
  • Account floor: the weak platform:@handle form emits P1, the strong form keeps P0 (consistent with feat(iid, iid-spec): floor weak account handles below anchor eligibility, with the spec amendment and conformance rule (P16g) #35).
  • Fallback: no firing rung, a null ladder, or a canonical int:url: value over 220 characters produces a validated P1 envelope without identifier; iid, scheme and class are null on that result, so consumers that assume every successful anchor carries an IID must narrow. Unknown, missing or invalid fields still fail.
  • Serialization: compact JSON in insertion order, UTF-8 hex, the atom id over the exact bytes.
  • Conformance harness: support/proofs.ts registers encode proofs for identified anchors only, since a no-identifier envelope has no URI to encode (the encode inventory pinned in the manifest is unchanged).
  • Conformance ledger: 19 anchor entries retired because both sides now agree (17 builder defects and the two fallback-envelope rulings); the six "reference adopts the train's builder" entries stay, with their fingerprints intact. README enumeration: anchor proof 52 agreements / 6 divergences / 23 OPEN (was 33 / 25 / 23).

Parity

Matches the reference implementation's anchor builder byte for byte on all 52 agreeing vectors (src/__tests__/anchor-parity.test.ts pins every one: JSON, hex, atom id, IID or null, profile). The six remaining anchor divergences are the cases where the reference is expected to adopt the train's field order; they are documented in the ledger, not changed here. The primitives README now describes the reproducible canonicalization and hashing; the IID spec should carry that as a section in a later cut.

Held out

Evidence

Review notes

Base codex/p16d-classifications-parity (#39), which sits on fix/pr15-integration-gates (#36); retarget as those land. Read the ledger diff first (19 retirements), then src/anchor.ts top to bottom, then the parity test. The one judgement call is the fallback envelope (the reference builds it; the train used to refuse it); it is in effect by default and open to ratification here.

… to parity with the reference implementation (P16d)

Application code imports helpers and data from the classifications
package that the train lacked, and the train's spec data had drifted from
the reference since August. This ports all of it onto the train's
declarative spec shape.

- Helpers: getClassificationLabel, getClassificationByType,
  getClassificationByReference (plus the reference resolver tiers),
  deriveClassificationIdentifier, buildClassificationSearchText,
  visibility presets incl. PRIMARY_ITEM_CATALOGUE_PRESET, native atom
  types, identity field aliases, DISCOVER_ACTIVITY_GROUPS; all exported
  from the package root.
- Spec shape: optional typed commonName and atomCategory fields (the
  reference's label and engine category); every spec populates
  atomCategory. schema, metadataPredicates, inline identity and the
  creation-profile shape stay canonical.
- Identity data: every rung order, wdSlug, recipe and identifies value
  audited against the reference for all 37 classifications; podcast GUID
  derived through normalizePodcastFeedUrl; person accepts a mononym
  (familyName optional) as the reference does.
- Schema contexts: four specs move to the reference's context values
  (ethereum-account and ethereum-smart-contract to
  https://schemas.intuition.systems/v1, social-media-account and one more
  to the reference value); no spec references schema.intuition.systems
  any more. Creation profiles regenerated through the repo generator.
- Tests: 256 pass, including inline parity oracles for labels, ladders
  and the catalogue (rung tokens, schema type and context per type) built
  from the reference data at authoring time; all 67 reference test cases
  present.

Six ladders still carry slugless wd rungs (brand, local-business,
location, event, thing, music-group); the ladder already refuses bare wd
minting unless the plain-wd policy allows it, matching the reference.
…ta (P16d)

The classification parity port changed data the primitives tests pinned:
the Ethereum classifications' JSON-LD context is now the reference value,
a person accepts a mononym (familyName optional, givenName required), and
the movie ladder carries an active typed wd binding so it no longer
serves as the polymorphic bare-P0 example (brand does). Eight
expectations updated; 140 tests pass.
…interpreter so every entry point derives one GUID (P16d fix round)
…lassification data resolves (P16d ledger round)
…ference, including the no-identifier fallback envelope (P05b)
…, now that the builder returns no-identifier envelopes (P05b)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants