-
Notifications
You must be signed in to change notification settings - Fork 0
OSINT cockpit: wire the full 11-dim V3 stacked cascade + runtime bake #68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4445f34
1f79e46
1179bf8
dda56d8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -51,17 +51,57 @@ use include_dir::{include_dir, Dir}; | |
| #[cfg(feature = "embed-cockpit")] | ||
| static COCKPIT_DIST: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/../../cockpit/dist"); | ||
|
|
||
| /// Pre-baked enriched OSINT SoA wire buffer (`osint_gotham::osint_soa_bytes`, | ||
| /// baked offline via the `bake_osint_soa` test). Served at `/osint.soa` and | ||
| /// decoded to a 3D scene client-side — no cypher at runtime, no JSON. | ||
| static OSINT_SOA: &[u8] = | ||
| /// Committed fallback OSINT SoA (used only if the harvest graph isn't on disk). | ||
| static OSINT_SOA_FALLBACK: &[u8] = | ||
| include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/assets/osint_scene.soa")); | ||
|
|
||
| /// Serve the pre-baked OSINT SoA as raw bytes (octet-stream) for `/osint3d`. | ||
| /// OSINT SoA wire buffer, **baked at startup from the on-disk enriched harvest** | ||
| /// (`osint_gotham::osint_soa_bytes`) so the served 3D scene reflects the CURRENT | ||
| /// `aiwar_graph.json` — the full 11-dim V3 stacked cascade (militaryUse:civicUse, | ||
| /// MLTask:MLType, purpose:capacity, output:impact, currentStatus:type, | ||
| /// stakeholder:airo:type), not a stale pre-bake. Falls back to the committed | ||
| /// asset when the harvest is absent (e.g. a minimal image). One-time init. | ||
| static OSINT_SOA: std::sync::LazyLock<Vec<u8>> = std::sync::LazyLock::new(|| { | ||
| let candidates = [ | ||
| // Anchored on the crate dir (baked at build) so it resolves regardless | ||
| // of the runtime cwd Railway launches from. | ||
| concat!(env!("CARGO_MANIFEST_DIR"), "/../../cockpit/public/aiwar_graph.json"), | ||
| "cockpit/public/aiwar_graph.json", | ||
| "/home/user/aiwar-neo4j-harvest/data/aiwar_graph.json", | ||
| "../aiwar-neo4j-harvest/data/aiwar_graph.json", | ||
| ]; | ||
| let Some(path) = candidates.iter().find(|p| std::path::Path::new(p).exists()) else { | ||
| tracing::warn!("osint: no aiwar_graph.json on disk — serving committed fallback asset"); | ||
| return OSINT_SOA_FALLBACK.to_vec(); | ||
| }; | ||
| let cypher = std::path::Path::new(path) | ||
| .parent() | ||
| .and_then(|p| p.parent()) | ||
| .map(|r| r.join("cypher")); | ||
| let graph = match &cypher { | ||
| Some(d) if d.is_dir() => aiwar_ingest::load_with_enrichment(path, d), | ||
| _ => aiwar_ingest::load_from_file(path), | ||
| }; | ||
| let Ok(graph) = graph else { | ||
| tracing::warn!("osint: harvest at {path} failed to load — serving fallback asset"); | ||
| return OSINT_SOA_FALLBACK.to_vec(); | ||
| }; | ||
| let rounds = cypher | ||
| .as_ref() | ||
| .and_then(|d| aiwar_ingest::encounter_round::load_encounter_rounds(d).ok()) | ||
| .unwrap_or_default(); | ||
| tracing::info!( | ||
| "osint: baked {} nodes from {path} (11-dim V3 stacked cascade)", | ||
| graph.nodes.len() | ||
| ); | ||
| osint_gotham::osint_soa_bytes(&graph, &rounds) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a runtime graph candidate is found, this returns Useful? React with 👍 / 👎. |
||
| }); | ||
|
|
||
| /// Serve the baked OSINT SoA as raw bytes (octet-stream) for `/osint3d`. | ||
| async fn osint_soa_handler() -> impl axum::response::IntoResponse { | ||
| ( | ||
| [(axum::http::header::CONTENT_TYPE, "application/octet-stream")], | ||
| OSINT_SOA, | ||
| OSINT_SOA.as_slice(), | ||
| ) | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -114,6 +114,16 @@ const FACET_AIRO_ROLE: usize = 3; // airo:type — u8 bitset (compound) | |
| const FACET_MLTYPE: usize = 4; // MLTask/MLTasks primary token, u8 code | ||
| const FACET_PURPOSE: usize = 5; // purpose / purpose:vair — u8 code | ||
| const FACET_CAPACITY: usize = 6; // capacity / capacity:airo — u8 code | ||
| // V3 6×(8:8) completion (bytes 7..=11) — the six AIRO/VAIR dimensions the | ||
| // original 1..=6 tenant left unstacked. Additive: byte offsets 1..=6 are | ||
| // unchanged (client + committed asset stay compatible); these complete the | ||
| // stacked cascade so every used property is a hot, groupable value tenant — | ||
| // HEEL currentStatus:type · family output:impact · identity stakeholder:airo. | ||
| const FACET_STATUS: usize = 7; // currentStatus — lifecycle stage, u8 code | ||
| const FACET_TYPE: usize = 8; // type — system/actor class, u8 code | ||
| const FACET_OUTPUT: usize = 9; // output:airo — u8 code | ||
| const FACET_IMPACT: usize = 10; // impact:vair — primary harm token, u8 code | ||
| const FACET_STAKEHOLDER: usize = 11; // stakeholder — owning actor class, u8 code | ||
|
|
||
| /// `airo:type` actor roles in bit order. The four canonical AIRO players plus | ||
| /// the two rare variants the harvest carries; the game-theory structure is | ||
|
|
@@ -275,6 +285,107 @@ const CAPACITY_AIRO: &[&str] = &[ | |
| "SignalTracking", | ||
| ]; | ||
|
|
||
| /// `currentStatus:airo` lifecycle stage (aiwc.ods column ∪ actor states). | ||
| const CURRENT_STATUS: &[&str] = &[ | ||
| "Development", | ||
| "Deployment", | ||
| "Operation", | ||
| "Retirement", | ||
| "Active", | ||
| "Historical", | ||
| "Deployed", | ||
| ]; | ||
|
|
||
| /// `type` — the system/actor class (aiwc.ods `type` column ∪ common instances). | ||
| const NODE_TYPE: &[&str] = &[ | ||
| "IntelligentControlSystem", | ||
| "GenerativeModel", | ||
| "GenerativeAI", | ||
| "NarrowAI", | ||
| "TrainingDatabase", | ||
| "ExpertSystem", | ||
| "ServiceRobot", | ||
| "MultiAgentSystem", | ||
| "Dashboard", | ||
| "Nation", | ||
| "TechCompany", | ||
| "DefenseCompany", | ||
| "Military", | ||
| "Investor", | ||
| "Institution", | ||
| "Utility", | ||
| "SurveillanceSystem", | ||
| "FacialRecognition", | ||
| "AutonomousWeapon", | ||
| "TargetingSystem", | ||
| "RoboticSystem", | ||
| "LoiteringMunition", | ||
| "PredictiveAnalytics", | ||
| "DataAnalyticsCompany", | ||
| "FoundationModelProvider", | ||
| "SurveillanceVendor", | ||
| "AILab", | ||
| "GovernmentOfficial", | ||
| "HeadOfState", | ||
| "Investor", | ||
| "Financier", | ||
| "TechExecutive", | ||
| ]; | ||
|
|
||
| /// `output:airo` — what the system emits. | ||
| const OUTPUT_AIRO: &[&str] = &[ | ||
| "Action", | ||
| "Content", | ||
| "Decision", | ||
| "Prediction", | ||
| "Recommendation", | ||
| "Detection", | ||
| "Monitoring", | ||
| "Identification", | ||
| "Generation", | ||
| "Investment", | ||
| "Influence", | ||
| ]; | ||
|
|
||
| /// `impact:vair` — the VAIR harm (primary token of a compound list). | ||
| const IMPACT_VAIR: &[&str] = &[ | ||
| "PsychologicalHarm", | ||
| "PhysicalInjury", | ||
| "PhysicalHarm", | ||
| "WellbeingImpact", | ||
| "DistortionInHumanBehavior", | ||
| "Overreliance", | ||
| "UnderminingFreedom", | ||
| "LossOfLife", | ||
| "LossOfHumanControl", | ||
| "LossOfPrivacy", | ||
| "DiscriminationBias", | ||
| "ConcentrationOfPower", | ||
| "Escalation", | ||
| "PolicyCapture", | ||
| "Deregulation", | ||
| ]; | ||
|
|
||
| /// `stakeholder` — the owning/operating actor class. | ||
| const STAKEHOLDER: &[&str] = &[ | ||
| "Nation", | ||
| "TechCompany", | ||
| "DefenseCompany", | ||
| "Institution", | ||
| "Military", | ||
| "Police", | ||
| "Company", | ||
| "Investor", | ||
| "Utility", | ||
| "Owner", | ||
| "CEO", | ||
| "Politician", | ||
| "Agency", | ||
| "Person", | ||
| "NGO", | ||
| "Consortium", | ||
| ]; | ||
|
|
||
| /// Code a single facet value (`1 + index` in its codebook; `0` = absent / | ||
| /// unknown). Compound axes (comma-joined) code their **primary** token; the | ||
| /// match is case-insensitive so harvest casing drift never silently drops. | ||
|
|
@@ -326,6 +437,22 @@ fn write_facet_tenant(value: &mut [u8; 480], props: &HashMap<String, Value>) { | |
| if let Some(v) = s("capacity").or_else(|| s("capacity:airo")) { | ||
| value[FACET_CAPACITY] = facet_code(CAPACITY_AIRO, v); | ||
| } | ||
| // V3 6×(8:8) completion — the six dims the original tenant left unstacked. | ||
| if let Some(v) = s("currentStatus").or_else(|| s("currentStatus:airo")) { | ||
| value[FACET_STATUS] = facet_code(CURRENT_STATUS, v); | ||
| } | ||
| if let Some(v) = s("type") { | ||
| value[FACET_TYPE] = facet_code(NODE_TYPE, v); | ||
| } | ||
| if let Some(v) = s("output").or_else(|| s("output:airo")) { | ||
| value[FACET_OUTPUT] = facet_code(OUTPUT_AIRO, v); | ||
| } | ||
| if let Some(v) = s("impact").or_else(|| s("impact:vair")) { | ||
| value[FACET_IMPACT] = facet_code(IMPACT_VAIR, v); | ||
| } | ||
| if let Some(v) = s("stakeholder") { | ||
| value[FACET_STAKEHOLDER] = facet_code(STAKEHOLDER, v); | ||
| } | ||
| } | ||
|
|
||
| /// Golden angle (radians) — the φ-spiral / Vogel constant. | ||
|
|
@@ -858,6 +985,14 @@ const REL_FACET_AIRO: u8 = 12; | |
| const REL_FACET_MLTYPE: u8 = 13; | ||
| const REL_FACET_PURPOSE: u8 = 14; | ||
| const REL_FACET_CAPACITY: u8 = 15; | ||
| // V3 6×(8:8) completion — the remaining stacked dimensions as traversable facet | ||
| // edges (rel 16..20). Same distinct-layer contract as 10..15 (toggleable in the | ||
| // client); together the eleven rels put the WHOLE cascade in the schema graph. | ||
| const REL_FACET_STATUS: u8 = 16; | ||
| const REL_FACET_TYPE: u8 = 17; | ||
| const REL_FACET_OUTPUT: u8 = 18; | ||
| const REL_FACET_IMPACT: u8 = 19; | ||
| const REL_FACET_STAKEHOLDER: u8 = 20; | ||
|
|
||
| /// (property-key candidates, facet rel) per dual-use axis. First matching key | ||
| /// wins (e.g. `MLTask` before `MLTasks`). Mirrors the facet tenant axes. | ||
|
|
@@ -868,6 +1003,11 @@ const FACET_AXES: &[(&[&str], u8)] = &[ | |
| (&["MLTask", "MLTasks"], REL_FACET_MLTYPE), | ||
| (&["purpose", "purpose:vair"], REL_FACET_PURPOSE), | ||
| (&["capacity", "capacity:airo"], REL_FACET_CAPACITY), | ||
| (&["currentStatus", "currentStatus:airo"], REL_FACET_STATUS), | ||
| (&["type"], REL_FACET_TYPE), | ||
| (&["output", "output:airo"], REL_FACET_OUTPUT), | ||
| (&["impact", "impact:vair"], REL_FACET_IMPACT), | ||
| (&["stakeholder"], REL_FACET_STAKEHOLDER), | ||
|
Comment on lines
+1006
to
+1010
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
These new rel codes 16–20 are described as toggleable facet edges, but the UI still classifies only Useful? React with 👍 / 👎. |
||
| ]; | ||
|
|
||
| /// Entity → `SchemaValue` facet edges: for each node carrying a dual-use facet | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| # OSINT-V3 SoA Bake — aiwar-neo4j-harvest → 6×(8:8) substrate | ||
|
|
||
| Baked from `AdaWorldAPI/aiwar-neo4j-harvest` (611 nodes) into the V3 SoA | ||
| `6×(8:8) part_of:is_a` centroid cascade (CAM-PQ-shaped) under classid | ||
| `0x1000_0700` (System) / `0x1000_0701` (Person, McClelland). | ||
|
|
||
| ## Assets | ||
| - `osint_v3.soa` — binary SoA. Header `OSINTV3\0` + `ver(u16=3) count(u32) stride(u16=36)`, | ||
| then `count` records of `row_id(u32) | GUID1(16B) | GUID2(16B)` little-endian. | ||
| - `osint_v3_codebook.json` — the aiwc.ods controlled vocab → byte map, tier layout, classids. | ||
| - `osint_v3_nodes.json` — per-node index (row, id, name, guid1/guid2 hex, is_person). | ||
|
|
||
| ## GUID1 (identity+location, 6×(8:8), CAM-PQ-shaped) | ||
| `[classid u32][HEEL|HIP|TWIG|LEAF|family|identity]` — each tier `hi:lo` byte-pair: | ||
| HEEL currentStatus:type · HIP militaryUse:civicUse · TWIG MLTask:MLType · | ||
| LEAF purpose:capacity · family output:impact · identity stakeholder:airo_type. | ||
|
|
||
| ## GUID2 (relationships, McClelland, persons) | ||
| `[classid u32][stage:need|receptor:rubicon|motive:_|...]`. | ||
|
|
||
| ## Findings (this bake) | ||
| - Codebook max cardinality = 30 → every dim fits u8 (u16 is 8× overkill). | ||
| - 45 dual-use HIP basins (militaryUse:civicUse prefix) emerge with zero hub nodes — | ||
| the AIRO "island" axes collapse into prefix-adjacency. | ||
| - 78 collision groups = same-type basins (finance/politician/…), u32 row = local identity. | ||
| - 133 persons carry a McClelland GUID2. | ||
|
|
||
| Provisional: enrichment for unwired dims was inferred by a 15-agent sweep against | ||
| the aiwc.ods controlled vocabulary; base dims (type/currentStatus/stakeholder) are | ||
| from the harvest. Reconcile against ground-truth cypher enrichments before locking. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In a source checkout like this one,
cockpit/public/aiwar_graph.jsonexists, has only the 221 base nodes, and there is nocockpit/cypher; because these public-graph candidates are tried before the enriched harvest paths or the committed 920-node fallback asset,/osint.soanow runtime-bakes the base graph and silently drops the enriched scene the route used to serve. This affects any deployment that ships the repo/public files alongside the binary.Useful? React with 👍 / 👎.