#000070: spatial-anchor pi*_w_object ticket + pre-review bench

New ticket for Joseph (@TrudoJo)'s 6-dim procedural spatial-anchor
framework as the first verifier kernel under the #000013 v7-W reserved
namespace. A single committed 32-byte SHA-256 hash deterministically
expands into six 32-byte regions H1..H6 via the HMAC-SHA-512 KDF already
shipped in arborist/substrate/anchor_prg.py (#000035); each region drives
one quantized object dimension under a fixed canonical mapper. Domain
separation from #000035 by dedicated spatial_anchor_seed published in
the v7-W manifest -- preserves #000035's KAT freeze + dav1d 2026-05-11
final review intact.

Bundle:
- docs/tickets/ticket-000070-spatial-anchor-pi-w-object.md (718 lines):
  full spec with 8 design-choice subsections, working Python sketch,
  12-NOT scope boundaries, 8-row cross-references, five-step deletions,
  10 open questions for dav1d.
- bench/spatial_anchor_validation.py: pure-stdlib pre-review evidence
  (~2s, RNG-seed-pinned, reproducible). Five benches: avalanche,
  cell-distribution uniformity, collision vs birthday-bound, cross-region
  independence, domain separation.
- bench/spatial_anchor_validation_results.md: report from first run.
- Makefile: 'make bench-spatial-anchor [SPATIAL_N=N]' target + PHONY.
- docs/TICKETS.md: index row + Next ID 000070 -> 000071.

Bench headlines (N=10000):
- Avalanche mean 767.85 bits (PRF null 768, z=-0.49)        -> PASS
- Cell-distribution chi^2 |z|<1 at L=2,3,4                  -> PASS
- Birthday-bound ratio obs/exp 0.989/1.038 at populated L   -> PASS
- Cross-region Pearson all 15 pairs < 2sigma                -> PASS
- Domain separation Arm A 767.91 / Arm B exact 0 collision  -> PASS

Five of dav1d's ten open questions (Q1 seed source, Q2 segmentation,
Q3 position mapper, Q8 endianness, Q9 KAT adversarial vectors) now
resolve with measurements rather than appeals to PRF authority.
Q4/Q5/Q6/Q7/Q10 remain non-empirical design decisions.

Status: open, awaiting dav1d review + fox go/no-go. No registry slot
booked, no substrate-paper amendment landed, no kernel module created.
This commit is contained in:
russell@unturf.com 2026-05-31 10:16:02 -04:00
parent 2b8777c947
commit 55b651f624
No known key found for this signature in database
5 changed files with 1463 additions and 2 deletions

View file

