refactor(contract): reusable facet module — content-blind 8:8 substrate + zero-cost reinterpret#614
Conversation
… + zero-cost reinterpret Follow-up to #613. FacetTier/FacetCascade are a content-blind *reading*, not part of the operator-LOCKED node layout, so they belong in their own module rather than canonical_node. Extracted to src/facet.rs; canonical_node re-exports both for the historical path. No behaviour change to the existing API. Rounded out the reusable lane API (the one-register / four-lane design): - as_u128 / from_u128 single-register (128-bit) view - rows() the 4 dword rows: {domain}{schema} / HEEL:HIP / TWIG:LEAF / family:identity (vpcmpeqd lane) - prefix_distance / shared_prefix_tiles the granularity-free LCP redout (vpxor + tzcnt; 8:8 vs nibble is a free >> on the count, measured) - row_match_mask which of the 4 rows match (vpcmpeqd + vmovmskps) - as_bytes / ref_from_bytes ZERO-COST reinterpret (repr(C, align(16))): as_bytes lowers to `mov rax, rdi` (a literal no-op, verified in asm), so a &FacetCascade over the slab reads fields/lanes with no decode. ref_from_bytes is the checked-aligned borrow (mirrors node_rows_from_le_bytes; None if unaligned). repr C -> C, align(16) (0 padding; size stays 16) makes the facet an explicit 128-bit register value (aligned SIMD loads + the no-op reinterpret). Board: LATEST_STATE Contract Inventory entry. Lab-test write-up deferred. 741 lib tests green (default + guid-v3-tail), clippy -D warnings + fmt clean. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TzqvDqbFRzyx17EkLKBoZF
|
Warning Review limit reached
More reviews will be available in 40 minutes and 32 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe PR adds a public ChangesFacet module extraction
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.claude/board/LATEST_STATE.md:
- Around line 143-144: The blockquote in LATEST_STATE.md is broken by an
unquoted blank line, causing the entry to split and trigger MD028. Keep the
inventory note contiguous by either removing the blank line or turning it into a
quoted blank line so the quoted section remains a single block. Refer to the
Markdown block starting with the `2026-06-25 — MODULARIZED` entry and ensure the
`>` prefix is preserved consistently.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 7b97c2ea-2f4f-4a72-92ae-c0882f52a4f1
📒 Files selected for processing (4)
.claude/board/LATEST_STATE.mdcrates/lance-graph-contract/src/canonical_node.rscrates/lance-graph-contract/src/facet.rscrates/lance-graph-contract/src/lib.rs
CodeRabbit flagged MD028 on #614 — the blank line between the new facet entry and the #613 entry breaks the blockquote. Quote it (`>`) so the two entries stay in one blockquote, the fix CodeRabbit suggested. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TzqvDqbFRzyx17EkLKBoZF
Same MD028 fix as #614: quote (`>`) the blank line between the new Phase-1 entry and the #613 entry so they stay one blockquote. Preempts the identical CodeRabbit nit on this PR. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TzqvDqbFRzyx17EkLKBoZF
…bstrate The doc was authored without awareness that V3 shipped (#613/#614 FacetCascade, #615 mint_for). Three alignments; the AST-as-(part_of:is_a) idea is preserved: - Slot-count "open gate" CLOSED: facet.rs FacetCascade = facet_classid(4) | 6x(8:8) = 6 tiers (HEEL.HIP.TWIG.LEAF.family.identity), const_-asserted = the full-key 6-pair/12-slot answer; the key carries the 4-tier routing prefix (NiblePath::from_guid_prefix_v3), the complete address is the FacetCascade value facet. Nothing left to ratify. - Carrier NOT missing: FacetCascade is content-blind and already lists (part_of:is_a) as a consumer projection (hi_chain=part_of, lo_chain=is_a). Only the deterministic rank-minter is genuinely new; it writes into existing tiers (no new type/layout). - classid row is 0x1000_0700-shaped (shipped CLASSID_OSINT_V3: marker hi u16, domain on lo u16); its (part_of:is_a) ordering flagged OPEN pending the operator's Canon:Custom correction. Doc-only, CONJECTURE status retained. Claude-Session: https://claude.ai/code/session_01TANd15SECEb1Gm4cpaRVD9
What
Follow-up to #613. Extracts
FacetTier/FacetCascadeout of the operator-LOCKEDcanonical_nodeinto a dedicated, reusablefacetmodule — they are a content-blind reading over borrowed bytes, not part of the node layout, so this is the correct factoring.canonical_nodere-exports both for the historical path; no behaviour change to the existing API.This is the optimized reusable V3-shaped pattern that the V3 value-tenant migration builds on.
Reusable lane API (one register, four lenses)
The 16-byte facet (
facet_classid(4) | 6×(8:8)) is#[repr(C, align(16))]— one 128-bit register, addressable four ways, each a single op:u32×4)rows(),row_match_mask()vpcmpeqd+vmovmskpsu16×8).tiers,hi_chain/lo_chainvpcmpeqw/pshufbprefix_distance/shared_prefix_tilesvpxor+tzcnt(granularity-free)FacetTier::mortonas_u128/from_u128vmovdquRow 0 is the
facet_classid({domain}{schema}); rows 1–3 are the cascade pairs (HEEL:HIP/TWIG:LEAF/family:identity). Transpose-native for AoS→SoA batch sweeps.Zero-cost reinterpret
as_bytes/ref_from_bytesareSAFETY-commented reinterprets (mirroringnode_rows_from_le_bytes). Verified in asm:as_byteslowers tomov rax, rdi— a literal no-op — and reading a field through it is a single load. So a&FacetCascadeheld over the slab reads every field/lane with zero decode.Content-blind: only the consumer projects meaning (
part_of:is_a/ 256:256 palette centroid /group:member/column:row/ concatenatedu16…); every reading amortizes to one 2bit×2bit Morton tile cascade.Tests / gates
Additive, zero-dep. 741 lib tests (default +
guid-v3-tail), clippy-D warnings+ fmt clean. Lab-test write-up deferred. Board:LATEST_STATEContract Inventory entry.🤖 Generated with Claude Code
https://claude.ai/code/session_01TzqvDqbFRzyx17EkLKBoZF
Generated by Claude Code
Summary by CodeRabbit