Skip to content

Commit a011736

Browse files
authored
Merge pull request #490 from AdaWorldAPI/claude/wire-canonical-node-lock
feat(contract): canonicalise #489 — wire-in + self-describing Display + retire Phase-A wrapper
2 parents 1af2a45 + e806058 commit a011736

6 files changed

Lines changed: 58 additions & 403 deletions

File tree

.claude/board/AGENT_LOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2026-06-13 — #489 canonicalised: wire-in + self-describing Display + retire Phase-A wrapper
2+
3+
**bardioc cross-session.** Operator pin: *"#489 is canonical."* Audited OGAR/CLAUDE.md P0 against `canonical_node.rs` group-by-group. Key (classid·HEEL·HIP·TWIG·family·identity = 8·4·4·4·6·6 hex) matches exactly; RFC-WAIVED matches ("No UUID ceremony"); 3×4 uniform tiers match (each u16; tier-of-level = `level >> 2`); 16-byte EdgeBlock at fixed offset = row-layout analogue of the zero-fallback ladder (default class's default ClassView reserves it, registry-resolved opt-out for non-default classes, "reserve-don't-reclaim" at row level). **One gap closed:** canon mandates *"every printed GUID is self-describing at sight"* via the dash-groups, wrapper had no `Display`. Added `impl Display for NodeGuid` emitting canonical `{classid:08x}-{heel:04x}-{hip:04x}-{twig:04x}-{family:06x}{identity:06x}` (LE in-memory bytes folded through the accessors so hex print is canon-ordered regardless). +2 Display tests. **Phase-A wrapper retired in the same PR** (operator: *"delete #480 from your mind"*): `identity.rs` deleted (UUIDv8 NodeGuid + RFC ceremony bits + IDENTITY_LAYOUT_VERSION + SHAPE_HASH_BITS/LOCAL_BITS — all canon-incompatible per *"wrappers adapt to the canon, never the reverse"*); `pub use identity::{NodeGuid, IDENTITY_LAYOUT_VERSION}` → `pub use canonical_node::{EdgeBlock, NodeGuid, NodeRow}`; `pub mod identity;` removed. Two stale doc references reworded: `hhtl.rs:192` (`from_packed` now a general HHTL utility, not identity::NodeGuid-specific), `lance-graph-ontology/src/registry.rs:405` (`niblepath_of` now points at the canon's `classid·HEEL·HIP·TWIG` resolution). `cargo test -p lance-graph-contract --lib`: **594/594 green** (−10 retired UUIDv8 tests, +2 Display, +8 wire-in canonical_node tests now visible); `cargo check -p lance-graph-ontology`: clean (5 pre-existing `oxrdf::Subject` deprecation warnings, untouched files); `cargo clippy -p lance-graph-contract --all-targets -- -D warnings`: clean. Anchored on #482 (GUID canon) + #489 (canonical_node) + OGAR/CLAUDE.md P0 (the canon itself, *"wrappers audited against this canon group-by-group — never the reverse"*).
4+
15
## 2026-06-11 — tombstone commit: emission artifacts removed per PR #477 follow-up
26

37
**Main thread (Fable, session splat3d-cpu-simd-renderer).** Executed the PR #477 documented follow-up (the "what does NOT exist" table → source reality): removed `CollapseGateEmission` from `lance-graph-contract::collapse_gate` (+ lib.rs re-export; `MailboxId`/`MergeMode`/`GateDecision` survive), removed `MailboxSoA::emit()`, renamed `last_emission_cycle` → `last_active_cycle`, added in-place `consume_firing(row)` successor (same threshold + same-cycle-idempotency semantics, no carrier object), reworded 4 stale doc references (kanban/episodic_edges/witness_tombstone/mailbox_soa header), superseded the CLAUDE.md Baton-scoping block, fixed cycle-coherent-soa-snapshot-v1 D-SOA-SNAP-1/2 to generic `SnapshotProvider::Column` (closes #477 CodeRabbit Critical — contract stays zero-dep), closed TD-COLLAPSE-GATE-SMALLVEC-1 as moot. Verified #477 codex P2 (`verify_layout` ColumnOutOfBounds) already fixed on main with regression test. Tests: contract 594 (−8 emission, +2 gate/merge), driver 85 (emit tests → consume tests, +1 OOB), clippy clean, workspace check clean. Commit: in PR.

crates/lance-graph-contract/src/canonical_node.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,30 @@ impl NodeGuid {
133133
}
134134
}
135135