@ -111,6 +111,7 @@ Newest first. Update on every open/close.
| ID | Title | Status | Opened | Directive |
|----------|------------------------------------------------|-----------------------|------------|-----------|
| #000070 | Spatial-anchor π*_w_object (Joseph 6-dim determination kernel) | **open · awaiting dav1d review + fox go/no-go** (2026-05-31; surfaced when fox brought in Joseph @TrudoJo's procedural-spatial framework — "hashes do not encode the world, hashes determine the world" — and asked whether it fits arborist's substrate model. It does, cleanly. Implements the first verifier kernel under the #000013 v7-W reserved namespace (`arborist/world/__init__.py` `STATUS = "namespace_reserved"``kernel_in_progress` on land): a single committed 32-byte SHA-256 hash deterministically expands into six named 32-byte regions `H₁..H₆` via the HMAC-SHA-512 KDF already shipped in `arborist/substrate/anchor_prg.py` (#000035), and each region drives one quantized object dimension under a fixed canonical mapper — `H₁→octree position`, `H₂→scale level`, `H₃→quantized SO(3) rotation`, `H₄→material palette`, `H₅→raw links (reserved for π*_w_relation sibling ticket)`, `H₆→behavior code`. Domain separation from #000035 by dedicated `spatial_anchor_seed` (manifest-published) — keeps #000035's KAT freeze + dav1d 2026-05-11 final review intact. Hard constraints: stays inside A1A3, no continuous tensors in proof path, no new `audit_mode` token (substrate commitments are not warrants — the four-rung ladder is unchanged), no SQL schema change at Phase 1, `canonicalization_version` absorbs the new `spatial-anchor-object@v1` registry slot. Phase 1 deliverable ~150 LoC + 10 KATs + tests in one PR: `arborist/substrate/spatial_anchor.py` (segmentation), `arborist/world/pi_star/object.py` (six mappers), registry entry, KAT vectors at `bench/fixtures/spatial-anchor/known-answer-tests.jsonl` matching #000035 KAT discipline, `tests/test_spatial_anchor.py` + `tests/test_world_pi_star_object.py`, substrate-paper amendment citing Joseph (@TrudoJo) in `docs/_source/merkle-agi-v7w-spatial-temporal.rst`. Position mapper at Phase 1 = octree (substrate paper §2.1 + §A worked example); H3/S2/Hilbert/Morton siblings deferred — Morton's value is purely as the relation-kernel `pair(A,B)` cheap bit-interleave and surfaces in the sibling ticket. **Ten open questions for dav1d** in §8: seed-source choice, segmentation method, position mapper, scope split (object alone vs object+relation per CLAUDE.md memory `feedback_ticket_proliferation`), privacy-class fail-closed default, `audit_mode` discipline confirmation, manifest-validator timing, endianness reconfirmation, KAT count + adversarial vectors, paper-amendment wording. Five-step §7 deletions captured: dropped the prior `/tmp/arborist-spatial-ontology-plan.md`'s geographic-search backend (encoding-route confusion), `Document.extra` lat/lon hooks (different ticket if at all), `audit_mode=HYBRID` for spatial hits (convention-illegal), geohash (subsumed by Morton), quadtree as separate (octree at z-level-0), Hilbert at Phase 1 (deferred), tier-1/2/3 hash-suite framing (conflated hard vs soft hashes), and `arborist/spatial/` namespace (violates topic-naming rule). Full spec in `docs/tickets/ticket-000070-spatial-anchor-pi-w-object.md`. | 2026-05-31 | — |
| #000069 | Arborist VIZ / Merkle Command Center (Pyramid + six.js + SSE browser dashboard) | **open · awaiting go/no-go · doc-only scaffold** (2026-05-27; filed from `/home/fox/Downloads/TICKET_0000VIZ_*`, stack corrected same day per fox). Configurable browser dashboard for inspecting arborist's content-addressed state: Merkle root explorer, proof verifier, claim warrant + graveyard, audit timeline, run-DAG replay, cache-key explainer, root diff, 3D Merkle lattice, optional circuit/activation traces. Read-only consumer; arborist proper stays source-of-truth, dashboard projects state. **Stack pinned to unturf-native** (fox 2026-05-27, supersedes proposal §3): **Pyramid + Jinja2 + SQLAlchemy** (matches `remarkbox` / `make_post_sell` / `unhomeschool.com` idiom), **SSE** (`text/event-stream` via Pyramid streaming response) for live audit/claim/falsifier patches, **vanilla JS + six.js** (fox's patched three.js fork at `git.unturf.com/gumyum/six.js` — three.js r175 + CWE-407 patches incl. ObjectBVH O(N)→O(log N); bundles vendored from `~/git/cupPCB/cdn/six/`; third-instance MOAD-0001 dogfood alongside `java-topology` + gumyum-engine) for 3D widgets and large-graph rendering, SQLite for dashboard metadata (no PostgreSQL/ClickHouse/Redis/NATS by default — promote on measured need), no React / no Next.js / no Node build step. Server-rendered SVG (or Graphviz `.dot` per existing `docs/diagrams/*.dot` pattern) replaces React Flow for run-DAG widgets. Browser-side proof verification dropped from v1 (server-side Pyramid view returns PASS/FAIL + receipt; reinstate phase-N only if third-party-verification use case surfaces). **Three filing-note gates before phase 0** (in ticket body): **F-1** sibling-repo home — implementation lives in a new `~/git/arborist-viz` (Pyramid Python, matches existing unturf apps), not in-tree; arborist's contribution is the read-API spec + view package + arborist library import via `arborist.embed`. **F-2** scope split — proposal carries 8 phases (§17 phases 08); recommended cut keeps phases 03 (schema + shell + proof/root widgets + claim/audit/run widgets) inside #000069, and spawns sibling tickets for SSE streaming (4), 3D six.js (5), massive-graph (6, only if measured need surfaces), circuit-tracing (7, gated on #000062), embeddable widgets (8) — Dav1d-audience rule. **F-3** upstream prereqs — phase 7 (circuit/activation) consumes **#000062 Mechanistic Witness**'s `MechanisticWitnessRoot`; phase 3's claim-graveyard widget projects **#000059**'s bounded-ingestion graveyard. Hard constraints: arborist soft-vs-hard discipline applies verbatim (attribution weights renderable but never `audit_mode`, never causal without intervention/ablation evidence); private-leaf default-deny (commitments + hashes + redacted maps only without explicit auth); every widget exposes its data query + source roots. Reserved scope: NOT a replacement for `arborist controller-events` / `arborist analyze` / `arborist inspect` CLI — those stay canonical inspector surfaces; VIZ is the projection layer. | 2026-05-27 | — |
| #000068 | Verifier-blind missed-answer falsification guard | **in progress · Phase 1+2+3 landed 2026-05-27 · Phase 4 default flip NO-GO** (Phase 2 bench 2026-05-27 76q × n=3 claim_lattice Hermes-3-8B: 2/228 sidecar fires, both STRONG confidence, both the Ballestrini regression fixture, 100% precision, 0/226 false positives across non-Ballestrini runs. Phase 3 demote flag opt-in via `--demote-on-missed-answer` on `query`/`ask` — wires `EVIDENCE-WARRANTED → EVIDENCE-MISSED-PARTIAL` for strong/medium confidence on lattice modes; lower rungs + non-lattice modes get `· missed-answer` tail tag. `answerability_demote_enabled` added to `_VERIFIER_POLICY_FIELDS` so flipping the flag partitions cache via verifier_policy_hash. Default OFF per Dav1d Phase 4 NO-GO — 100% precision at n=2 fires is too few samples to claim precision floor empirically; default flip blocks on wider bench + human spot-check. 47 tests (36 Phase 1 + 11 Phase 3) all passing. End-to-end verified live: 4/4 Hermes runs on Ballestrini with --demote-on-missed-answer rendered EVIDENCE-MISSED-PARTIAL.) Original opening 2026-05-27 (Dav1d de-novo review GO for Phase 1 with seven hardenings folded into spec — subject-token cue-stripping, answer-type alignment, confidence_class, candidate cap=10, precise offset_start/end/basis, cache-hit recompute-on-read, Phase 1 out of verifier_policy_hash). Original opening 2026-05-27; sibling to the user-payload-layout work shipped 2026-05-26, split out per the Dav1d-audience rule — `feedback_ticket_proliferation`). Surfaced by the Ballestrini case: evidence E2 literally contained the song names, Hermes-3-8B under `user_payload_layout=tail` said *"specific songs by her are not mentioned in the provided evidence blocks"*, verifier marked the run `EVIDENCE-WARRANTED` 2/2 because nothing positive was unsupported. **Verifier-blind false-negative class** — existing layered verifier (quote/span/entity/paraphrase + Rule 8 + Rule 9 + claim ceiling) guards unsupported *presence*, has no hook for unsupported *absence*. Layout fixes attention placement on the specific instance (n=3 bench 2026-05-27 confirms bookend/per_chunk recover Ballestrini); layout alone can't close the class — adversarial phrasing or bigger prompt resurfaces it under any layout. Proposed deterministic sidecar in `arborist/qa/inspect.py:diagnose_missed_answer`: three-clause conjunction — **(A)** answer matches denial pattern ("not mentioned", "not provided", "the evidence does not say", …, closed list versioned via `denial_patterns_version`); **(B)** question is extraction shape (reuse `arborist.qa.quantifier` classifier — `ALL`/`COMPREHENSIVE`/`OPEN_REQUEST` intensities, OR surface cues "songs by"/"works by"/"who wrote"/"list"/"name all"); **(C)** evidence contains candidate spans near subject tokens (reuse `entity_proximity_n`/`entity_proximity_window` from verify.py — quoted strings, title-case spans, comma-separated title lists within W chars of stemmed subject content tokens). All three must fire. Output: `result["answerability"]` with `missed_answer_candidate_spans` list (evidence_id + offset + text). **Hash discipline:** sidecar fields (`denial_patterns_version`, `extraction_cues_version`, `answerability_threshold`) fold into `governance_policy_hash` only; an optional `answerability_demote_enabled` flag (default OFF) wires `EVIDENCE-WARRANTED → EVIDENCE-MISSED-PARTIAL` in `_render_audit_label`, and IF on folds into BOTH `governance_policy_hash` AND `verifier_policy_hash` (changes rendered audit_mode, so verifier hash must move — the deliberate opt-in moves the verifier hash, sidecar-only stays out). No LLM-as-judge. Never writes `providence_cache`/`audit_events`. Never promotes claims. Pattern verbatim from `arborist.qa.inspect.diagnose_*` (deflection, coherence, title-relevance). Phases: 1 sidecar read-only, 2 bench + threshold tuning, 3 demote opt-in, 4 default decision (bench-gated). 5F-Falsification fixture: Ballestrini case already in `bench/qa_questions.txt` under "entity list". Full spec in `docs/tickets/ticket-000068-verifier-blind-missed-answer-guard.md`. | 2026-05-27 | D2 |
| #000067 | M-aware cold-pack hydration (route incoming docs by content hash into M target shards) | **open · scaffold · prereq for #46 genesis test** (2026-05-26; surfaced while preparing the 3090 SPV-wallet validation). Today's `hydrate_from_metadata_pack` takes a single `conn` and writes every incoming row into one shard. With the corpus now in M=4 hash-routed topology (#000065), a fresh peer needs to land each document on `shard_for_document(document_root, M)` — same routing function as the producer. Without this, a fresh peer's `~/.arborist/shards/` is just one big single-shard DB and the M=4 ATTACH-and-route assumption #000065 was sized for doesn't hold consumer-side. Two coherent shapes: **(α) two-step kludge** — hydrate into single shard, then `arborist corpus reshard --to M` on the consumer. Works today (proven by the 2026-05-26 reshard executor) but doubles the wall time and treats packed shards as if they came from an arbitrary topology. **(β) direct M-aware hydrate** — extend `hydrate_from_metadata_pack` to accept `targets: list[sqlite3.Connection]` + `M: int` and route per-row at restore time (reusing `arborist.document.shard_for_document` + the table-routing rules in `arborist/migrate.py`). Manifest carries `corpus_shard_count` so the unpacker knows M from the pack itself. β is the right answer — α exists only as a fallback if 20-min-window pressure forces it. Sequence: (1) add `corpus_shard_count` to pack manifest (read from source meta during `dump_shard_metadata`); (2) `restore_shard_metadata_routed(targets, M, table_dir)` in `cold_pack_metadata.py` mirroring `_route_per_doc_table` from migrate.py; (3) `hydrate_from_metadata_pack` gains a `targets`/`shards_dir` param; (4) `arborist cold unpack --shards-dir DIR` initialises M target shards from the manifest's `corpus_shard_count` and routes; (5) regression test: pack 2 shards → hydrate into fresh 4 shards → assert every doc on its hash-routed target. Refactor opportunity: the routing rules (ROUTED_BY_DOCUMENT_ROOT, CONSOLIDATED_TABLES) currently live in migrate.py; this ticket can either duplicate them in cold_pack_metadata.py (fast) or factor into a shared `arborist/multi_shard.py` module (cleaner). The shared-module path is more honest given graft mode (#000066) wants the same primitives. Out of scope: graft / overlay mode (that's #000066 — overlays onto populated, this is hydrate-into-empty). | 2026-05-26 | — |
@ -183,4 +184,4 @@ Newest first. Update on every open/close.
## Next ID
`000070`
`000071`

