Skip to content

OSINT cockpit: dissolve property-node islands → tenant, reason dual-use as a Person×Situation causal chain#69

Merged
AdaWorldAPI merged 5 commits into
mainfrom
claude/v3-substrate-migration-review-o0yoxv
Jul 1, 2026
Merged

OSINT cockpit: dissolve property-node islands → tenant, reason dual-use as a Person×Situation causal chain#69
AdaWorldAPI merged 5 commits into
mainfrom
claude/v3-substrate-migration-review-o0yoxv

Conversation

@AdaWorldAPI

@AdaWorldAPI AdaWorldAPI commented Jul 1, 2026

Copy link
Copy Markdown
Owner

What

Follow-up to the merged #68. Takes the OSINT cockpit from "11 dims stacked as tenant bytes + materialized schema hubs" to the substrate as intended: the dimension is a prefix carried on the node, and the cross-cutting structure is reasoned as logical edges — never a property-as-node hub. Then wires a real analysis on top: dual-use divergence as a Person × Situation causal chain.

Why

The rendered graph was "still islands": each dimension value (MLTask, SpatialReasoning, a basin) was materialized as a node with spokes into it — a category error (key: value is a tenant slot, not two nodes + an edge). A materialized property-node has no logic to dock as an edge; it just invites "look up a property as a node." This PR removes that and replaces it with reasoning over the tenant.

Changes (5 commits)

1 — dissolve the hubs into anchor-entity tissue (osint_gotham.rs, OsintGraph.tsx)

  • Stop emitting per-basin SOA_HUB_CLASS hubs; member-of/interfaces now dock to the basin's anchor entity (a real node with its own edges), not a synthetic hub.
  • Frontend renders entity↔entity only; SchemaValue/SchemaAxis property-nodes + their facet spokes are no longer rendered — the dimension lives on the node.

2 — 11-wide facet tenant tail + expandable property palette (osint_gotham.rs, OsintGraph.tsx)

  • OSO1 wire carries node_count × 11 facet bytes (value[1..=11]); client decodes stride 11 (legacy 6 still decodes).
  • New lower-right property palette: pick N values across axes, the graph filters by that explicit prefix (AND across axes, OR within). "explicit prefix → immediately find."

3 — dual-use divergence lens (OsintGraph.tsx)

  • Two orthogonal reasoning distances, measured over the tenant, nothing materialized: Demand (offer⟷need) and Causality (intent⟷impact). Divergence = the causality distance (Jaccard of impact sets between the militaryUse and civicUse branches of the same capability — the shared pivot that makes the fork measurable).
  • McClelland/Freud power flow read straight from airo:type bits (P1 consume · P3 control-others · P4 empower).

4 — the causal chain: Person × Situation (OsintGraph.tsx)

  • Reframed as the chain AIwar builds to prove the harm companies deny ("as long as dual-use isn't proven harmful, we continue"): Situation = capability → [mil/civ] → explicit purpose ⟹ implicit impact; Person = the power trait reasoned against it. Macht-driven % = the Person→Situation attribution (Lewin/Atkinson/Rheinberg; Tendency = Motive × Incentive).

5 — align bake ⟷ reasoning schema

  • Verified all 11 tenant positions + the airo:type bitset + stride match between bake and reasoning. Fixed one naming blemish: byte 4 is MLTask (the NEED), was mislabeled MLType (the OFFER) on both sides — renamed consistently. Codebook stays ML_TYPE (value register ≠ dimension name).

Test on Railway

Deploy this branch → the default OSINT graph:

  • Islands gone — schema property-nodes no longer rendered; entities + basin-anchor tissue only.
  • Property palette (lower-right) — expand an axis, select values, graph filters by prefix; live N match.
  • ◆ dual-use lens — nodes painted cool→hot by causality divergence; readout streams the causal chain per capability (capability → [mil/civ] → explicit ⟹ implicit │ trait) with Macht-driven %.

Honest gaps

  • Could not cargo/npm-verify locally (session network-gated); edits are structurally balanced and mirror existing patterns — Railway's build is the verification.
  • The Demand/Flow axis (offer⟷need distance) is not computed: the cockpit has no semantic distance table, and cross-codebook label-matching would be a fabricated distance. Only the Causality axis is honestly measured; wiring ndarray's distance table into the cockpit for the Demand axis is the clean next step (Flow = origin where both axes ≈ 0).

🤖 Generated with Claude Code


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Added live property-based filtering for the OSINT graph, making it easier to focus on matching nodes and relationships.
    • Introduced a heat-style divergence view that highlights higher-interest nodes and surfaces ranked chain results in the readout.
    • Improved node coloring so facet-related views are easier to scan at a glance.
  • Bug Fixes

    • Updated graph rendering to show only relevant entity-to-entity connections, reducing visual clutter.
    • Improved handling of legacy graph data so older and newer datasets display consistently.

The basin belongs in the node's own detail (GUID family byte + EdgeBlock
mixin adapters), not in an outsourced helper node. A materialized hub —
whether a SOA_HUB_CLASS basin node or a SchemaValue property-node — cannot
dock as an edge; it only invites 'look up a property as a node', which
fragments the graph into islands.

