Skip to content

feat(cockpit): put the dual-use dimensions in the schema as facet edges#44

Merged
AdaWorldAPI merged 2 commits into
mainfrom
claude/aiwar-facet-edges
Jun 23, 2026
Merged

feat(cockpit): put the dual-use dimensions in the schema as facet edges#44
AdaWorldAPI merged 2 commits into
mainfrom
claude/aiwar-facet-edges

Conversation

@AdaWorldAPI

@AdaWorldAPI AdaWorldAPI commented Jun 23, 2026

Copy link
Copy Markdown
Owner

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:

  • All 12 SchemaAxis nodes exist (incl. purpose_vair, output_airo, impact_vair) with their SchemaValue leaves via VALID_FOR.
  • But zero edges go from any entity to a SchemaValue. So Anduril's militaryUse = Intelligence had no path to the Intelligence value sitting right on the militaryUse axis. The schema was a disconnected legend.
  • The 0x0700 ClassView is 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.rs calls 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 → SchemaValue facet edges during the SoA bake.

  • entity_facet_edges() (osint_gotham.rs): for each node carrying a dual-use facet, an edge (rel 10..15 = militaryUse / civicUse / airo:type / MLType / purpose / capacity) 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 ◇ dimensions toggle that hides the dimension layer (cls 5/6 nodes + VALID_FOR + facet edges) via vis hidden — 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 (every civicUse = Policing system, every AIDeployer ∩ AISubject actor). The tenant stays as the hot mirror; these edges are the schema.