View file

@ -0,0 +1,761 @@
# Ticket #000070 — Spatial-anchor π*_w_object (Joseph 6-dim determination kernel)
**Status:** open · awaiting dav1d review + fox go/no-go
**Opened:** 2026-05-31
**Scope:** Pin the operational spec for **π*_w_object** — the first
verifier kernel of v7-W. Implements **Joseph (@TrudoJo)**'s 6-dimension
procedural-anchor framework: a single committed 32-byte SHA-256 hash
deterministically expands into six named regions `H₁..H₆` via the
HMAC-SHA-512 KDF already shipped in `arborist/substrate/anchor_prg.py`
(#000035), and each region drives one quantized object dimension under
a fixed canonical mapper. This ticket lands segmentation + position
mapper + registry slot + KATs. Relation / event / place / agent_trace
kernels land as siblings under #000013.
**Audience:** dav1d (primary review), v7-W substrate-paper maintainers,
Joseph (@TrudoJo, original framework author), #000013 follow-up,
#000035 follow-up.
**Hard constraint:**
- Stays inside A1A3 (canonical encoding, public quantization,
collision-resistant hash). No new axiom.
- π*_w on **quantized integer state** only; continuous floats do not
enter the proof path (v7-W manifest hard rule, paper §1.2).
- 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.** CLAUDE.md: `audit_mode` is decided
by the verifier, never asserted. π*_w_object emits commitments,
not warrants. The four-rung ladder (POINTER-LINKED →
ANCHOR-WARRANTED → EVIDENCE-WARRANTED → ENTAILMENT-VERIFIED) is
not extended by Phase 1.
- **Schema column-unchanged.** A new `pi_star/spatial-anchor@v1`
registry entry folds into `canonicalization_version` (one of the
v9.8 8-dim cache_key dimensions). No new SQL table required for
Phase 1; persistence to a `world_state_cells` table is deferred.
- Topic-named, not version-prefixed (CLAUDE.md naming rule). Lands
under `arborist/world/pi_star/`, not `arborist/v7w/` or
`arborist/spatial/`.
---
## 1. Problem statement
### 1.1 What #000013 left undefined
#000013 closed 2026-05-09 doc-only — substrate paper at
`docs/_source/merkle-agi-v7w-spatial-temporal.rst` (658 lines) plus
the frontier catalog at `docs/v7w-frontier-catalog.md` plus the
namespace stub at `arborist/world/__init__.py` (`STATUS =
"namespace_reserved"`). The substrate paper §1.1 names five
world-state object kinds:
```
- objects: { id, class, bbox, pose, confidence }
- relations: { subject_id, predicate, object_id, time_window }
- events: { type, t_start, t_end, participants, place }
- places: { id, frame_of_reference, geometry, parent_place }
- agents: { id, position_trace, pose_trace, attention_trace }
```
§2.1 specifies the **discretization grammar** (octree / S2 / quadtree
with hierarchical levels declared by the deployment manifest). §2.3
specifies the **frame discipline** (frame_id = SHA-256 of canonical
frame definition; transforms committed). The paper §A worked example
walks a 10×10×3 m room with an octree manifest. What the paper does
**not** specify operationally is the function
```
H : 32-byte SHA-256 commitment → object record
```
— how a *single anchor hash* determines an object. The paper treats
π*_w as an encoder of observations produced by an exogenous
world-model engine (SLAM, Gaussian splatting, predictive video). That
is the *encoding* model: object → bytes → hash.
### 1.2 Joseph's framework — determination model
2026-05-31 fox brought in Joseph (@TrudoJo)'s framework. Verbatim
core distinction:
> **Hashes do not encode the world. Hashes determine the world.**
> The hash is not a message. It is a fixed generative coordinate.
> Object identity = determined by its own hash. Object expression =
> determined by the hash plus its surrounding hashes.
Operational spec: a single anchor hash splits into six stable regions
and each region drives one object dimension via a fixed deterministic
mapper.
```
H = 9f3a...c71b
H₁ → position
H₂ → scale
H₃ → rotation
H₄ → material
H₅ → relation / links
H₆ → behavior / motion
object.position = map(H₁)
object.scale = map(H₂)
object.rotation = map(H₃)
object.material = map(H₄)
object.links = map(H₅)
object.motion = map(H₆)
same hash + same rule-field = same object every time
```
Joseph's "necessary rule" (verbatim): the system must fix **hash
algorithm, hash length, byte order, segmentation method, pairing
method, ordering rule, mapping functions, world version, collision
policy**. Otherwise the same hashes generate different worlds under
different interpreters.
### 1.3 Why this fits arborist's substrate model
Cross-checked against ground truth on 2026-05-31:
| Joseph spec requirement | Arborist primitive that fulfills it |
|---|---|
| `hash → rule-field → object` (determination) | `arborist/substrate/anchor_prg.py` `_expand()` — counter-mode HMAC-SHA-512 KDF, 193 LoC, KAT-frozen #000035 |
| Fixed hash algo + length | SHA-256 (`arborist/merkle.py:24-40`, `LEAF_PREFIX=0x00`, `NODE_PREFIX=0x03`, 32-byte output) |
| Fixed byte order | Little-endian throughout (v7 §A1; `PHI_PRG_VERSION = "phi-prg-v1-hmac-sha512-le"`) |
| World version (different interpreters ≠ different worlds) | v9.8 8-dim `cache_key``governance_policy_hash` + `canonicalization_version` + `schema_version` + `chunking_version`; bump any dim → prior worlds invalidated on lookup |
| Mapping functions | `arborist/pi_star/registry.py``register(pi_star: PiStar)` API; one slot per canonical projection (existing slots: `arithmetic@v1`, `logic-kernel@v1`, `algebra-symbolic@v1`, `claim-lattice@v1`, …) |
| Object identity (H alone) | π*_w_object — this ticket |
| Object expression (H in field) | π*_w_relation — sibling ticket |
| Hash + grammar (joint canonicalization) | governance_policy_hash absorbs grammar changes; bumping registry version stales worlds |
Joseph's framework supplies the **operational layer** the substrate
paper deferred. Without it, `world/` stays a namespace stub. With it,
`world/pi_star/object.py` becomes the first verifier kernel and the
v7-W substrate moves from `namespace_reserved` to
`kernel_in_progress`.
### 1.4 Encoding vs determination — both compose
Important: arborist's existing merkle commits are *encoding* (object
→ canonical bytes → SHA-256 root). Merkle proofs verify "this object
hashed to this root." Joseph's framework is *determination* (hash →
grammar → object). A determination "proof" verifies "given this seed,
grammar, and hash, the object **must** be this."
These compose. Encoding gives commitment (un-forgeable post-hoc).
Determination gives reproducibility (every interpreter agrees on the
object). For π*_w_object both hold: the SHA-256 hard hash is the
commitment surface (encoding), and the HMAC-SHA-512 expansion plus
six mappers is the determination grammar. This is the same shape as
verifiable random functions in cryptography; it is the same shape as
v7 §9.10 φ_PRG already shipped.
## 2. Design choices
### 2.1 Seed source — dedicated `spatial_anchor_seed` vs domain-tag bump
**A. Dedicated `spatial_anchor_seed` in the v7-W manifest (recommended).**
Publish a second 32-byte seed beside `anchor_prg_seed`. `_expand()`
from `arborist/substrate/anchor_prg.py` is reused as-is with the new
seed. No `PHI_PRG_VERSION` bump.
- **Strength:** respects #000035 §2.4 single-purpose rule exactly. No
PRF-security regression. dav1d's 2026-05-11 #000035 final review
stays valid.
- **Cost:** manifest gains one field. Rotation policy stays at the
v7-W manifest layer.
**B. Domain-tag input under bumped `PHI_PRG_VERSION`.**
Bump to `phi-prg-v2-hmac-sha512-le-dst` and add a 4-byte
little-endian domain tag (e.g. `0x77_77_5f_53` = ASCII `"w_S"`) into
the KDF input: `HMAC(seed, hard_hash || domain_tag || counter)`.
Reuses `anchor_prg_seed`.
- **Strength:** cleaner cryptographic story — true domain separation
by tag rather than by seed independence.
- **Cost:** spec churn. #000035 just KAT-froze (10 KATs at
`bench/fixtures/phi-prg/known-answer-tests.jsonl`). Bumping forces
regeneration for every v7 anchor-map consumer and invalidates
dav1d's 2026-05-11 review.
**Recommendation: A.** Smaller blast radius; orthogonal to #000035's
frozen surface.
### 2.2 Region segmentation — fixed offsets vs per-region nested HMAC
**A. Fixed-offset slicing (recommended).**
Compute `_expand(spatial_anchor_seed, hard_hash_32, 192)` → 192 bytes
→ six 32-byte regions at byte offsets `[0,32), [32,64), …,
[160,192)`. Three HMAC-SHA-512 blocks (64 B each) cover the 192-byte
output exactly.
- **Strength:** trivial; KAT-able; deterministic; reuses #000035's
counter-mode discipline byte-for-byte.
- **PRF independence argument:** counter-mode HMAC-SHA-512 blocks are
computationally independent under the standard SHA-512 + HMAC
assumption — the same argument #000035 §2.1 used to bound the
channel. Slicing the concatenation does not weaken independence.
**B. Per-region nested HMAC.**
For each region, `H_i = HMAC-SHA-512(spatial_anchor_seed, hard_hash_32
|| i_le_u32)[:32]` with `i ∈ {1..6}`.
- **Strength:** textbook tree-PRF; per-region independence by
construction.
- **Cost:** 6× HMAC calls vs 3× in A. Negligible at v7-W cadence but
pointlessly more code.
**Recommendation: A.**
### 2.3 Spatial coordinate output per dimension
Each region's mapper consumes 32 bytes and emits a canonical integer
cell. Per-dimension choice:
| `H_i` | Dimension | Mapper output | Rationale |
|------|----------|---------------|-----------|
| `H₁` | position | **octree cell at manifest-declared level `L`** — read `H₁[0:8]` as little-endian uint64, modulo `8**L`, descend bit-by-bit to canonical `cell_id` | Substrate paper §2.1 explicitly recommends octree for object-fixed local frames; §A worked example uses octree with `level_max=18` |
| `H₂` | scale | **level integer** in `[level_min, level_max]` — read `H₂[0]` as uint8, modulo `(level_max - level_min + 1)`, offset by `level_min` | Manifest-declared range; uniform modulo across declared levels |
| `H₃` | rotation | **quantized SO(3) cell** — read `H₃[0:12]` as three LE uint32, normalize to integer-quaternion grid of step `Δ_rot ≥ 1 mrad` | Paper §A ε budget `Δ_rot ≈ 1 mrad` |
| `H₄` | material | **palette index** — read `H₄[0:4]` as LE uint32, modulo manifest-declared palette size | Deployment-specific |
| `H₅` | links / relation seed | **opaque 32 bytes carried through** as raw input to the relation kernel (sibling ticket) | Phase boundary — relation kernel canonicalizes the `pair(A,B) → relation-seed` operator |
| `H₆` | behavior / motion | **behavior code** — read `H₆[0:4]` as LE uint32, modulo manifest-declared behavior-table size | Deployment-specific |
`H₅` deliberately stays raw — Joseph's `pair(A, B) → relation-seed`
operator consumes raw bytes from both anchors. Canonicalizing `H₅`
here would foreclose the relation kernel's design space.
**Why octree and not Morton / H3 / S2 / Hilbert at Phase 1.** The
substrate paper §2.1 names octree for object-fixed frames as the
primary recommendation; the §A worked example uses octree. Picking
one mapper at Phase 1 keeps KAT scope tractable. Geographic /
planetary deployments register `spatial-anchor-s2@v1` later;
image-plane / 2D-floor deployments register
`spatial-anchor-quadtree@v1`; pairwise-locality deployments register
`spatial-anchor-hilbert@v1`. All siblings, all under #000013.
Morton's value is purely as a cheap bit-interleave for the relation
kernel's `pair(A,B)` operator and surfaces there, not here.
### 2.4 Scope: does this ticket also land π*_w_relation?
Joseph's framework treats object and relation as a tightly coupled
pair: identity from a single hash, expression from pairs. CLAUDE.md
memory: "don't proliferate tickets — prefer extending existing."
**A. Single ticket lands object + relation.**
- Smaller cross-reference graph; one dav1d-review pass covers the
full identity+expression substrate.
- Larger review surface (~300 LoC + 20 KATs vs ~150 + 10).
**B. Sibling ticket for relation (recommended pending fox call).**
- Object kernel ships and can be benched independently before
relation canonicalization is pinned.
- Relation introduces the `pair(A,B)` canonicalization choice
(symmetric `min || max` vs ordered) — that's a distinct
architectural decision dav1d will want to review on its own
surface.
- #000049 and #000048 split similarly when NLI introduced a fresh
audit_mode question; this is the same shape.
**fox call requested. Open question #4 below.**
### 2.5 Privacy class — fail-closed manifest declaration
v7-W paper §6 requires the deployment manifest to declare its
privacy class:
```json
{"privacy": {"class": "public | aggregated_only | ZK_with_selective_disclosure"}}
```
The §A worked example defaults to `"public"`.
**A. Phase 1 requires explicit declaration (recommended).** Manifest
loader raises if `privacy.class` is missing.
- **Strength:** fail-closed (CLAUDE.md guardrail). Anyone shipping a
non-public deployment cannot accidentally omit the class.
- **Cost:** worked example manifests must be edited to declare
`"public"` explicitly — trivial.
**B. Default to `"public"` if absent.**
- **Strength:** matches the paper §A example shape.
- **Risk:** a downstream operator forgets to declare; deployment
ships exposing positions. Surveillance risk per paper §6.
**Recommendation: A.** Fail-closed beats convenience.
### 2.6 `audit_mode` discipline — commitments are not warrants
CLAUDE.md: "`audit_mode` is decided by the verifier, never
asserted." A spatial-anchor-derived object is **not** evidence for a
spatial claim. It is a commitment that "given THIS seed + grammar +
hash, THIS is the object." The verifier discipline (quote / span /
entity / paraphrase) is unchanged by Phase 1.
If a downstream consumer wants to use spatial commitments as
warrants for spatial claims, that requires a new verifier method
(`spatial_commitment`) — separate ticket, separate
`verifier_policy_hash` impact, **not in scope here**. The four-rung
ladder (POINTER-LINKED → ANCHOR-WARRANTED → EVIDENCE-WARRANTED →
ENTAILMENT-VERIFIED reserved) is not extended by Phase 1.
This is the single most important conceptual discipline of this
ticket. The prior `/tmp/arborist-spatial-ontology-plan.md` proposed
"hits carry `audit_mode=HYBRID`" — convention-illegal, rejected.
### 2.7 Manifest schema — declared or coded?
`world/manifest.py` is not in Phase 1 scope. Phase 1 accepts a
Python `dict` matching the paper §A shape and reads its `grid`,
`frames`, `materials`, `behaviors`, `privacy` fields. A JSON-Schema
validator + canonical-bytes serializer lands as a separate ticket
under #000013.
**Open question #8 below** — is "manifest-as-dict, no validator" an
acceptable Phase 1 contract, or does the validator have to land
together?
### 2.8 Endianness
Little-endian throughout, matching v7 §A1 / #000035. The Phase 1
mapper reads bytes as LE uint8 / uint32 / uint64 for `H₁`, `H₂`,
`H₃`, `H₄`, `H₆`. Big-endian readers would be a #000035-style
silent-divergence defect.
## 3. Recommendation
**Phase 1 deliverable** — ship the segmentation + position kernel
under one PR:
1. **`arborist/substrate/spatial_anchor.py`** — module wrapping
`_expand` from `anchor_prg.py`. Constants:
- `SPATIAL_ANCHOR_VERSION = "spatial-anchor-v1-hmac-sha512-le"`
- `PLACEHOLDER_SPATIAL_SEED: bytes` — 32 bytes, SHA-256 of fixed
string for test reproducibility, NOT a security claim, matching
`anchor_prg.PLACEHOLDER_SEED` discipline
- `class Anchor6(NamedTuple)` — six 32-byte regions
- `def split_anchor(hard_hash_32, *, seed) -> Anchor6`
2. **`arborist/world/pi_star/object.py`** — six `_map_*` functions
per §2.3 table. Public callable
`pi_star_w_object(hard_hash_32, manifest, *, seed) -> ObjectRecord`.
3. **`arborist/world/pi_star/__init__.py`** — package marker.
4. **`arborist/pi_star/registry.py` registration** —
`spatial-anchor-object@v1` registered via `register(pi_star)`.
The version string folds into `canonicalization_version`
(CLAUDE.md schema invariant).
5. **KAT vectors** at
`bench/fixtures/spatial-anchor/known-answer-tests.jsonl` — 10
vectors, matching the #000035 §3.4 KAT discipline. Each vector
pins `(seed_hex, hard_hash_hex, manifest_canonical_bytes_hex,
octree_cell_id, scale_level, rotation_cell_tuple,
material_index, links_blob_hex, behavior_code)`.
6. **Tests**:
- `tests/test_spatial_anchor.py``split_anchor` shape,
deterministic, domain separation from `anchor_prg`
(`split_anchor(H, seed=S1) ≠ phi_prg(H, …, seed=S1)` outputs),
bool-reject + size-reject mirroring `phi_prg`, KAT replay.
- `tests/test_world_pi_star_object.py` — per-mapper KAT replay,
manifest validation (missing privacy class → raise; missing
grid → raise; out-of-range level → raise), determinism under
dict ordering.
7. **AUTOCOUNT discipline** — wrap any numeric claim added to docs
(test count, KAT count) per `docs/tickets/ticket-000044-*`.
**Phase 2 (separate ticket per §2.4 recommendation B)** —
π*_w_relation consuming `H₅` from two anchors. Canonicalization
decision: lexicographic `min(A,B) || max(A,B)` for symmetric
predicates; ordered for directed. Pinned by
`relation_canonicalization_version`.
**Phase 3 (separate ticket)** — `world/frontier/{pose_integration,
observation_update, object_logits, relation_logits}.py` per paper
Part 4.
**Phase 4 (separate ticket)** — `world/manifest.py` JSON-Schema
validator + canonical-bytes serializer.
**Phase 5 (separate ticket)** — SQL persistence layer:
`world_state_cells` table or `edges` extension; folds into
`schema_version` bump (stales prior records — must be batched with
other v9.x → v9.y migrations).
## 4. Implementation sketch
```python
# arborist/substrate/spatial_anchor.py
"""π*_w_object six-region anchor segmentation (Joseph @TrudoJo framework).
Splits a committed 32-byte SHA-256 hash into six named 32-byte regions
using HMAC-SHA-512 counter-mode KDF (reuses ``anchor_prg._expand`` from
#000035). Domain separation from #000035 is by **seed**: a dedicated
``spatial_anchor_seed`` is published in the v7-W manifest beside
``anchor_prg_seed``; never reuse one for the other.
"""
from __future__ import annotations
import hashlib
from typing import NamedTuple
from arborist.substrate.anchor_prg import _expand
SPATIAL_ANCHOR_VERSION = "spatial-anchor-v1-hmac-sha512-le"
# Test placeholder; v7-W deployment manifest publishes the real seed.
PLACEHOLDER_SPATIAL_SEED: bytes = hashlib.sha256(
b"arborist v7-w spatial_anchor placeholder seed -- ticket #000070"
).digest()
# 6 regions × 32 bytes; HMAC-SHA-512 produces 64-byte blocks → 3 blocks.
_REGION_BYTES = 32
_TOTAL_BYTES = 6 * _REGION_BYTES # 192
class Anchor6(NamedTuple):
h1_position: bytes # 32 B → octree cell id
h2_scale: bytes # 32 B → manifest grid level
h3_rotation: bytes # 32 B → quantized SO(3) cell
h4_material: bytes # 32 B → palette index
h5_links: bytes # 32 B → raw, consumed by π*_w_relation
h6_behavior: bytes # 32 B → manifest behavior code
def split_anchor(
hard_hash_32: bytes,
*,
seed: bytes = PLACEHOLDER_SPATIAL_SEED,
) -> Anchor6:
"""Determine the six-region anchor for a committed object hash.
Same hash + same seed = same anchor every time, by HMAC-SHA-512
PRF property under the standard SHA-512 + HMAC assumption.
"""
if not isinstance(hard_hash_32, (bytes, bytearray)) or len(hard_hash_32) != 32:
raise ValueError(
"hard_hash_32 must be exactly 32 bytes (SHA-256 output)"
)
if not isinstance(seed, (bytes, bytearray)) or len(seed) != 32:
raise ValueError("seed must be exactly 32 bytes")
raw = _expand(bytes(seed), bytes(hard_hash_32), _TOTAL_BYTES)
return Anchor6(
h1_position=raw[0:32],
h2_scale=raw[32:64],
h3_rotation=raw[64:96],
h4_material=raw[96:128],
h5_links=raw[128:160],
h6_behavior=raw[160:192],
)
__all__ = ["Anchor6", "split_anchor", "SPATIAL_ANCHOR_VERSION",
"PLACEHOLDER_SPATIAL_SEED"]
```
```python
# arborist/world/pi_star/object.py
"""π*_w_object — Joseph 6-dim object kernel (#000070).
Composes ``split_anchor`` (#000070 §3) with six per-dimension mappers
to emit a canonical integer ObjectRecord. Output is content-addressable
under (seed, hard_hash_32, manifest_canonical_bytes).
"""
from __future__ import annotations
from typing import TypedDict
from arborist.substrate.spatial_anchor import Anchor6, split_anchor
PI_STAR_OBJECT_VERSION = "spatial-anchor-object-v1"
class ObjectRecord(TypedDict):
octree_cell_id: int
scale_level: int
rotation_cell: tuple[int, int, int]
material_index: int
links_blob_hex: str # raw H5, hex-encoded for canonical JSON
behavior_code: int
def pi_star_w_object(
hard_hash_32: bytes,
manifest: dict,
*,
seed: bytes,
) -> ObjectRecord:
_require_manifest(manifest)
a = split_anchor(hard_hash_32, seed=seed)
grid = manifest["grid"]
return ObjectRecord(
octree_cell_id=_map_position(a.h1_position, grid),
scale_level=_map_scale(a.h2_scale, grid),
rotation_cell=_map_rotation(
a.h3_rotation,
int(manifest.get("rotation_delta_mrad_inv", 1000)),
),
material_index=_map_material(a.h4_material, len(manifest["materials"])),
links_blob_hex=a.h5_links.hex(),
behavior_code=_map_behavior(a.h6_behavior, len(manifest["behaviors"])),
)
def _require_manifest(manifest: dict) -> None:
# Fail-closed (Phase 1 §2.5 recommendation A): explicit privacy class
if "privacy" not in manifest or "class" not in manifest["privacy"]:
raise ValueError(
"manifest must declare privacy.class explicitly (v7-W paper §6); "
"see worked example at "
"docs/_source/merkle-agi-v7w-spatial-temporal.rst §A"
)
# Grid declaration required (paper §2.1)
if "grid" not in manifest or "type" not in manifest["grid"]:
raise ValueError("manifest must declare grid.type (paper §2.1)")
# Materials + behaviors required for H4 + H6 mappers
if not manifest.get("materials"):
raise ValueError("manifest must declare a non-empty materials list")
if not manifest.get("behaviors"):
raise ValueError("manifest must declare a non-empty behaviors list")
def _map_position(h1: bytes, grid: dict) -> int:
"""octree cell id at manifest level `L`.
Reads h1[0:8] as LE uint64, modulo 8**L → canonical descent
address. Higher levels = finer cells; L declared by manifest.
"""
level = int(grid.get("level_max", 18))
cells = 1 << (3 * level) # 8 ** level
raw = int.from_bytes(h1[:8], "little")
return raw % cells
def _map_scale(h2: bytes, grid: dict) -> int:
lo = int(grid.get("level_min", 0))
hi = int(grid.get("level_max", 18))
span = hi - lo + 1
return lo + (h2[0] % span)
def _map_rotation(h3: bytes, delta_inv: int) -> tuple[int, int, int]:
"""Three integer Euler-equivalent indices at 1/delta_inv mrad step.
Reads three LE uint32 from h3[0:12], modulo (2π / step).
"""
step_count = int(6_283 * delta_inv // 1000) # 2π * 10^3 ≈ 6283 mrad
axes = []
for i in range(3):
u = int.from_bytes(h3[4 * i : 4 * (i + 1)], "little")
axes.append(u % step_count)
return tuple(axes) # type: ignore[return-value]
def _map_material(h4: bytes, palette_size: int) -> int:
u = int.from_bytes(h4[:4], "little")
return u % palette_size
def _map_behavior(h6: bytes, table_size: int) -> int:
u = int.from_bytes(h6[:4], "little")
return u % table_size
__all__ = ["ObjectRecord", "pi_star_w_object", "PI_STAR_OBJECT_VERSION"]
```
```python
# arborist/world/pi_star/__init__.py
"""``arborist.world.pi_star`` — v7-W π*_w canonical projections (#000070+).
Per ``arborist/world/__init__.py`` reserved-namespace roadmap:
pi_star/object.py — π*_w_object (#000070, this package's first kernel)
pi_star/relation.py — π*_w_relation (sibling ticket TBD)
pi_star/event.py — π*_w_event (sibling ticket TBD)
pi_star/place.py — π*_w_place (sibling ticket TBD)
pi_star/agent_trace.py — π*_w_agent_trace (sibling ticket TBD)
"""
```
(Mapper internals are illustrative; KAT vectors in
`bench/fixtures/spatial-anchor/known-answer-tests.jsonl` will pin the
exact byte-level behavior under review.)
## 5. Scope boundaries (what this ticket does NOT do)
- **No π*_w_relation kernel.** `H₅` is reserved raw; the `pair(A,B)`
operator is a separate ticket's decision.
- **No event / place / agent_trace kernels.** Separate tickets per
paper Part 4.
- **No ε-frontier kernels.** `world/frontier/*.py` is Phase 3.
- **No `world/manifest.py` validator.** Phase 1 accepts a dict with
manual `_require_manifest()`.
- **No `world/frame.py`.** Frame discipline (paper §2.3) is honored
via manifest declaration but not validated by an in-code kernel.
- **No `Document.extra` lat/lon hooks.** The prior
`/tmp/arborist-spatial-ontology-plan.md` proposed a
geographic-search feature on `Document.extra`; that is a
soft-channel consumer of π*_w outputs, not a substrate concern,
and lives in a different ticket if at all.
- **No new `audit_mode` token.** Substrate commitments are not
warrants.
- **No SQL schema change.** Phase 1 emits canonical bytes consumed
by callers; persistence to a `world_state_cells` table is Phase 5.
- **No CLI surface.** Phase 1 ships as a library kernel. CLI
(`arborist substrate world-object …`) is a follow-up.
- **No SLAM stack.** Paper §6 out-of-scope unchanged.
- **No ZK / privacy implementation.** Defers to #000016.
- **No mass-storage tier integration.** Cold-pack (#000061)
unchanged.
- **No bench harness wiring.** Phase 1 is KAT-tested; bench-qa
integration follows when relation + event land.
## 6. Cross-references
| Ref | Title | Relationship |
|---|---|---|
| #000013 | Spatial-temporal substrate (Merkle-AGI v7-W) | Parent. Closed doc-only 2026-05-09; this ticket implements the first verifier kernel under that namespace. Reopens #000013 status from `namespace_reserved` to `kernel_in_progress` upon land. |
| #000035 | PRG choice for φ_PRG (HMAC-SHA-512 KDF) | Primitive reused. Domain separation by dedicated seed; #000035 KAT freeze stays intact. |
| #000018 | Soft-hash covert channel | Hard-hash discipline inherited. Spatial-anchor outputs are integer cells (hard channel); locality indices (Morton / H3) would be soft and never enter proof path. |
| #000015 | π* cross-domain composition | Future: composing v9.8 language claims with v7-W spatial claims requires the composition theorem from #000015. Out of scope for #000070 but the registration pattern keeps the door open. |
| #000016 | ZK / privacy | Required before any non-public spatial-anchor deployment. Phase 1 fails closed on missing privacy class. |
| #000049 | Attribution-aware grounding check | Architectural sibling — split from #000048 because NLI raised a fresh `audit_mode` question that needed its own dav1d-review surface. Same shape as the §2.4 split-or-extend decision here. |
| v7-W paper | `docs/_source/merkle-agi-v7w-spatial-temporal.rst` (658 lines) | Specification this kernel implements. §A worked example informs default manifest shape. |
| v7 paper | `docs/_source/merkle-agi-dag-v7.rst` §9.10 / §9.10.1 | φ_PRG amendment context. Domain-separation argument inherits from §9.10. |
| Joseph framework | Memory: `joseph_trudojo_6dim_spatial_ontology.md` | Author attribution. The six-dimension `H₁..H₆` split is Joseph (@TrudoJo)'s. Substrate paper amendment under this ticket cites him. |
| Prior plan | `/tmp/arborist-spatial-ontology-plan.md` (2026-05-31, not in repo) | The plan this ticket replaces. Five-step §2 deletions captured in §7 below. |
## 7. Five-step alignment
1. **Requirements less dumb.** Joseph (@TrudoJo) authored the
framework; fox brought it in 2026-05-31 and decided which kernel
lands first. Names, not departments.
2. **Delete the part or the process.** ~40 % of the prior
`/tmp/arborist-spatial-ontology-plan.md` deleted before drafting:
- Geographic-search backend (encoding route — substrate confusion)
- `Document.extra` lat/lon hooks (different ticket if at all)
- `audit_mode = HYBRID` for spatial hits (convention-illegal)
- Geohash (subsumed by raw Morton)
- Quadtree as separate (octree at level-z=0)
- Hilbert at Phase 1 (deferred; not used by H₁ mapper)
- Five-tier "hash suite" framing (conflated hard vs soft hashes)
- `arborist/spatial/` namespace (violates topic-naming rule;
`world/pi_star/object.py` is the right home)
3. **Simplify.** One registry slot (`spatial-anchor-object@v1`); one
new seed; no new SQL; reuses #000035's `_expand`. ~150 LoC
excluding KATs + tests.
4. **Cycle time.** KATs ship with the projection — replay is the
test, no separate harness. Phase 1 is a single PR.
5. **Automate.** `arborist/pi_star/registry.py` already automates
`name@version` lookup; this ticket adds a row, not a mechanism.
## 7a. Pre-review empirical evidence
To shrink dav1d's review surface, ticket #000070 ships a pure-stdlib
empirical-validation bench **before** any kernel code lands. It runs
against `arborist.substrate.anchor_prg._expand` directly (no new module
required) and prototypes `split_anchor` + `map_position_octree` inline.
Run: `make bench-spatial-anchor` (~2 s, RNG-seed-pinned, byte-identical
across re-runs).
Source: `bench/spatial_anchor_validation.py`
Report: `bench/spatial_anchor_validation_results.md`
Bench results from the first run (2026-05-31, N=10000):
| Bench | Headline number | Verdict | Answers |
|---|---|---|---|
| §1 Avalanche (single-bit flip) | mean = 767.85 bits, z = -0.49 vs PRF null 768 | PASS | Q2 |
| §2 Cell-distribution uniformity (octree L=2,3,4) | \|z\| < 1.0 at every level | PASS | Q3 |
| §3 Collision vs birthday-bound (L=4,6,8,10) | obs/exp ratio = 0.989 / 1.038 at populated L | PASS | Q3, Q9 |
| §4 Cross-region independence (Pearson on all 15 pairs of H₁..H₆) | every pair < 2σ, none flag at 4σ | PASS | Q2 (§2.2 option A safe) |
| §5 Domain separation (Arm A distinct seeds vs Arm B shared seed) | Arm A: 767.91 bits independent · Arm B: **0.00 bits — collision class confirmed** | PASS | Q1 (§2.1 option A required) |
Numerical headlines:
- **Q1** (seed source): Arm B's exact-zero Hamming distance is the
measurable footgun the §2.1 option A discipline protects against.
- **Q2** (segmentation method): cross-region Pearson r in
[-0.018, +0.012] across 15 pairs, all sub-2σ — counter-mode block
independence holds empirically; fixed-offset slicing is safe.
- **Q3** (octree position mapper): uniform under chi² at L=2,3,4;
birthday-bound holds at L=4,6,8,10.
- **Q8** (endianness): inherited from #000035 by byte-identical reuse
of `_expand`; no separate test needed.
- **Q9** (adversarial KAT vectors): §3 surfaces the structural
importance of including `0x00 * 32`, `0xFF * 32`, and at least one
low-entropy hash engineered to map to cell 0 at the deployment's L
in the KAT set.
Remaining open questions (Q4 scope split, Q5 privacy default, Q6
audit_mode discipline, Q7 manifest validator timing, Q10 paper-amendment
wording) are non-empirical — design decisions that stay with dav1d's
review.
## 8. Open questions for dav1d
1. **§2.1 — dedicated seed vs domain-tag bump.** Recommendation A
(dedicated seed) preserves your 2026-05-11 #000035 final review.
Acceptable, or do you prefer the cleaner domain-tag separation
under a `PHI_PRG_VERSION` bump?
2. **§2.2 — fixed-offset slicing vs per-region nested HMAC.**
Recommendation A relies on counter-mode block independence —
the same PRF argument #000035 §4 used. Confirm the slicing
inherits the independence cleanly, or do we need a separate
per-region HMAC for paper-citation purposes?
3. **§2.3 — H₁ mapper choice.** Octree at Phase 1 matches paper
§2.1 + §A. Should we ship a second position mapper
(`spatial-anchor-h3@v1` or `spatial-anchor-morton@v1`) at Phase
1 to avoid registry churn later, or is one mapper per ticket the
right discipline?
4. **§2.4 — scope.** Object alone (sibling ticket for relation), or
object + relation in one drop? CLAUDE.md memory says don't
proliferate; #000049/#000048 says split when the audience
differs. Your call.
5. **§2.5 — privacy class default.** Recommendation A (fail-closed
on missing class) is the safest. Is requiring explicit
declaration acceptable, or does the worked-example's silent
`"public"` default need to ship as-is?
6. **§2.6 — `audit_mode` discipline.** Confirm that a spatial
commitment is structurally different from a verifier warrant and
that the ladder is not extended by Phase 1.
7. **§2.7 — manifest validator timing.** Phase 1 accepts a dict with
inline `_require_manifest()`. Acceptable to land
`world/manifest.py` as a follow-up ticket, or must the validator
land alongside the position kernel?
8. **§2.8 — endianness.** Confirm LE throughout matches your
2026-05-11 #000035 review (the `-le` suffix discipline).
9. **KAT count.** #000035 shipped 10 vectors. Phase 1 plan also
says 10. Larger? Specifically: should the KAT set include
adversarial cases (zero hash, all-ones hash, low-entropy hash,
`phi_prg` output reused as `split_anchor` input) to harden
against future-developer foot-guns?
10. **Substrate paper amendment wording.** Phase 1 land includes
a paragraph in `docs/_source/merkle-agi-v7w-spatial-temporal.rst`
introducing the six-dimension framework. Preferred wording for
@TrudoJo attribution? Default draft: "The six-dimension anchor
split formalized in this section follows the procedural-spatial
framework presented by Joseph (@TrudoJo) on 2026-05-31."
---
**Land sequence on go:**
1. Land this ticket file + `Next ID` bump + index row (this commit).
2. dav1d review pass.
3. fox go.
4. Implementation PR per §3.
5. Substrate-paper amendment in the same PR.
6. Memory update: flip `joseph_trudojo_6dim_spatial_ontology.md`
from "reference (cite when used)" to "reference (used in #000070,
landed `<sha>`)".
7. Reopen #000013 status `namespace_reserved``kernel_in_progress`.