feat(wikidata-hhtl): the N4 second-domain falsifier — 16ⁿ router + class-meta-DTO proven domain-independent on Wikidata#442
Conversation
Mandatory post-merge board update (merge a77e119): - STATUS_BOARD: 5 D-CLS rows In PR -> Shipped - PR_ARC_INVENTORY: prepend #441 entry (Added/Locked/Deferred/Docs/Confidence) — records the class-flies-above-SoA invariant, C2/N3, FieldMask-no-fold (Codex P2), carrier-methods (CodeRabbit), DOLCE-from-cache + class_id-reuse decisions - LATEST_STATE: prepend Contract-Inventory blockquote (class_view + class_resolver + class_signature surface, so a new session does not re-derive them) https://claude.ai/code/session_01R9AWgFa65uPnLyS2my2d2R
…FieldMask::inherit (Wikidata-HHTL slice 1) The downstream 16^n Abstammung bucket router #438 (D-ARM-14 P1) names but did not build: subClassOf nibble path, bit-shift O(1) addressing (root/child/basin/parent/is_ancestor_of). DOLCE-agnostic by construction (basin: u8 = dolce_id 0..3 resolved THROUGH the ontology cache per OD-DOLCE b31464d — never an embedded enum; matches both #441 dolce_id and #438 basin() orderings). + FieldMask::inherit (mask-inherits-as-delta; multi-parent = orthogonal facet bit in the same mask, NOT a 2nd path). Reuses #441 FieldMask; zero-dep preserved. The N4 second-domain falsifier for the D-CLS machinery: the Wikidata D-CLS triple (class_id, shape_hash, presence_bitmask) = (ClassId, StructuralSignature, FieldMask) — all #441. Convergent with D-ARM-14, firewall preserved (aerial = zero-dep proposer; contract/ontology = hub). 4 teeth-tests (bit-shift round-trip, depth cap + out-of-range nibble ignored, prefix reachability, multi-parent-is-a-facet-bit); 501 contract lib green; clippy -D warnings + fmt clean. Board: FINDING D-CLS<->D-ARM-14 reconciliation (EPIPHANIES) + D-WIKI-HHTL-1 row. https://claude.ai/code/session_01R9AWgFa65uPnLyS2my2d2R
…a-DTO generalises to Wikidata) The N4 second-domain falsifier (cognitive-risc-classes.md): routes a curated set of REAL Wikidata classes (Q5 human, Q215627 person, Q515 city, Q11424 film, Q5398426 tv-series, Q1656682 event) through the SAME machinery the D-CLS arc built for Odoo — proving the Wikidata D-CLS triple (class_id, shape_hash, presence_bitmask) = (ClassId, StructuralSignature, FieldMask) is domain-independent, not Odoo-overfit. Reuses (not re-grows): contract::hhtl::NiblePath (routing, basin = cache-resolved dolce_id u8, NO DOLCE enum on the path — OD-DOLCE), FieldMask (presence/facet-bitmask), StructuralSignature + contract::hash::fnv1a (shape-family key over the canonical property-set), and the #441 ClassView trait (WikidataClassView impls it unchanged). Falsification CONFIRMED on data (5 teeth-tests): corpus collapses to fewer shape-families (film ≡ tv-series share the AV-work shape), DOLCE→basin routing through the cache u8, triple shape domain-independent, ClassView resolves a Wikidata class with render_rows off-bits-skip (C2), subclass human⊂person inherits path (is_ancestor_of) + mask-as-delta. 245 ontology lib green; clippy -D warnings + fmt clean. Firewall preserved (hub side; aerial untouched). https://claude.ai/code/session_01R9AWgFa65uPnLyS2my2d2R
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughThis PR implements the Wikidata-HHTL "second-domain falsifier" by adding a nibble-based NiblePath router, a const FieldMask::inherit helper, ontology-side WikidataClass/WikidataClassView implementations with fixtures/tests, and governance/status and tech-debt records. ChangesWikidata HHTL Architecture
Sequence DiagramsequenceDiagram
participant CuratedCorpus
participant WikidataClassView
participant NiblePath
participant FieldMask
CuratedCorpus->>WikidataClassView: curated_wikidata_classes()
WikidataClassView->>NiblePath: build nibble_path from basin + subclass descent
WikidataClassView->>FieldMask: compute presence_mask from property ids
WikidataClassView->>WikidataClassView: produce dcls_triple(ClassId, StructuralSignature, FieldMask)
WikidataClassView->>WikidataClassView: render_rows(template, fields filtered by mask)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b6e3725c03
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| self.properties | ||
| .iter() | ||
| .map(|p| FieldRef::new(*p, *p)) | ||
| .collect() |
There was a problem hiding this comment.
Cap Wikidata fields to FieldMask width
When a WikidataClass carries more than 64 properties, this ClassView exposes more fields than FieldMask can address, violating the ClassView::field_count <= FieldMask::MAX_FIELDS contract. In that case presence_mask() only represents the first 64 positions while render_rows() still iterates the longer field list, so oversized real Wikidata classes will have properties silently skipped or, past usize→u8 wraparound in projection, aliased to lower bits. Please cap or reject the field list the same way the Odoo object_view() path does before building the view.
Useful? React with 👍 / 👎.
…442) A WikidataClass with > 64 properties overflowed the FieldMask contract: field_count() exceeded MAX_FIELDS, presence_mask() covered only the first 64, render_rows() iterated the longer field list, and i as u8 wrapped past 256 — aliasing a high property onto a low bit. Now both presence_mask() and field_refs() cap at FieldMask::MAX_FIELDS (the same discipline as the Odoo object_view() path), and the presence loop runs i in 0..min(len,64) so i as u8 can never wrap. Teeth-test: a 70-property class -> presence/field_count cap at 64, render yields 64 rows not 70, property 64+ never aliases onto a low bit. 6 wikidata_hhtl tests; clippy -D warnings + fmt clean. https://claude.ai/code/session_01R9AWgFa65uPnLyS2my2d2R
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@crates/lance-graph-contract/src/class_view.rs`:
- Around line 136-138: Add a focused unit test for the new FieldMask::inherit
API in the same file's #[cfg(test)] module: create a test that constructs two
FieldMask values (e.g., base and delta), calls inherit (FieldMask::inherit or
base.inherit(delta)), and asserts the result equals the bitwise OR of the two
masks and that the originals remain unchanged; place the test in class_view.rs
alongside other tests to ensure focused coverage of inherit behavior.
In `@crates/lance-graph-contract/src/hhtl.rs`:
- Around line 69-73: root() currently masks the basin with (basin & 0x0F) which
silently aliases out-of-range values; replace that masking with an explicit
validation: check that the basin value is < 16 and if not either return an
error/Option (change signature to Result<Self, Error> or Option<Self>) or
assert/panic (e.g., debug_assert!(basin < 16) or panic! for non-debug builds) so
invalid basin inputs are not silently folded; update the function body that
constructs Self { path: basin as u64, depth: 1 } and adjust callers if you
change the return type.
🪄 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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 5e2b1184-6e6b-41ee-8304-b662c915adaa
📒 Files selected for processing (9)
.claude/board/EPIPHANIES.md.claude/board/LATEST_STATE.md.claude/board/PR_ARC_INVENTORY.md.claude/board/STATUS_BOARD.mdcrates/lance-graph-contract/src/class_view.rscrates/lance-graph-contract/src/hhtl.rscrates/lance-graph-contract/src/lib.rscrates/lance-graph-ontology/src/lib.rscrates/lance-graph-ontology/src/wikidata_hhtl.rs
…o silent fold) + focused FieldMask::inherit test Two valid CodeRabbit findings: 1. (Major) NiblePath::root() folded an out-of-range basin via (basin & 0x0F), silently aliasing e.g. 16 -> basin 0 and misrouting ancestry. Now basin >= FAN_OUT returns Self::EMPTY (the 'no route' sentinel; basin() -> None) — consistent with child()'s out-of-range no-op and FieldMask's ignore-don't-fold discipline. Valid basins (0..15, dolce_id 0..3) are unaffected. Test asserts root(16)/root(99) == EMPTY, no alias to basin 0. 2. (Minor) FieldMask::inherit had only transitive coverage; added a focused unit test in class_view.rs: inherit == bitwise union, overlap not double-counted, EMPTY identity both directions, commutative, operands unmutated. 502 contract lib green; clippy -D warnings + fmt clean. https://claude.ai/code/session_01R9AWgFa65uPnLyS2my2d2R
…ecord #442 scale-freezes (D-ARM-14 review) The D-ARM-14 session's review of #442 (merge-worthy verdict) flagged two non-blocking 'name the freeze' items; acting on both: Flag 1 (the strong one) — NiblePath::child() saturated SILENTLY past MAX_DEPTH=16, so two distinct deep P279 chains truncated at 16 would collide on one path (is_ancestor_of/basin treat them as one). Same no-silent-aliasing class as the root()/FieldMask fixes. Added is_full() (the depth_exhausted flag) + try_child() -> Option (returns None instead of saturating), so the deferred 115M loader DETECTS the ceiling and switches to a ref instead of colliding. child() stays the saturating convenience, now documented to gate on is_full(). Flag 2 + minors — recorded as TD-WIKI-SCALE (TECH_DEBT, append-only): StructuralSignature u32 birthday ceiling (~77k shape-families — a #441 contract decision to widen to u64, WITH the deferred loader, not unilaterally here); signature() per-call Vec alloc; dolce_category_id default-ENDURANT-on-unknown. All fine at curated/Odoo scale; bite only at the 115M load. signature() doc now cites the u32 freeze. 503 contract + 246 ontology lib green; clippy -D warnings + fmt clean. Firewall preserved; the proposer-side dolce_id alignment remains the D-ARM-14 session's lane. https://claude.ai/code/session_01R9AWgFa65uPnLyS2my2d2R
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/TECH_DEBT.md:
- Line 16: The header "### TD-WIKI-SCALE (D-WIKI-HHTL / `#442`) — three
scale-freezes the N4 falsifier inherits" is an h3 under "Open Debt" but there is
no preceding h2, triggering the markdown heading-level warning; fix by either
promoting that line to h2 (replace leading ### with ##) or add a dated h2 above
the batch of recent entries (e.g., "## YYYY-MM-DD — Scale and Performance Debt")
so all subsequent h3s (including "TD-WIKI-SCALE", "TD-ARM-CARRIER-FORK",
"TD-RESONANCEDTO-DUP-1") are valid subsections and the file structure matches
the existing "Paid Debt" pattern.
🪄 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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: ac4da768-a485-4ac4-a9fb-2214c8425354
📒 Files selected for processing (3)
.claude/board/TECH_DEBT.mdcrates/lance-graph-contract/src/hhtl.rscrates/lance-graph-ontology/src/wikidata_hhtl.rs
🚧 Files skipped from review as they are similar to previous changes (2)
- crates/lance-graph-contract/src/hhtl.rs
- crates/lance-graph-ontology/src/wikidata_hhtl.rs
…ent, CodeRabbit #442) The file jumped h1 -> h3 (all debt entries are ### by convention), tripping markdownlint MD001 on the first entry. Promoting only my entry to h2 would make it an outlier vs the other ### entries; instead added one '## Open Debt' section header before the first entry, which silences MD001 file-wide AND keeps every entry consistent at h3. Pre-existing condition (inherited the first-h3 position on prepend), fixed minimally. https://claude.ai/code/session_01R9AWgFa65uPnLyS2my2d2R
…d emit + worked Wikidata example) Answers "how to use aerial + the 10000^2 splat + land on Wikidata-shaped HHTL": builds the proposer->hub seam end-to-end, verifiable standalone. (a) The OD-DOLCE alignment #442 deferred to this lane: - OntologyProjector::dolce_id() emits the stable dolce_id u8 (= basin nibble, already matching dolce_id::{ENDURANT=0,..}) — the proposer hands the hub the enum-free routing key; the IRI becomes a late-resolvable label (resolve-through-cache). + DolceCategory::from_index, + is_dolce flag. (b) The worked end-to-end example (tests/wikidata_landing.rs, --features landing): - splat top-k -> extract_rules recovers all 6 DOLCE basins -> lands each on the REAL lance-graph-contract::class_view::FieldMask (presence) + hash::fnv1a_str (the StructuralSignature value). The 16^n NiblePath router is inlined (annotated) until #442's contract::hhtl lands on main. - CONFIRMED on data: corpus collapses 6->5 shape-families (film Q11424 ≡ tv-series Q5398426, sig 0xad7fade7); human ⊂ person inherits path + mask-as-delta; basin preserved down the subclass path. - Firewall intact: the lib never imports the hub. The example uses an opt-in dev-dep on the zero-dep lance-graph-contract (the exact pattern jc uses for bridge examples), gated behind the `landing` feature so the default build stays zero-dep. Only the (ClassId, signature, FieldMask) triple + dolce_id u8 cross the seam. Verified: default (zero-dep) 42/42 + clippy -D warnings clean; --features landing -> wikidata_landing green + clippy clean. Run: cargo test --manifest-path crates/lance-graph-arm-discovery/Cargo.toml \ --features landing --test wikidata_landing -- --nocapture Remaining (documented): the real jc/blasgraph splat producing the lists; the ndjson->WikidataClass loader; swap the inline nibble routing for contract::hhtl::NiblePath once #442 merges; gated on D-ARM-7 (jc::jirak). https://claude.ai/code/session_012SorR8UbtEvYmbX8cXftj7
…:NiblePath (#442 merged) The Phase-2 worked example reproduced NiblePath's bit-shift addressing inline because contract::hhtl wasn't on main yet. #442 merged, so tests/wikidata_landing.rs now uses the REAL contract::hhtl::NiblePath::{root,child,basin,is_ancestor_of,depth} + FieldMask::inherit — the landing is on the canonical 16^n router, not a stand-in. Rebased onto post-#442 main (415971a). default 42/42 + clippy clean; --features landing wikidata_landing green (real NiblePath depths: person 0x1 d2 → human 0x12 d3; film≡tv collapse holds). https://claude.ai/code/session_012SorR8UbtEvYmbX8cXftj7
Wikidata-HHTL: the N4 falsifier for the D-CLS class-meta-DTO (hub side)
cognitive-risc-classes.mdN4: the class-meta-DTO that #441 (D-CLS) built for Odoo —FieldMaskpresence +StructuralSignatureshape +ClassViewresolution — must generalize beyond Odoo or it is overfit to one ERP. Wikidata is the falsifier domain. This PR routes a curated set of real Wikidata classes through the same machinery and confirms, on data, that the "D-CLS triple"(class_id, shape_hash, presence_bitmask)=(ClassId, StructuralSignature, FieldMask)is domain-independent.It is also the downstream 16ⁿ bucket router that merged #438 (D-ARM-14 Phase 1) explicitly named as remaining — built here on the hub side, convergent with that arc, firewall intact.
Slices (2)
contract::hhtl, zero-dep) —NiblePath: the 16ⁿ Abstammung (subClassOf/P279) bucket router, bit-shift O(1) addressing (root/child/basin/parent/is_ancestor_of/packed). DOLCE-agnostic by construction: takes abasin: u8; it has zero DOLCE knowledge. +FieldMask::inherit(mask-inherits-as-delta). Reuses feat(class-meta-dto): D-CLS arc — classes as SoA-view with presence bitmask (FieldMask + ClassView + structural-signature + render) #441FieldMask.ontology::wikidata_hhtl) —WikidataClass(curated real QIDs) +WikidataClassView(impls the feat(class-meta-dto): D-CLS arc — classes as SoA-view with presence bitmask (FieldMask + ClassView + structural-signature + render) #441ClassViewunchanged). ReusesNiblePath(routing),FieldMask(presence),StructuralSignature+contract::hash::fnv1a(shape-family key over the canonical property-set), and theClassViewtrait.Through-the-cache (OD-DOLCE, the agreed resolution of the
DolceCategoryduplication)The duplicated
DolceCategory(arm-discovery discovery-side vs ontology cache-side) is not dedup'd into a third canonical copy. It is dissolved at the resolution layer: every class carries the cache-resolveddolce_idu8 (0..3), andbasin = dolce_id— no DOLCE enum on the Wikidata path (#441b31464d"DOLCE-from-cache, dissolves 6v4").basin0..3agrees with both #441'sdolce_id::{ENDURANT=0,PERDURANT=1,QUALITY=2,ABSTRACT=3}and #438's discovery-sideDolceCategory::basin()ordering — both sides of the firewall share the nibble without either embedding the enum.Firewall (convergent with D-ARM-14, no collision)
arm-discovery::aerialstays the zero-dep proposer.contract/ontologyownFieldMask/signature/ClassView+ the router. The mapping(class_id, shape_hash, presence_bitmask) = (ClassId, StructuralSignature, FieldMask)is the seam where the two arcs meet.Falsification — CONFIRMED on data (not asserted)
The 5
wikidata_hhtlteeth-tests are the N4 gate:film (Q11424) ≡ TV series (Q5398426)share oneStructuralSignature(the AV-work shape); 6 classes → 5 families. The classes.md:42 collapse property holds on Wikidata.(ClassId, StructuralSignature, FieldMask)types as Odoo; one present bit per property.ClassViewresolves a Wikidata class unchanged —render_rowsskips off-bits (C2 presence-only).human ⊂ personinherits path + mask-as-delta —is_ancestor_of+FieldMask::inherit; the DOLCE basin is preserved down the subclass path.Verification
cargo test -p lance-graph-contract→ 501 (+4 hhtl);-p lance-graph-ontology→ 245 (+5 wikidata_hhtl).-D warnings+ rustfmt clean on all new files.Deferred (follow-ups, not this PR)
The 115M-entity streaming load (skeleton + basins + CAM-dedup + thin rows — its own plan,
wikidata-hhtl-load.md); the live registry-backedWikidataClassView(curated fixture today, mirroring the D-CLS-AUDIT pattern); naming the discovered shape-families; the proposer-sideaerial::ontology::DolceCategory→emit-dolce_idalignment (the D-ARM-14 session's lane).Board hygiene (same branch)
This branch also carries the post-merge hygiene for #441 (commit
3a5d836: PR_ARC entry, LATEST_STATE inventory, D-CLS rows → Shipped) which had not yet reached main; the cross-arc FINDING D-CLS↔D-ARM-14 (EPIPHANIES); and the two D-WIKI-HHTL STATUS_BOARD rows.https://claude.ai/code/session_01R9AWgFa65uPnLyS2my2d2R
Generated by Claude Code
Summary by CodeRabbit
New Features
Documentation