Backend (osint_soa_bytes):
- Stop emitting per-basin SOA_HUB_CLASS hub nodes; node_count = members only.
- member-of / interfaces now dock to the basin's ANCHOR ENTITY (the real
  top-degree node that names the basin) via anchor_idx, never a synthetic
  hub. No self-loop on the anchor.
- Drop the basin-hub label loop; remove the now-dead SOA_HUB_CLASS const.

Frontend (OsintGraph.tsx):
- Render entity<->entity relations only: real relations (2..7,9) PLUS basin
  tissue (member-of 0 / interfaces 1, now real anchor edges). Schema
  property-nodes (cls 5/6) and their facet spokes (VALID_FOR 8, facets
  10..20) are no longer rendered — a dimension is a prefix carried ON the
  node (read live by the facet lens), never a node to spoke into.
- Give member-of/interfaces visible tissue colours.

Retrieval stays explicit-prefix: to gather a basin you filter the family
prefix, you don't chase a hub. The facet lens (tenant colouring + raw-edge
naming) is unaffected.
…lette

Wire the dual-use dimensions ON the node into the OSO1 wire and make them
navigable: the explicit prefix you select is the query, and the graph
filters to matches immediately.

Backend (osint_soa_bytes):
- Emit an additive tenant tail: node_count x 11 facet bytes = value[1..=11]
  (militaryUse, civicUse, airo:type, MLType, purpose, capacity, currentStatus,
  type, output, impact, stakeholder). No schema node — the dimension is a
  prefix carried on the node.

Frontend (OsintGraph.tsx):
- decode picks the tenant stride that fits (11 current / 6 legacy), exposed as
  soa.tenantStride; all tenant reads are stride-aware.
- FACET_AXES_UI widened 6 -> 11 to match the backend axis order.
- New lower-right EXPANDABLE PROPERTY PALETTE: per-axis value catalogue
  (value -> label + count), click a value to add/remove it from the filter.
  A node survives if, for every axis carrying >=1 selected value, its code is
  selected (AND across axes, OR within an axis); non-matches dim, edges survive
  only between two matches. Live '<n> match' count + clear.
- This subsumes the single-axis facet legend and expresses the quid-pro-quo
  query directly: militaryUse=* + stakeholder=* + a purpose value.

Note: McClelland motive (GUID2) is not yet populated in the bake, so 'filter by
motivation' uses purpose:vair (the AIRO purpose dim) — the real 'why' signal in
this data. The '<> dimensions' toggle is now inert (schema nodes no longer
rendered); the palette replaces it.
…+ McClelland/Freud power flow

Measures the model as distance during reasoning, never materialized:
- CAUSALITY axis (intent->impact drift) = divergence, per capability the
  Jaccard distance of the impact sets between the militaryUse branch and the
  civicUse branch of the SAME offer (the shared pivot that makes the fork
  measurable).
- DEMAND fork = mil vs civ count for that offer.
- POWER level read straight from airo:type bits (the adjacency): P1 oral
  consume (Subject) / P3 phallic control-others (Deployer) / P4 genital
  empower-others (Developer/Provider) — McClelland nPow as Freud's gradient.
  nAch/nAff from intent/use labels (keyword heuristic).

'◆ dual-use' lens paints every node by the causality distance of the
capability it offers (cool->hot) and streams the ranked capabilities
(demand fork · Δimpact · power level · motive) into the readout, with a
Macht-adjacency % (how much high-divergence skews to power/nPow).