Verification

  • New test facet_edges_wire_entities_to_schema_values: 5 edges, compound split (a System → both civicUse values; a boomerang stakeholder → both airo roles), no spurious sources. Logic also verified standalone.
  • cd cockpit && npm run build — green (tsc + vite).
  • The osint_soa_bytes size-invariant test still holds (edge count + bytes grow together; the sample() fixture has no SchemaValue nodes so it's unaffected).
  • Not built as the full cockpit-server crate locally — its closure (lance 7 + datafusion + arrow + aws) exhausts the dev-sandbox disk. CI / Railway is the integration gate.

⚠️ Re-bake required

The facet edges are inert until osint_scene.soa is regenerated:

cargo test -p cockpit-server --bin q2-cockpit -- --ignored bake_osint_soa

This needs (a) a machine that can compile cockpit-server, and (b) the full enriched harvest at /home/user/aiwar-neo4j-harvestnot the 221-node public/aiwar_graph.json fallback, which has no SchemaValue nodes 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

    • Added a dimensions toggle button to the OSINT graph visualization, allowing users to show or hide dimension-related nodes and edges in the graph view.
  • Tests

    • Added test coverage for the new facet edge generation functionality to ensure proper wiring of entity relationships to schema values.

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
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@AdaWorldAPI, we couldn't start this review because you've reached your PR review rate limit.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ecc845df-24c4-4b48-bfe1-10152d8f3bae

📥 Commits

Reviewing files that changed from the base of the PR and between 86dd48e and 83561c3.

📒 Files selected for processing (1)
  • cockpit/src/OsintGraph.tsx
📝 Walkthrough

Walkthrough

The PR adds entity → SchemaValue facet edges to the OSINT SoA binary encoding (osint_gotham.rs), introducing relation constants, a FACET_AXES property map, and an entity_facet_edges helper that handles comma-split multi-values. The frontend (OsintGraph.tsx) gains facet relation rendering metadata and a "◇ dimensions" toggle that hides/shows the new dimension layer via vis-network hidden flags. A design plan document is also updated to record the corrected approach and Phase 3 follow-ups.

Changes

OSINT Facet Dimension Edge Feature

Layer / File(s) Summary
Rust facet edge generation and SoA wiring
crates/cockpit-server/src/osint_gotham.rs
Adds REL_FACET_* constants, FACET_AXES mapping, and entity_facet_edges() that scans non-SchemaValue nodes, matches property values (including comma-split) against SchemaValue node ids, and emits one typed 5-byte edge per match. osint_soa_bytes appends these into the existing edges buffer. Unit test facet_edges_wire_entities_to_schema_values verifies correct wiring, compound airo:type splitting, and that SchemaValue nodes do not emit edges.
OsintGraph dimension layer rendering and toggle UI
cockpit/src/OsintGraph.tsx
Extends REL_NAME/REL_COLOR tables with facet codes; adds isFacetRel helper. GraphApi gains setDims(show: boolean). Component adds showDims state (default true), implements setDims by toggling vis-network hidden on cls-5/6 schema nodes and facet edges, wires it into apiRef.current, adds toggleDims() handler, and adds a styled "◇ dimensions" button.
Design plan update
claude-notes/plans/2026-06-23-aiwar-dual-use-value-tenant.md
Replaces incorrect Phase 2 plan with corrected schema-level facet edge approach, adds re-bake-required note for osint_scene.soa, and records two Phase 3 optional tasks (harvest cypher canonicalization, SchemaValue boomerang traversal).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 Hoppity-hop through the graph I go,
Facet edges now glow in a row!
Entity meets SchemaValue with a typed link,
Toggle the dims — watch the layer unshrink.
The plan was wrong, but the fix is bright,
◇ dimensions shining in the night! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and specifically describes the main change: adding dual-use dimensions to the schema as facet edges, which aligns with the PR's core objective of making schema values traversable via new edge connections.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/AdaWorldAPI/q2/issues/comments/4779343407","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- review_stack_entry_start -->\n\n[![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/AdaWorldAPI/q2/pull/44?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)\n\n<!-- review_stack_entry_end -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> <details>\n> <summary>⚙️ Run configuration</summary>\n> \n> **Configuration used**: Organization UI\n> \n> **Review profile**: CHILL\n> \n> **Plan**: Pro Plus\n> \n> **Run ID**: `83bcaf5e-b9a5-4c76-998f-952cd1d44f0c`\n> \n> </details>\n> \n> <details>\n> <summary>📥 Commits</summary>\n> \n> Reviewing files that changed from the base of the PR and between 8c27a7cca8e6a670af59dd1d9c3d334c063d84bb and 86dd48e1304f4955c1b317551b91bf7720732040.\n> \n> </details>\n> \n> <details>\n> <summary>📒 Files selected for processing (3)</summary>\n> \n> * `claude-notes/plans/2026-06-23-aiwar-dual-use-value-tenant.md`\n> * `cockpit/src/OsintGraph.tsx`\n> * `crates/cockpit-server/src/osint_gotham.rs`\n> \n> </details>\n> \n> ```ascii\n>  _________________________________________________________\n> < Nuke the bugs from orbit. It's the only way to be sure. >\n>  ---------------------------------------------------------\n>   \\\n>    \\   (\\__/)\n>        (•ㅅ•)\n>        /   づ\n> ```\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing Touches</summary>\n\n<details>\n<summary>📝 Generate docstrings</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> Create stacked PR\n- [ ] <!-- {\"checkboxId\": \"3e1879ae-f29b-4d0d-8e06-d12b7ba33d98\"} --> Commit on current branch\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=AdaWorldAPI/q2&utm_content=44)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n\n<sub>Comment `@coderabbitai help` to get the list of available commands.</sub>\n\n<!-- tips_end -->"},"request":{"retryCount":3,"signal":{},"retries":3,"retryAfter":16}}}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
cockpit/src/OsintGraph.tsx (1)

60-60: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Bound facet classification to the declared facet code range.

Line 60 currently treats any r >= 10 as dimension-layer relation. Making this explicit to 10..15 avoids 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

📥 Commits

Reviewing files that changed from the base of the PR and between 8c27a7c and 86dd48e.

📒 Files selected for processing (3)
  • claude-notes/plans/2026-06-23-aiwar-dual-use-value-tenant.md
  • cockpit/src/OsintGraph.tsx
  • crates/cockpit-server/src/osint_gotham.rs

Comment thread cockpit/src/OsintGraph.tsx
- 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
@AdaWorldAPI AdaWorldAPI merged commit 91b18e3 into main Jun 23, 2026
4 checks passed
AdaWorldAPI pushed a commit that referenced this pull request Jun 23, 2026
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants