feat(cockpit): put the dual-use dimensions in the schema as facet edges#44
Conversation
The schema was a disconnected legend. The harvest defines all 12 SchemaAxis nodes and their SchemaValue leaves (VALID_FOR), but emits ZERO edges from any entity to a SchemaValue -- so an entity's "militaryUse = Intelligence" had no path to the Intelligence value sitting on the militaryUse axis. The 0x0700 ClassView is empty + display-only (it renders one entity's fields on click; it cannot emit shared graph edges), and the value tenant (#43) is a hot-scan twin, not graph structure. "In the schema" means traversable edges. Fix: emit entity -> SchemaValue facet edges (the harvest's own faceted graph, model.rs pattern #1, that its cypher never emitted). - entity_facet_edges() in osint_gotham.rs: per-axis edges (rel 10..15: militaryUse/civicUse/airo:type/MLType/purpose/capacity) from each node's facet props to the matching SchemaValue (keyed by value string); compound values comma-split. Emitted in osint_soa_bytes after the harvest edges. - OsintGraph.tsx: REL_NAME/REL_COLOR for 10..15 + a dimension-layer toggle (the "family concepts" can be hidden via vis hidden, no relayout). - test facet_edges_wire_entities_to_schema_values (5 edges, compound split, no spurious sources); logic verified standalone; cockpit npm build green. This supersedes the weaker "decode tenant into tooltips" Phase 2. The tenant stays as the hot-scan mirror; these edges are the schema structure. Now a value node shows every entity that shares it (the "same tool" / boomerang traversal). RE-BAKE REQUIRED: the edges are inert until osint_scene.soa is regenerated (cargo test -p cockpit-server -- --ignored bake_osint_soa), which needs the full enriched harvest at /home/user/aiwar-neo4j-harvest and a machine that can compile cockpit-server (lance 7 + datafusion -- disk-infeasible in the sandbox). Plan: claude-notes/plans/2026-06-23-aiwar-dual-use-value-tenant.md Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TzqvDqbFRzyx17EkLKBoZF
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Warning Review limit reached
More reviews will be available in 30 minutes and 41 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 refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses rolling per-developer review limits. Reviews become available again as older review attempts age out of the rolling limit 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 ChangesOSINT Facet Dimension Edge Feature
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 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 |
|
Caution Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted. Error details |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
cockpit/src/OsintGraph.tsx (1)
60-60: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winBound facet classification to the declared facet code range.
Line 60 currently treats any
r >= 10as dimension-layer relation. Making this explicit to10..15avoids accidental coupling if new non-facet relation codes are added later.Suggested refactor
-const isFacetRel = (r: number) => r === 8 || r >= 10; +const isFacetRel = (r: number) => r === 8 || (r >= 10 && r <= 15);🤖 Prompt for 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. In `@cockpit/src/OsintGraph.tsx` at line 60, The isFacetRel function in OsintGraph.tsx currently treats any relation code r >= 10 as a facet relation with no upper bound, which could cause incorrect classification if new non-facet relation codes are added later. Change the condition from r === 8 || r >= 10 to explicitly bound the range to r === 8 || (r >= 10 && r <= 15) to restrict facet classification to the actual facet code range of 10 through 15.
🤖 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 `@cockpit/src/OsintGraph.tsx`:
- Around line 605-614: The setDims function defined at line 610 is never invoked
during initialization, which can cause the graph visualization to be out of sync
with the showDims toggle state. After defining the setDims function in the
dimension layer setup (after the lines defining schemaNodeIds, schemaEdgeIds,
and the setDims function itself), immediately invoke setDims with the current
showDims value to apply the dimension visibility state to the graph upon
initialization.
---
Nitpick comments:
In `@cockpit/src/OsintGraph.tsx`:
- Line 60: The isFacetRel function in OsintGraph.tsx currently treats any
relation code r >= 10 as a facet relation with no upper bound, which could cause
incorrect classification if new non-facet relation codes are added later. Change
the condition from r === 8 || r >= 10 to explicitly bound the range to r === 8
|| (r >= 10 && r <= 15) to restrict facet classification to the actual facet
code range of 10 through 15.
🪄 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: 83bcaf5e-b9a5-4c76-998f-952cd1d44f0c
📒 Files selected for processing (3)
claude-notes/plans/2026-06-23-aiwar-dual-use-value-tenant.mdcockpit/src/OsintGraph.tsxcrates/cockpit-server/src/osint_gotham.rs
- apply setDims(showDims) on (re)build so a toggle that landed before the network/apiRef existed can't leave the button "off" while dims still render (CodeRabbit: functional-correctness, minor). - bound isFacetRel to r === 8 || (r >= 10 && r <= 15) so future non-facet rel codes aren't misclassified as the dimension layer (CodeRabbit: nitpick). cockpit npm build green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TzqvDqbFRzyx17EkLKBoZF
The served OSINT asset predated PR #44's entity->SchemaValue facet edges (rel 10-15), so the dual-use dimension cluster (127 SchemaValue + 12 SchemaAxis) rendered as a 139-node island: connected only to itself via VALID_FOR, touching the entity graph at zero points. In the cockpit it floated free regardless of the dimensions toggle. cockpit-server's own re-bake OOMs at the disk cap (lance+datafusion+arrow+ deno/V8), so lift the pure bake (aiwar-ingest + zero-dep lance-graph- contract, no heavy closure) into a light tool crate, osint-bake, and regenerate the asset through the REAL Rust path -- not a Python splice, which would have diverged (the real bake emits 431 facet edges; an earlier label-join estimate said 438). Verified by decoding the bytes (before -> after): - nodes 920 unchanged, GUID section byte-identical - edges 3344 -> 3775 (+431 facet edges, rel 10-15; 0 originals changed) - dimension<->entity bridges: {} -> System 297, Stakeholder 122, Hist 12 - BFS from a System now reaches 118/127 SchemaValues, 10/12 SchemaAxes => the dimensions share the entity graph's connected component The 12 SchemaAxis nodes are the family/category nodes; the facet edges make them connective tissue (entity -> value -> VALID_FOR -> axis) rather than a detached legend. osint-bake's bake is verbatim-identical to osint_gotham.rs's (single source of truth until cockpit-server delegates to it -- deferred; that edit needs a cockpit-server build to verify, blocked by the disk cap). Builds clean, 7/7 tests pass, clippy-clean. cockpit-server itself is untouched. Incidental: osint_gotham.rs's soa_bytes_have_a_parseable_header test hard-equates byte length to the fixed records and is stale (predates the OSO1 label tail); corrected in the mirror, original still needs the fix. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TzqvDqbFRzyx17EkLKBoZF
The bug (your screenshots)
The dimensions weren't in the schema, and the family-adapter-as-model ↔ ClassView path couldn't put them there. Diagnosed in the harvest cypher:
SchemaAxisnodes exist (incl.purpose_vair,output_airo,impact_vair) with theirSchemaValueleaves viaVALID_FOR.SchemaValue. SoAnduril'smilitaryUse = Intelligencehad no path to theIntelligencevalue sitting right on themilitaryUseaxis. The schema was a disconnected legend.0x0700ClassViewis empty + display-only — it renders one entity's fields when you click it; it cannot emit the shared graph edges that make a dimension traversable. And the value tenant from feat(cockpit): aiwar dual-use enrichment as a value tenant on the OSINT:Aiwar class #43 is a hot-scan twin, not graph structure. "In the schema" = edges.The harvest's own
model.rscalls this the faceted graph ("nodes belong to multiple overlapping taxonomies", pattern #1) — but the cypher never emitted the membership edges. That's the real gap, upstream of the tenant.The fix
Emit
entity → SchemaValuefacet edges during the SoA bake.entity_facet_edges()(osint_gotham.rs): for each node carrying a dual-use facet, an edge (rel10..15=militaryUse/civicUse/airo:type/MLType/purpose/capacity) to the matchingSchemaValue(keyed by value string; compound values comma-split). Emitted inosint_soa_bytesafter the harvest edges.OsintGraph.tsx:REL_NAME/REL_COLORfor10..15+ a◇ dimensionstoggle that hides the dimension layer (cls 5/6 nodes +VALID_FOR+ facet edges) via vishidden— no relayout, so the "family concepts" drop to a clean entity graph and back.Now the dimensions do work: walk
Anduril → its militaryUse/civicUse/airo values, and walk a value → every entity that shares it — the "same tool" / boomerang traversal (everycivicUse = Policingsystem, everyAIDeployer ∩ AISubjectactor). The tenant stays as the hot mirror; these edges are the schema.Verification
facet_edges_wire_entities_to_schema_values: 5 edges, compound split (a System → bothcivicUsevalues; a boomerang stakeholder → both airo roles), no spurious sources. Logic also verified standalone.cd cockpit && npm run build— green (tsc + vite).osint_soa_bytessize-invariant test still holds (edge count + bytes grow together; thesample()fixture has noSchemaValuenodes so it's unaffected).cockpit-servercrate locally — its closure (lance 7 + datafusion + arrow + aws) exhausts the dev-sandbox disk. CI / Railway is the integration gate.The facet edges are inert until
osint_scene.soais regenerated:This needs (a) a machine that can compile cockpit-server, and (b) the full enriched harvest at
/home/user/aiwar-neo4j-harvest— not the 221-nodepublic/aiwar_graph.jsonfallback, which has noSchemaValuenodes to link to. After re-baking, confirm node count is unchanged and the facet edges are present.Plan:
claude-notes/plans/2026-06-23-aiwar-dual-use-value-tenant.md(Phase 2 corrected).🤖 Generated with Claude Code
https://claude.ai/code/session_01TzqvDqbFRzyx17EkLKBoZF
Generated by Claude Code
Summary by CodeRabbit
Release Notes
New Features
Tests