Codebooks stay separate (no merge — distance measured at reason time);
nothing materialized as a node or edge. Replaces the now-inert dimensions
toggle.
Reframe the divergence readout as the CAUSAL CHAIN AIwar builds to prove the
harm companies deny ('as long as dual-use isn't proven harmful, we continue'):

  SITUATION (4 outside factors, the two orthogonal axes):
    capability → [mil/civ demand] → explicit purpose ⟹ implicit impact
    — the intent→impact drift, chained end to end.
  PERSON (personality trait):
    POWER_LEVEL from airo:type (Freud gradient P1 consume / P3 control-others /
    P4 empower), else the McClelland motive (nPow/nAch/nAff), reasoned AGAINST
    the situational chain.

Per capability the readout now shows the chain + the driving trait, and a
'Macht-driven %' = how much of the high-divergence is carried by a power trait
(P3/P4 or nPow) — the Person→Situation attribution that closes the causal chain
the 'can't prove it's harmful' defense relies on staying open.

Model additions: per-capability dominant explicit purpose + implicit impact
(the chain's two ends), collected from the tenant purpose/impact bytes. No
demand-axis distance fabricated (no semantic table in the cockpit — the honest
gap); the causality axis is what's computed. Lewin/Atkinson/Rheinberg grounding.
…LType

Verified every tenant position matches between the bake (osint_gotham.rs
value[1..=11]) and the frontend reasoning (OsintGraph.tsx AX 0..10), plus the
airo:type bitset bit-values (P4=Dev|Prov|Supp, P3=Deployer|Operator,
P1=Subject) and stride=11. One naming blemish fixed: byte 4 is fed from
MLTask/MLTasks (the NEED per the need/offer typing) but was labeled MLType
(the OFFER) on both sides. Renamed FACET_MLTYPE→FACET_MLTASK,
REL_FACET_MLTYPE→REL_FACET_MLTASK (bake) and AX.mlType→mlTask,
FACET_AXES_UI[3]/REL_NAME[13] 'MLType'→'MLTask' (reasoning). The codebook
stays ML_TYPE (the value register) — dimension name ≠ codebook name.
@AdaWorldAPI AdaWorldAPI merged commit bf5e9e0 into main Jul 1, 2026
3 of 4 checks passed

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 31348d26c0

ℹ️ 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".

// DEMAND fork = mil vs civ count for that offer.
// POWER level = airo:type bits (Freud gradient), the adjacency to nPow.
const duModel = useMemo(() => {
if (!soa || !soa.tenants || !soa.tenantStride || !view) return null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Require 11-wide tenants for the divergence lens

When /osint.soa is a legacy 6-wide tenant asset (which decodeSoa explicitly accepts, and the committed fallback crates/cockpit-server/assets/osint_scene.soa is 6-wide), this guard still enables the new dual-use model. The code below then indexes axes such as AX.impact/AX.stakeholder with i * stride + ax; with stride === 6 those reads come from the next node's tenant bytes rather than missing columns, so the ◆ dual-use heatmap/readout is computed from unrelated data. Return null unless tenantStride >= 11 (or avoid the 11-wide-only axes) before enabling this lens.

Useful? React with 👍 / 👎.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4e4eb40e-6253-4c96-b726-b934637777e8

📥 Commits

Reviewing files that changed from the base of the PR and between 650d2a5 and 31348d2.

📒 Files selected for processing (2)
  • cockpit/src/OsintGraph.tsx
  • crates/cockpit-server/src/osint_gotham.rs

📝 Walkthrough

Walkthrough

The PR changes the OSINT SoA wire format and facet encoding on the server (renaming the MLTask facet, emitting members-only nodes with anchor-docked edges, and appending a per-node facet tenant tail), and rewrites the cockpit OsintGraph component to decode that tail, filter/color nodes by tenant facets, and drive a new dual-use divergence heat lens.

Changes

Server-side SoA and facet encoding

Layer / File(s) Summary
MLTask facet constant rename
crates/cockpit-server/src/osint_gotham.rs
FACET_MLTYPE renamed to FACET_MLTASK, REL_FACET_MLTASK added, FACET_AXES and facet packing updated, dual-use test assertion updated.
Members-only SoA with anchor docking and tenant tail
crates/cockpit-server/src/osint_gotham.rs
osint_soa_bytes emits member-only nodes, docks member-of/interfaces edges to real anchor entities instead of hub sentinels, appends an additive per-node facet tenant tail, and header/length tests are adjusted.

OsintGraph cockpit rewrite

Layer / File(s) Summary
Tenant tail decoding and data model
cockpit/src/OsintGraph.tsx
Adds tenant/facet metadata and motive heuristics, extends Soa with tenantStride, extends GraphApi with setPropFilter/heatNodes, and decodeSoa auto-detects 11-wide vs 6-wide tenant tails.
Semantic edge filtering and tenant coloring
cockpit/src/OsintGraph.tsx
Narrows the semantic view to entity-entity edges and updates facet-lens node border coloring to use tenantStride-based indexing.
Live property filter pipeline
cockpit/src/OsintGraph.tsx
Removes dimension-visibility state, adds property-filter selection state, and implements matchesFilter/applyPropFilter/heatNodes wired through apiRef.
Dual-use divergence lens and property palette
cockpit/src/OsintGraph.tsx
Adds fireDivergence, duModel causality computation, property selection handlers, a properties catalogue, replaces the dimensions toggle button, and replaces the facet legend with an expandable property palette.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant OsintGraph
  participant duModel
  participant HeatOverlay
  User->>OsintGraph: click dual-use button
  OsintGraph->>duModel: compute causality/divergence from tenant signals
  duModel-->>OsintGraph: ranked Person x Situation rows and heat map
  OsintGraph->>HeatOverlay: heatNodes(heat)
  OsintGraph->>OsintGraph: stream ranked chain lines to readout
Loading

Possibly related PRs

  • AdaWorldAPI/q2#44: Overlaps with FACET_MLTASK/REL_FACET_MLTASK alignment in FACET_AXES within osint_gotham.rs.
  • AdaWorldAPI/q2#68: Both extend the OSINT value-tenant/facet encoding in osint_gotham.rs and related cockpit tenant/stride-based rendering.
  • AdaWorldAPI/q2#47: Both modify OsintGraph.tsx's Soa/decodeSoa output schema and node rendering.

Poem

A tenant byte, a stride, a hop —
I nibble facets till they pop.
No more hubs of ghostly kind,
anchors hold the truth aligned.
Heat blooms bright where risks entwine,
hop along, this graph is fine! 🐇🔥

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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.

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.

1 participant