arborist/docs/tickets/ticket-000070-spatial-anchor-pi-w-object.md
russell@unturf.com cb9b57eb80
#000070: rewrite ticket as directive forward-spec (Joseph6 as worked example)
Per fox 2026-06-01: same treatment as #000071 — replace the
review-archaeology structure with what we SHOULD grow. Ticket goes
from 978 lines (original Anchor6 §§1-8 design log + dav1d-review §0
retrofit) to 498 lines of directive spec. **Joseph6 stays as the
first registered example grammar** per fox's note — concrete enough
that an implementer sees what a WorldDimensionGrammar looks like
end-to-end, not abstract enough to lose its load-bearing role.

What changed in shape:
  Before: §0 dav1d verdict retrofit + §§1-8 archaeology of the
          original Anchor6 spec being reviewed (validate seed source,
          segmentation method, mapper choice — all decisions long
          since made).
  After:  §1-13 forward spec. Goal · Axis split · Hard constraints
          (all phases) · AnchorN primitive · WorldDimensionGrammar ·
          Quantization mappers (with uint256-H₁ + no-SO(3) corrections
          documented inline) · π*_w_object canonicalizer with
          four-identity-hash record · **Joseph6 as worked example** ·
          Phase 1 deliverables (9 items) · Pre-review empirical
          bench preserved as §7 · Phase 2/3 deferred · Open questions
          (3 remaining; 5 closed by bench, 4 by dav1d's review) ·
          Cross-references · Five-step alignment · One-line review
          history at the bottom.

What changed in content: nothing material. The corrected spec from
the prior §0 retrofit IS the body now. The original Anchor6 design
log is no longer inlined — git history preserves it at commit
`862662b` (pre-rewrite tip); readers who want the rejection-by-
rejection detail go to
docs/dav1d-reviews/000070-spatial-anchor-pi-w-object--2026-06-01.txt.

Critical technical corrections preserved inline (not as "what was
fixed", but as the directive answer):
  - §3.1: uint256 for H₁ position (octree depth >8 entropy
    preservation)
  - §3.2: rename `map_rotation_so3` → `map_rotation_euler_ypr` (no
    SO(3) overclaim — quantized Euler is not SO(3) coverage)
  - §4: WorldObjectRecord carries all four identity hashes
    (grammar_hash, axiom_pack_hash, manifest_hash, seed_hash) for
    replayability
  - §5: Joseph6 ships as one example grammar; future grammars
    register through the same mechanism

TICKETS.md index row also rewritten in directive voice.

doc_counts tests still pass.
2026-06-01 07:24:17 -04:00

20 KiB
Raw Blame History

Ticket #000070 — AnchorN + π*_w_object: deterministic world-object canonicalization

Status: open · Phase 1 deliverable scoped · dav1d GO-with-rewrite landed 2026-06-01 (full review at docs/dav1d-reviews/000070-spatial-anchor-pi-w-object--2026-06-01.txt). Opened: 2026-05-31

Goal

Implement the first executable v7-W world-object canonicalization kernel. The kernel takes:

hard_hash_32                  one committed 32-byte SHA-256
spatial_anchor_seed           v7-W manifest-published, dedicated
WorldDimensionGrammar         frozen grammar declaring N + N mappers
world_manifest                privacy class, axiom pack, version pins

and produces:

canonical_world_object_bytes  deterministic byte string
world_object_hash             SHA-256(canonical bytes)
object_record                 grammar_hash + axiom_pack_hash +
                              manifest_hash + seed_hash + per-dim values

A single committed hash deterministically expands into N named regions via the HMAC-SHA-512 KDF already shipped in arborist/substrate/anchor_prg.py (#000035). Each region drives one quantized dimension under a registered mapper. N is grammar-decided, not hard-coded.

Axis split (cross-ref #000071)

#000070  intra-world state instantiation
         AnchorN + WorldDimensionGrammar + AxiomPack + Manifest →
         canonical world-state records

#000071  inter-world treaty grammar
         two chains decide whether commitments cross the gap →
         agreement | translation | embassy | quarantine | no_bridge

Joseph6 (six-dimension Joseph @TrudoJo framework) is the first registered default grammar, not THE substrate ontology. See §5.

Hard constraints

  • A1A3 axioms. Canonical encoding · public quantization for proof-path state · collision-resistant hash. No new axiom.
  • Quantized integer state only. Continuous floats do not enter the proof path (v7-W manifest hard rule, paper §1.2). Mappers emit integers; any continuous-domain math (e.g. Euler rotation) quantizes deterministically before commitment.
  • Hard-hash family stays SHA-256 commit + HMAC-SHA-512 expansion. Soft locality indices (Morton / H3 / S2 / Hilbert / geohash) live outside the proof path per CLAUDE.md soft-hash rule.
  • Domain separation from #000035. A NEW seed spatial_anchor_seed is published in the v7-W manifest beside anchor_prg_seed; #000035 §2.4 "single-purpose — never reuse anchor_prg_seed" is honored without a PHI_PRG_VERSION bump.
  • No new audit_mode token. π*_w_object emits commitments, not warrants. The four-rung ladder (POINTER-LINKED → ANCHOR-WARRANTED → EVIDENCE-WARRANTED → ENTAILMENT-VERIFIED) is not extended.
  • No SQL at Phase 1. A new pi_star/spatial-anchor-object@v1 registry entry folds into canonicalization_version (one of the v9.8 8-dim cache_key dimensions). Persistence to a world_state_cells table is deferred to Phase 3.
  • Privacy fail-closed. Missing privacy.class in the manifest is a HARD reject — no PUBLIC fallback.
  • Grammars must be FROZEN before proof-path use. Axioms MAY select a grammar (LLM may propose candidates), only deterministic validators may accept them. Accepted grammars are canonicalized, hashed, KAT-tested, versioned. grammar_hash binds into every downstream commitment.
  • Topic-named, not version-prefixed (CLAUDE.md naming rule). Lands under arborist/world/ and arborist/pi_star/, not arborist/v7w/ or arborist/spatial/.

1. AnchorN — the substrate primitive

AnchorN is the generic key-derivation primitive. Given a hard hash and a frozen grammar declaring N regions, it expands the hash into N named 32-byte regions via HMAC-SHA-512 counter mode.

@dataclass(frozen=True)
class AnchorN:
    hard_hash: bytes              # 32 bytes (SHA-256 of source)
    seed: bytes                   # spatial_anchor_seed from manifest
    grammar_hash: bytes           # binds region identities to a grammar
    regions: tuple[bytes, ...]    # N × 32 bytes


def split_anchor_n(
    hard_hash: bytes,
    seed: bytes,
    grammar_hash: bytes,
    n: int,
) -> AnchorN:
    """Generic N-region split. Counter-mode HMAC-SHA-512 over the
    triple (hard_hash || seed || grammar_hash || counter_be8) yields
    64-byte blocks; first 32 bytes of each block is the region.

    Same construction as arborist.substrate.anchor_prg._expand;
    the difference is grammar_hash binds into the expansion so the
    same hard_hash under two different grammars yields disjoint
    regions. Without that binding, swapping grammars at proof-path
    time would silently reuse anchor bytes for new semantics.
    """

Lives at arborist/substrate/spatial_anchor.py. Substrate-level (not under arborist/world/) because AnchorN is the generic primitive any future world kernel may consume — v7-W is one consumer, but other consumers may want N-region splits without the v7-W semantics.


2. WorldDimensionGrammar — frozen, hash-pinned, registry-addressable

A grammar declares N and the N region-to-mapper bindings. It is a canonical-bytes-serializable record; its SHA-256 is grammar_hash.

@dataclass(frozen=True)
class WorldDimensionGrammar:
    name: str                     # e.g. "joseph6"
    version: str                  # e.g. "v1"
    n: int                        # number of regions
    region_mappers: tuple[str, ...]   # registered mapper names
    region_names: tuple[str, ...]     # human-readable per-region label
    axiom_pack_ref: str               # "axiom-pack@v1" registry slot


def canonical_grammar_bytes(g: WorldDimensionGrammar) -> bytes:
    """Stable serialization. Field order pinned, integers little-endian."""


def grammar_hash(g: WorldDimensionGrammar) -> bytes:
    return sha256(canonical_grammar_bytes(g))


def validate_grammar(g: WorldDimensionGrammar) -> None:
    """Raise GrammarInvalid if:
      - n != len(region_mappers) != len(region_names)
      - any mapper name isn't in the registry
      - axiom_pack_ref isn't in the registry
      - reserved-name collision (e.g. names starting with '_')
    """

Lives at arborist/world/grammar.py (new file).


3. Quantization mappers

Five registered mappers ship in Phase 1 (Joseph6's full set). Each takes a 32-byte region and returns a quantized integer record.

mapper input output notes
map_octree_position() 32 bytes (level: uint8, cell: uint256) uint256, not uint64 — preserves entropy at any octree depth
map_scale_level() 32 bytes uint16 quantized log-scale, fixed scale-ladder per grammar
map_rotation_euler_ypr() 32 bytes (yaw: uint16, pitch: uint16, roll: uint16) NOT "SO(3)" — quantized Euler triple, no continuous SO(3) coverage claim
map_symbol_table_index() 32 bytes uint64 modulo over a fixed-size symbol palette
map_passthrough_hex() 32 bytes hex_str 64-char hex; preserves the full region byte string for downstream interpretation

All mappers are deterministic and registered by name@version. Adding a mapper = bump canonicalization_version: spatial-anchor-object@v1 → v2.

Lives at arborist/world/pi_star/object.py.

3.1 Critical correction (dav1d §16)

The original Anchor6 spec called map_octree_position() to return uint64. That loses entropy at octree depth > 8. Use uint256: preserves the full 32-byte region. The bench (§7) measured chi² uniformity at L=2,3,4 only; production deployments will go deeper, and uint64 truncation would silently bias cell selection at the bits that get dropped.

3.2 Critical correction (dav1d §17)

The original Anchor6 spec described H₃ as "quantized SO(3) rotation." Do not overclaim. The mapper is a quantized Euler ypr triple. Quantized Euler is not SO(3) coverage — adjacent rotation operations are not metrically adjacent in this quantization. Name the mapper map_rotation_euler_ypr() so consumers don't import SO(3) semantics.


4. π*_w_object — the canonicalizer

def derive_world_object_record(
    hard_hash: bytes,
    seed: bytes,
    grammar: WorldDimensionGrammar,
    manifest: WorldManifest,
) -> WorldObjectRecord:
    """End-to-end:
      1. validate_grammar(grammar)            — fail-closed
      2. validate_manifest(manifest)          — privacy.class HARD-required
      3. anchor = split_anchor_n(...)         — N regions
      4. per region: invoke registered mapper
      5. assemble record with all four hashes
      6. SHA-256(canonical(record)) = world_object_hash
    """

Output record carries the FOUR identity hashes plus per-dimension values:

@dataclass(frozen=True)
class WorldObjectRecord:
    grammar_hash: bytes           # which grammar produced this
    axiom_pack_hash: bytes        # which axiom pack the grammar pins
    manifest_hash: bytes          # which deployment manifest
    seed_hash: bytes              # which spatial_anchor_seed
    dimensions: tuple[Any, ...]   # length N; one per region_mapper
    world_object_hash: bytes      # SHA-256 of the canonical bytes

All four hashes are required for replayability across grammar versions. A consumer presented with a world_object_hash and the four identity hashes can re-derive the record byte-for-byte by loading the named grammar + axiom pack + manifest + seed.

Lives at arborist/world/pi_star/object.py.

A separate registry-facing adapter at arborist/pi_star/spatial_anchor_object.py exposes the canonicalizer as a registered π*:

PI_STAR_NAME = "spatial-anchor-object"
PI_STAR_VERSION = "v1"


def canonicalize(raw: bytes) -> bytes:
    """Registry contract. Parses raw bytes into the (hard_hash,
    seed_ref, grammar_ref, manifest_ref) tuple, dispatches to
    derive_world_object_record, returns the canonical bytes."""

5. Joseph6 — the first registered grammar (example)

Joseph @TrudoJo's six-dimension framework lands as the first canonical grammar. It is an example of what a WorldDimensionGrammar looks like, not THE substrate.

JOSEPH6 = WorldDimensionGrammar(
    name="joseph6",
    version="v1",
    n=6,
    region_names=(
        "position",        # H₁
        "scale",           # H₂
        "rotation",        # H₃
        "material",        # H₄
        "links",           # H₅ — reserved for π*_w_relation sibling
        "behavior",        # H₆
    ),
    region_mappers=(
        "map_octree_position",
        "map_scale_level",
        "map_rotation_euler_ypr",
        "map_symbol_table_index",       # material palette
        "map_passthrough_hex",          # raw links reserved
        "map_symbol_table_index",       # behavior code
    ),
    axiom_pack_ref="axiom-pack-joseph6@v1",
)

Joseph6's grammar_hash is computed at module-load time; KATs (§7) pin it byte-for-byte. Future grammars (Joseph12, Cartesian5, spatial+temporal-7, etc.) register through the same mechanism — none is privileged over Joseph6 except by being chosen at deployment-manifest level.

Why ship Joseph6 in Phase 1:

  • Proves AnchorN can host a non-trivial grammar end-to-end.
  • Gives the substrate-paper a concrete worked example readers can follow without inventing one.
  • Lets the bench (§7) measure a real grammar's avalanche / uniformity / domain-separation properties rather than a synthetic.

6. Phase 1 deliverables

What ships:

  1. Substrate primitive:
    • arborist/substrate/spatial_anchor.pyAnchorN, split_anchor_n(), SPATIAL_ANCHOR_VERSION, PLACEHOLDER_SPATIAL_SEED
  2. Grammar layer:
    • arborist/world/grammar.pyWorldDimensionGrammar, canonical_grammar_bytes(), grammar_hash(), validate_grammar()
  3. Mappers + record:
    • arborist/world/pi_star/object.py — 5 mappers + WorldObjectRecord
      • derive_world_object_record()
  4. Registry adapter:
    • arborist/pi_star/spatial_anchor_object.py — registered π*
  5. Joseph6 grammar:
    • arborist/world/grammars/joseph6.py (or registry-registered constant) — the JOSEPH6 grammar definition + axiom-pack-joseph6@v1
  6. KATs:
    • bench/fixtures/spatial-anchor-object/known-answer-tests.jsonl — at minimum: zero-hash, max-hash, low-entropy hash, three mid-entropy hashes; expected outputs for Joseph6 grammar
  7. Tests:
    • tests/test_spatial_anchor.py — AnchorN unit + integration
    • tests/test_world_dimension_grammar.py — grammar validation
    • tests/test_pi_star_spatial_anchor_object.py — canonicalizer round-trip + KAT replay
  8. Paper amendment:
    • docs/_source/merkle-agi-v7w-spatial-temporal.rst — new section citing Joseph (@TrudoJo) as the framework author; AnchorN + grammar layer as the architecture
  9. Status:
    • arborist/world/__init__.py STATUS bumps from namespace_reservedworld_object_kernel_in_progress

What does NOT ship in Phase 1:

  • Relation / event / place / agent_trace kernels (siblings)
  • SQL world_state_cells table (Phase 3)
  • New audit_mode token (ever — hard)
  • verifier_policy_hash change (commitments ≠ warrants)
  • Continuous tensors anywhere in proof path
  • Runtime LLM-decided dimensionality (axioms select, validators accept, grammars freeze)
  • Bench at Phase 1 over and above the pre-review empirical bench (§7) — KATs replace open-ended bench

7. Pre-review empirical evidence (already shipped)

bench/spatial_anchor_validation.py (commit 55b651f, 561 lines) validated the HMAC-SHA-512 expansion properties before this ticket's implementation phase. Survives the AnchorN reframe — N just changes the loop count; the per-region properties measured are unchanged.

Reproduce:

make bench-spatial-anchor [SPATIAL_N=10000]
§ Bench Result What it proves
1 Avalanche (single-bit hash flip → Hamming distance over output) mean 767.85 / 768 bits (z = -0.49) counter-mode HMAC-SHA-512 is PRF-good; fixed-offset slicing inherits the property
2 Octree chi² uniformity (L=2,3,4) |z| < 1 every level map_octree_position() modulo 8^L is uniform; no LE-conversion bias
3 Birthday-bound collision ratio (L=4,6) 0.989 / 1.038 structural skew absent; collisions follow PRF expectation
4 Cross-region Pearson r (15 pairs of H₁..H₆) r ∈ [-0.018, +0.012], max |r|/stderr = 1.80 counter-mode block independence holds empirically
5 Domain separation (Arm A distinct seeds vs Arm B shared seed) Arm A 767.91 bits independent · Arm B 0.00 bits exact collision dedicated spatial_anchor_seed discipline is load-bearing; sharing seeds yields byte-identical anchor maps

Result file bench/spatial_anchor_validation_results.md pinned to the RNG seed 0xa8c90e551fd34427 — re-runs hash-stable.

The bench answers 5 of the original 10 design questions (Q1 seed source, Q2 segmentation method, Q3 octree mapper, Q8 endianness, Q9 KAT adversarial vectors). The remaining 5 are design decisions the dav1d review already resolved or paper-editorial calls (see §10).


8. Phase 2 (deferred — siblings under #000013)

When Phase 2 opens:

  • Second grammar registration — proves the registry mechanism works for grammars other than Joseph6. Candidate: Cartesian5 (position-only, 5-region for 3D + 2D-affine variants).
  • π_w_relation* — relation kernel sibling. Different grammar (relations don't have a single anchor), different π* registry slot.
  • π_w_event / π_w_place / π*_w_agent_trace** — three more sibling kernels. Each is its own ticket.

The substrate primitive AnchorN is unchanged across siblings — only the grammar + mappers vary.


9. Phase 3 (deferred — persistence)

  • SQL world_state_cells table (or whatever shape mesh-replay needs)
  • v9.8 cache_key may gain a new dimension if Phase 3 reveals it must (defer to bench evidence)
  • Cold-pack export for v7-W records (sibling of #000061 cold-pack)
  • audit_events writer for π*w* commitments (no new event_type needed; existing pi_star_emit handles this)

10. Open questions

Only the items the dav1d review left genuinely open. The empirical bench (§7) closed Q1/Q2/Q3/Q8/Q9; dav1d's review §0.7 answered Q4/Q5/Q6/Q7.

  1. Q10 — substrate-paper amendment wording. The paper at docs/_source/merkle-agi-v7w-spatial-temporal.rst needs a new section introducing AnchorN + grammar layer (not fixed Anchor6). The technical content is in this ticket; the paper's voice, diagram style, and reading order stay for fox to set.

  2. Grammar registry persistence shape. Are grammars Python constants in arborist/world/grammars/*.py, manifest-declared YAML, or hash-pinned blobs in a SQLite table? Phase 1 starts Pythonic; Phase 2 may need otherwise as more grammars land.

  3. Axiom pack registry vs declared inline. axiom_pack_ref is a registry slot; the axiom pack itself (the physics / math constraints the grammar pins) needs its own canonicalization and KAT discipline. May warrant a sibling ticket if axiom packs grow beyond simple shape.


11. Cross-references

  • #000013 — v7-W substrate reservation. This ticket's Phase 1 flips arborist/world/__init__.py STATUS from namespace_reservedworld_object_kernel_in_progress.
  • #000035 — HMAC-SHA-512 KDF (anchor_prg.py). AnchorN reuses _expand byte-for-byte. Domain separation via dedicated spatial_anchor_seed keeps #000035's KAT freeze intact.
  • #000071 — World-bridge grammar. Bridge ChainRoots may carry world_dimension_grammar_hash from this ticket's grammar layer.
  • #000015 — π* cross-domain composition. Eventually composes spatial π* with linguistic π* via the composition theorem.
  • #000061 — cold-pack object store. Future v7-W record persistence may piggyback on the cold-pack distribution tier.

12. Five-step alignment

  1. Make requirements less dumb. Joseph's framework named the six-dimension axis; dav1d's review named "freeze grammars before proof-path use." Both are load-bearing requirements with people attached.
  2. Delete the part / process. AnchorN replaces Anchor6 — same primitive, generalized. Joseph6 stays as the worked example. Five mappers, not "however many feels right." map_rotation_so3 is deleted; renamed map_rotation_euler_ypr so consumers don't import the SO(3) overclaim.
  3. Simplify and optimize. uint256 for H₁ position (no truncation ambiguity); grammar identity binds into AnchorN expansion (no silent reuse across grammars); manifest-published spatial_anchor_seed (no need to bump PHI_PRG_VERSION).
  4. Accelerate cycle time. KATs replace open-ended bench at Phase 1. Joseph6's grammar_hash is a fixed byte string; deviations show up as KAT failures, not bench drift.
  5. Automate. Last. The π* registry mechanism + KAT discipline automates what the paper specifies; no automation before the grammar registry mechanism freezes.

13. Review history

  • 2026-05-31 — original ticket filed (fixed Anchor6 framing, H₁..H₆ ontology, six-dimension Joseph kernel). Full original proposal preserved in git history at commit 55b651f / e2c8e2c (pre-rewrite tip).
  • 2026-05-31 — pre-review empirical bench shipped in 55b651f validating HMAC-SHA-512 expansion properties (§7); survives the rewrite unchanged.
  • 2026-06-01 — dav1d de-novo review: GO-with-rewrite. Generic AnchorN replaces fixed Anchor6; Joseph6 is the first registered grammar, not THE substrate. uint256 H₁ correction; no SO(3) overclaim; canonical record carries four identity hashes; privacy fail-closed; no SQL / new audit_mode / verifier_policy_hash change at Phase 1. Full review (1904 lines) archived at docs/dav1d-reviews/000070-spatial-anchor-pi-w-object--2026-06-01.txt. This ticket text is the rewrite dav1d's review requires.