136+
/// Canonical self-describing print: `classid-HEEL-HIP-TWIG-family·identity`.
137+
///
138+
/// The dash-groups ARE the semantic delimiters — every printed GUID is
139+
/// self-describing at sight (OGAR canon, P0). `{:08x}-{:04x}-{:04x}-{:04x}-{:06x}{:06x}`
140+
/// renders the canonical 8-4-4-4-12 hex layout regardless of in-memory byte
141+
/// order (the field accessors fold LE bytes into u32/u16/u24 first).
142+
impl core::fmt::Display for NodeGuid {
143+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
144+
let h = u16::from_le_bytes([self.0[4], self.0[5]]);
145+
let p = u16::from_le_bytes([self.0[6], self.0[7]]);
146+
let t = u16::from_le_bytes([self.0[8], self.0[9]]);
147+
write!(
148+
f,
149+
"{:08x}-{:04x}-{:04x}-{:04x}-{:06x}{:06x}",
150+
self.classid(),
151+
h,
152+
p,
153+
t,
154+
self.family(),
155+
self.identity(),
156+
)
157+
}
158+
}
159+
136160
/// 16-byte canonical edge block: 12 in-family + 4 out-of-family.
137161
///
138162
/// Canonical, not mandatory: the 16 bytes are ALWAYS reserved (zeroed when unused).
@@ -233,4 +257,25 @@ mod tests {
233257
fn new_panics_on_identity_overflow() {
234258
let _ = NodeGuid::new(0, 0, 0, 0, 0, 0x0100_0000);
235259
}
260+
261+
#[test]
262+
fn display_is_canonical_self_describing() {
263+
// Canon (OGAR P0): xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (8-4-4-4-12 hex);
264+
// groups = classid · HEEL · HIP · TWIG · family·identity.
265+
let g = NodeGuid::new(0xDEAD_BEEF, 0x1111, 0x2222, 0x3333, 0x00_00AB, 0x00_00CD);
266+
let s = g.to_string();
267+
assert_eq!(s, "deadbeef-1111-2222-3333-0000ab0000cd");
268+
assert_eq!(s.len(), 36, "8-4-4-4-12 + 4 hyphens");
269+
for i in [8usize, 13, 18, 23] {
270+
assert_eq!(s.as_bytes()[i], b'-', "hyphen at {i}");
271+
}
272+
}
273+
274+
#[test]
275+
fn display_zero_default_is_all_zeros() {
276+
// Zero-fallback ladder visible at sight: classid + family == 0 prints
277+
// as ...0...-...0... with identity-only discrimination.
278+
let g = NodeGuid::local(0x00_00CD);
279+
assert_eq!(g.to_string(), "00000000-0000-0000-0000-0000000000cd");
280+
}
236281
}

crates/lance-graph-contract/src/hhtl.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,8 @@ impl NiblePath {
189189
}
190190

191191
/// Reconstruct a path from its raw packed `(path, depth)` — the inverse of
192-
/// [`packed`](NiblePath::packed). Used by `identity::NodeGuid` to round-trip
193-
/// the routing-prefix it stores.
192+
/// [`packed`](NiblePath::packed). General HHTL utility for round-tripping
193+
/// a routing path through its packed `(u64, depth)` form.
194194
///
195195
/// Returns `None` if `depth > MAX_DEPTH`, or if `path` has bits set above the
196196
/// `depth` nibbles (an inconsistent pack — leading nibbles must be the route,

0 commit comments

Comments
 (0)