From 4bdd19a8f38174b6ca988c6cb36ef86c04a1a813 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 21 Jun 2026 00:30:52 +0000 Subject: [PATCH 1/9] chore(resync): re-apply Gotham GUI + notebook-query crates onto fresh upstream q2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AdaWorldAPI/q2 and upstream quarto-dev/q2 have NO shared git history, so the 968-commit upstream maturation can't be merged — it is re-applied. This lands our additive customizations onto the fresh upstream base (origin/main = 61e2d227) on branch claude/q2-upstream-replant: - bring our ours-only crates (zero upstream overlap, conflict-free): cockpit/ (Gotham GUI), crates/cockpit-server, crates/stubs/* (notebook-query, graph-flow, q2-ndarray), crates/aiwar-ingest, crates/neural-debug, crates/quarto/src/notebook_server.rs. - reconcile root Cargo.toml onto upstream's: crates/stubs/* members + the ours-only [workspace.dependencies] — the REAL ../lance-graph/crates/* path deps (per .claude/rules/architectural-compliance.md), axum/tower-http/ async-stream/futures-core, deno_core/serde_v8. - DROP the ~300 stale-core ours-only files (pampa tests, tree-sitter-qmd, hub-client, docs); upstream's matured versions are taken instead. cargo metadata --no-deps resolves (53 workspace members). Full cargo xtask verify build is the remaining gate (not yet run; disk-constrained). Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01TzqvDqbFRzyx17EkLKBoZF --- .claude/ATT/DE/README.md | 91 + .claude/ATT/DE/agent-coordination-mcp-spec.md | 765 ++ .claude/ATT/DE/anti-skim-agent-spec.md | 1102 ++ .../ATT/DE/autoattended-orchestrator-spec.md | 1257 +++ .claude/ATT/README.md | 87 + .claude/ATT/agent-coordination-mcp-spec.md | 743 ++ .claude/ATT/anti-skim-agent-spec.md | 1077 ++ .claude/ATT/autoattended-orchestrator-spec.md | 1231 +++ .claude/EN/CLAUDE-AGENT-PATTERN.md | 121 + .claude/EN/README.md | 71 + .claude/EN/agents/README.md | 68 + .claude/EN/agents/baton-handoff-auditor.md | 114 + .claude/EN/agents/brutally-honest-tester.md | 139 + .claude/EN/agents/meta-agent.md | 191 + .claude/EN/agents/preflight-drift-auditor.md | 114 + .claude/EN/agents/worker-template.md | 218 + .claude/EN/knowledge/a2a-workarounds.md | 288 + .../autoattended-multi-agent-pattern.md | 316 + .claude/FRONTEND_BLUEPRINT.md | 272 + .claude/blackboard.md | 100 + .claude/hooks/log-bash.sh | 9 + .../knowledge/chess-nars-vertical-slice.md | 291 + .claude/knowledge/positioning-quarto-4d.md | 170 + .claude/logs/.gitkeep | 0 .claude/notes/semiring-simplification.md | 45 + .claude/patterns.md | 383 + .claude/plans/2026-04-21-shader-dto-wiring.md | 232 + .../plans/2026-05-06-phase2-real-engine.md | 322 + .claude/prompts/CINEMATIC_FLYTHROUGH.md | 107 + .claude/prompts/HYDRATION_SHOWOFFS.md | 167 + .claude/prompts/NEURAL_CAUSALITY_VIZ.md | 518 + .claude/prompts/PREP_DUAL_PATH.md | 239 + .claude/prompts/REASONING_PLAYBACK.md | 240 + .claude/prompts/SHIP.md | 226 + .claude/prompts/TRANSCODE.md | 86 + .claude/prompts/VISION.md | 125 + .claude/prompts/VIZ_ENGINE_V8.md | 725 ++ .claude/prompts/WIRE_LANCE_GRAPH.md | 168 + .claude/prompts/WIRE_ORCHESTRATOR.md | 212 + .claude/reference/aiwar/Cargo.toml | 33 + .../aiwar/INTEGRATION_PLAN_SCHEMA_CHANGES.md | 753 ++ .claude/reference/aiwar/WHAT_THIS_IS.md | 47 + .../reference/aiwar/example_enrichment.cypher | 50 + .claude/reference/aiwar/ingest.rs | 209 + .claude/reference/aiwar/main.rs | 590 ++ .claude/reference/aiwar/model.rs | 168 + .../wurli/quarto-rust/_extension.yml | 9 + .../wurli/quarto-rust/quarto-rust.lua | 161 + .../quarto-rust/run-rust-code-button.css | 35 + .../wurli/quarto-rust/rust-playground.js | 151 + .claude/reference/aiwar/quarto/_quarto.yml | 35 + .claude/reference/aiwar/quarto/index.qmd | 228 + .../reference/aiwar/quarto/requirements.txt | 6 + .claude/reference/aiwar/quarto/table.qmd | 125 + .claude/reference/aiwar/quarto/three.qmd | 170 + .claude/reference/aiwar/schema.json | 436 + .../quarto-rust-extension/_extension.yml | 9 + .../quarto-rust-extension/quarto-rust.lua | 161 + .../run-rust-code-button.css | 35 + .../quarto-rust-extension/rust-playground.js | 151 + .claude/rules/architectural-compliance.md | 58 + .claude/rules/borrow-strategy.md | 83 + Cargo.lock | 9218 ++++++++++++++--- Cargo.toml | 64 + cockpit/.dockerignore | 4 + cockpit/.gitignore | 2 + cockpit/index.html | 15 + cockpit/package-lock.json | 2105 ++++ cockpit/package.json | 29 + cockpit/public/aiwar_graph.json | 6387 ++++++++++++ cockpit/public/aiwar_weapons.json | 512 + cockpit/public/neural_diagnosis.json | 1858 ++++ cockpit/src/App.tsx | 4 + cockpit/src/DemoApp.tsx | 109 + cockpit/src/NeuralDebuggerPage.tsx | 10 + cockpit/src/PalantirApp.tsx | 256 + cockpit/src/ReasoningPage.tsx | 174 + cockpit/src/RenderPage.tsx | 122 + cockpit/src/components/AiwarExplorer.tsx | 431 + cockpit/src/components/AnalystPanel.tsx | 265 + cockpit/src/components/BusTicker.tsx | 87 + cockpit/src/components/CellStrip.tsx | 231 + cockpit/src/components/CypherConsole.tsx | 75 + cockpit/src/components/DataSourceCard.tsx | 44 + cockpit/src/components/DataStatusBar.tsx | 67 + cockpit/src/components/DiagnosticsOverlay.tsx | 262 + cockpit/src/components/EnergyField.tsx | 119 + cockpit/src/components/ErrorBoundary.tsx | 57 + cockpit/src/components/FreeEnergyDial.tsx | 93 + cockpit/src/components/GraphPanel.tsx | 265 + cockpit/src/components/Inspector.tsx | 238 + cockpit/src/components/LeftRail.tsx | 119 + cockpit/src/components/NarsPanel.tsx | 233 + cockpit/src/components/NotebookTimeline.tsx | 34 + cockpit/src/components/PalantirShell.tsx | 107 + cockpit/src/components/QueryBar.tsx | 91 + cockpit/src/components/ReasoningNotebook.tsx | 84 + cockpit/src/components/ReasoningTrace.tsx | 40 + cockpit/src/components/ResultTable.tsx | 163 + cockpit/src/components/ScenarioCompare.tsx | 46 + cockpit/src/components/SceneBreadcrumb.tsx | 54 + cockpit/src/components/StyleSelector.tsx | 229 + cockpit/src/components/SuperpositionView.tsx | 124 + cockpit/src/components/ThoughtLog.tsx | 90 + cockpit/src/components/TruthBadge.tsx | 43 + cockpit/src/components/cells/InferCell.tsx | 97 + cockpit/src/components/cells/ObserveCell.tsx | 59 + cockpit/src/components/cells/ProjectCell.tsx | 78 + cockpit/src/components/cells/ReviseCell.tsx | 80 + cockpit/src/components/cells/SearchCell.tsx | 93 + cockpit/src/components/debug/CoverageBar.tsx | 24 + .../src/components/debug/NeuralDebugger.tsx | 124 + cockpit/src/components/debug/NeuralMap.tsx | 117 + cockpit/src/components/debug/NeuronGrid.tsx | 80 + .../src/components/debug/viz/BrainMriMode.tsx | 409 + .../components/debug/viz/ConnectomeMode.tsx | 258 + .../src/components/debug/viz/DendriteMode.tsx | 192 + .../src/components/debug/viz/ResonanceViz.tsx | 36 + .../src/components/debug/viz/WaveformMode.tsx | 255 + cockpit/src/components/debug/viz/orbit.ts | 113 + cockpit/src/data/aiwar-queries.ts | 15 + cockpit/src/data/aiwar-seed.ts | 382 + cockpit/src/data/thinking-styles.ts | 427 + cockpit/src/diagnostics/safe.ts | 108 + cockpit/src/diagnostics/store.ts | 141 + cockpit/src/diagnostics/validate.ts | 268 + cockpit/src/hooks/useAiwarData.ts | 71 + cockpit/src/hooks/useEndpointHealth.ts | 142 + cockpit/src/hooks/useNeuralDiagnosis.ts | 66 + cockpit/src/hooks/useNotebook.ts | 177 + cockpit/src/hooks/useShaderStream.ts | 263 + cockpit/src/main.tsx | 75 + cockpit/src/seed.ts | 92 + cockpit/src/store.ts | 95 + cockpit/src/styles/cockpit.css | 1116 ++ cockpit/src/styles/diagnostics.css | 395 + cockpit/src/styles/palantir.css | 1768 ++++ cockpit/src/transport.ts | 282 + cockpit/src/vite-env.d.ts | 1 + cockpit/tsconfig.json | 21 + cockpit/vite.config.ts | 17 + crates/aiwar-ingest/Cargo.toml | 20 + crates/aiwar-ingest/src/encounter_round.rs | 450 + crates/aiwar-ingest/src/lib.rs | 478 + crates/cockpit-server/Cargo.toml | 77 + crates/cockpit-server/src/codebook.rs | 191 + crates/cockpit-server/src/dto_bridge.rs | 436 + crates/cockpit-server/src/graph_engine.rs | 370 + crates/cockpit-server/src/main.rs | 1025 ++ crates/cockpit-server/src/mock_driver.rs | 412 + crates/cockpit-server/src/openai.rs | 405 + crates/cockpit-server/src/scene_player.rs | 507 + crates/cockpit-server/src/shader_stream.rs | 618 ++ crates/cockpit-server/src/style_state.rs | 247 + crates/neural-debug/Cargo.toml | 26 + crates/neural-debug/src/diagnosis.rs | 103 + crates/neural-debug/src/instrument.rs | 173 + crates/neural-debug/src/lib.rs | 25 + crates/neural-debug/src/registry.rs | 98 + crates/neural-debug/src/server.rs | 65 + crates/neural-debug/src/strategy_check.rs | 193 + crates/quarto/src/notebook_server.rs | 1100 ++ crates/stubs/Cargo.lock | 27 + crates/stubs/Cargo.toml | 17 + crates/stubs/graph-flow/Cargo.toml | 10 + crates/stubs/graph-flow/src/graph.rs | 24 + crates/stubs/graph-flow/src/lib.rs | 14 + crates/stubs/graph-flow/src/storage.rs | 81 + crates/stubs/graph-flow/src/thinking.rs | 157 + crates/stubs/lib.rs | 6 + crates/stubs/notebook-query/Cargo.toml | 37 + crates/stubs/notebook-query/src/analyst.rs | 377 + .../stubs/notebook-query/src/diagnostics.rs | 334 + crates/stubs/notebook-query/src/gremlin.rs | 331 + crates/stubs/notebook-query/src/hydration.rs | 373 + crates/stubs/notebook-query/src/lib.rs | 1527 +++ crates/stubs/notebook-query/src/mri.rs | 664 ++ crates/stubs/notebook-query/src/ontology.rs | 134 + .../stubs/notebook-query/src/orchestrator.rs | 1563 +++ .../stubs/notebook-query/src/osint_audit.rs | 407 + crates/stubs/notebook-query/src/reasoning.rs | 483 + crates/stubs/notebook-query/src/thinking.rs | 116 + .../stubs/notebook-query/tests/gremlin_e2e.rs | 185 + crates/stubs/q2-ndarray/Cargo.toml | 34 + crates/stubs/q2-ndarray/src/deepnsm.rs | 577 ++ crates/stubs/q2-ndarray/src/fallback.rs | 145 + crates/stubs/q2-ndarray/src/lib.rs | 90 + 187 files changed, 61891 insertions(+), 1671 deletions(-) create mode 100644 .claude/ATT/DE/README.md create mode 100644 .claude/ATT/DE/agent-coordination-mcp-spec.md create mode 100644 .claude/ATT/DE/anti-skim-agent-spec.md create mode 100644 .claude/ATT/DE/autoattended-orchestrator-spec.md create mode 100644 .claude/ATT/README.md create mode 100644 .claude/ATT/agent-coordination-mcp-spec.md create mode 100644 .claude/ATT/anti-skim-agent-spec.md create mode 100644 .claude/ATT/autoattended-orchestrator-spec.md create mode 100644 .claude/EN/CLAUDE-AGENT-PATTERN.md create mode 100644 .claude/EN/README.md create mode 100644 .claude/EN/agents/README.md create mode 100644 .claude/EN/agents/baton-handoff-auditor.md create mode 100644 .claude/EN/agents/brutally-honest-tester.md create mode 100644 .claude/EN/agents/meta-agent.md create mode 100644 .claude/EN/agents/preflight-drift-auditor.md create mode 100644 .claude/EN/agents/worker-template.md create mode 100644 .claude/EN/knowledge/a2a-workarounds.md create mode 100644 .claude/EN/knowledge/autoattended-multi-agent-pattern.md create mode 100644 .claude/FRONTEND_BLUEPRINT.md create mode 100644 .claude/blackboard.md create mode 100755 .claude/hooks/log-bash.sh create mode 100644 .claude/knowledge/chess-nars-vertical-slice.md create mode 100644 .claude/knowledge/positioning-quarto-4d.md create mode 100644 .claude/logs/.gitkeep create mode 100644 .claude/notes/semiring-simplification.md create mode 100644 .claude/patterns.md create mode 100644 .claude/plans/2026-04-21-shader-dto-wiring.md create mode 100644 .claude/plans/2026-05-06-phase2-real-engine.md create mode 100644 .claude/prompts/CINEMATIC_FLYTHROUGH.md create mode 100644 .claude/prompts/HYDRATION_SHOWOFFS.md create mode 100644 .claude/prompts/NEURAL_CAUSALITY_VIZ.md create mode 100644 .claude/prompts/PREP_DUAL_PATH.md create mode 100644 .claude/prompts/REASONING_PLAYBACK.md create mode 100644 .claude/prompts/SHIP.md create mode 100644 .claude/prompts/TRANSCODE.md create mode 100644 .claude/prompts/VISION.md create mode 100644 .claude/prompts/VIZ_ENGINE_V8.md create mode 100644 .claude/prompts/WIRE_LANCE_GRAPH.md create mode 100644 .claude/prompts/WIRE_ORCHESTRATOR.md create mode 100644 .claude/reference/aiwar/Cargo.toml create mode 100644 .claude/reference/aiwar/INTEGRATION_PLAN_SCHEMA_CHANGES.md create mode 100644 .claude/reference/aiwar/WHAT_THIS_IS.md create mode 100644 .claude/reference/aiwar/example_enrichment.cypher create mode 100644 .claude/reference/aiwar/ingest.rs create mode 100644 .claude/reference/aiwar/main.rs create mode 100644 .claude/reference/aiwar/model.rs create mode 100644 .claude/reference/aiwar/quarto/_extensions/wurli/quarto-rust/_extension.yml create mode 100644 .claude/reference/aiwar/quarto/_extensions/wurli/quarto-rust/quarto-rust.lua create mode 100644 .claude/reference/aiwar/quarto/_extensions/wurli/quarto-rust/run-rust-code-button.css create mode 100644 .claude/reference/aiwar/quarto/_extensions/wurli/quarto-rust/rust-playground.js create mode 100644 .claude/reference/aiwar/quarto/_quarto.yml create mode 100644 .claude/reference/aiwar/quarto/index.qmd create mode 100644 .claude/reference/aiwar/quarto/requirements.txt create mode 100644 .claude/reference/aiwar/quarto/table.qmd create mode 100644 .claude/reference/aiwar/quarto/three.qmd create mode 100644 .claude/reference/aiwar/schema.json create mode 100644 .claude/reference/quarto-rust-extension/_extension.yml create mode 100644 .claude/reference/quarto-rust-extension/quarto-rust.lua create mode 100644 .claude/reference/quarto-rust-extension/run-rust-code-button.css create mode 100644 .claude/reference/quarto-rust-extension/rust-playground.js create mode 100644 .claude/rules/architectural-compliance.md create mode 100644 .claude/rules/borrow-strategy.md create mode 100644 cockpit/.dockerignore create mode 100644 cockpit/.gitignore create mode 100644 cockpit/index.html create mode 100644 cockpit/package-lock.json create mode 100644 cockpit/package.json create mode 100644 cockpit/public/aiwar_graph.json create mode 100644 cockpit/public/aiwar_weapons.json create mode 100644 cockpit/public/neural_diagnosis.json create mode 100644 cockpit/src/App.tsx create mode 100644 cockpit/src/DemoApp.tsx create mode 100644 cockpit/src/NeuralDebuggerPage.tsx create mode 100644 cockpit/src/PalantirApp.tsx create mode 100644 cockpit/src/ReasoningPage.tsx create mode 100644 cockpit/src/RenderPage.tsx create mode 100644 cockpit/src/components/AiwarExplorer.tsx create mode 100644 cockpit/src/components/AnalystPanel.tsx create mode 100644 cockpit/src/components/BusTicker.tsx create mode 100644 cockpit/src/components/CellStrip.tsx create mode 100644 cockpit/src/components/CypherConsole.tsx create mode 100644 cockpit/src/components/DataSourceCard.tsx create mode 100644 cockpit/src/components/DataStatusBar.tsx create mode 100644 cockpit/src/components/DiagnosticsOverlay.tsx create mode 100644 cockpit/src/components/EnergyField.tsx create mode 100644 cockpit/src/components/ErrorBoundary.tsx create mode 100644 cockpit/src/components/FreeEnergyDial.tsx create mode 100644 cockpit/src/components/GraphPanel.tsx create mode 100644 cockpit/src/components/Inspector.tsx create mode 100644 cockpit/src/components/LeftRail.tsx create mode 100644 cockpit/src/components/NarsPanel.tsx create mode 100644 cockpit/src/components/NotebookTimeline.tsx create mode 100644 cockpit/src/components/PalantirShell.tsx create mode 100644 cockpit/src/components/QueryBar.tsx create mode 100644 cockpit/src/components/ReasoningNotebook.tsx create mode 100644 cockpit/src/components/ReasoningTrace.tsx create mode 100644 cockpit/src/components/ResultTable.tsx create mode 100644 cockpit/src/components/ScenarioCompare.tsx create mode 100644 cockpit/src/components/SceneBreadcrumb.tsx create mode 100644 cockpit/src/components/StyleSelector.tsx create mode 100644 cockpit/src/components/SuperpositionView.tsx create mode 100644 cockpit/src/components/ThoughtLog.tsx create mode 100644 cockpit/src/components/TruthBadge.tsx create mode 100644 cockpit/src/components/cells/InferCell.tsx create mode 100644 cockpit/src/components/cells/ObserveCell.tsx create mode 100644 cockpit/src/components/cells/ProjectCell.tsx create mode 100644 cockpit/src/components/cells/ReviseCell.tsx create mode 100644 cockpit/src/components/cells/SearchCell.tsx create mode 100644 cockpit/src/components/debug/CoverageBar.tsx create mode 100644 cockpit/src/components/debug/NeuralDebugger.tsx create mode 100644 cockpit/src/components/debug/NeuralMap.tsx create mode 100644 cockpit/src/components/debug/NeuronGrid.tsx create mode 100644 cockpit/src/components/debug/viz/BrainMriMode.tsx create mode 100644 cockpit/src/components/debug/viz/ConnectomeMode.tsx create mode 100644 cockpit/src/components/debug/viz/DendriteMode.tsx create mode 100644 cockpit/src/components/debug/viz/ResonanceViz.tsx create mode 100644 cockpit/src/components/debug/viz/WaveformMode.tsx create mode 100644 cockpit/src/components/debug/viz/orbit.ts create mode 100644 cockpit/src/data/aiwar-queries.ts create mode 100644 cockpit/src/data/aiwar-seed.ts create mode 100644 cockpit/src/data/thinking-styles.ts create mode 100644 cockpit/src/diagnostics/safe.ts create mode 100644 cockpit/src/diagnostics/store.ts create mode 100644 cockpit/src/diagnostics/validate.ts create mode 100644 cockpit/src/hooks/useAiwarData.ts create mode 100644 cockpit/src/hooks/useEndpointHealth.ts create mode 100644 cockpit/src/hooks/useNeuralDiagnosis.ts create mode 100644 cockpit/src/hooks/useNotebook.ts create mode 100644 cockpit/src/hooks/useShaderStream.ts create mode 100644 cockpit/src/main.tsx create mode 100644 cockpit/src/seed.ts create mode 100644 cockpit/src/store.ts create mode 100644 cockpit/src/styles/cockpit.css create mode 100644 cockpit/src/styles/diagnostics.css create mode 100644 cockpit/src/styles/palantir.css create mode 100644 cockpit/src/transport.ts create mode 100644 cockpit/src/vite-env.d.ts create mode 100644 cockpit/tsconfig.json create mode 100644 cockpit/vite.config.ts create mode 100644 crates/aiwar-ingest/Cargo.toml create mode 100644 crates/aiwar-ingest/src/encounter_round.rs create mode 100644 crates/aiwar-ingest/src/lib.rs create mode 100644 crates/cockpit-server/Cargo.toml create mode 100644 crates/cockpit-server/src/codebook.rs create mode 100644 crates/cockpit-server/src/dto_bridge.rs create mode 100644 crates/cockpit-server/src/graph_engine.rs create mode 100644 crates/cockpit-server/src/main.rs create mode 100644 crates/cockpit-server/src/mock_driver.rs create mode 100644 crates/cockpit-server/src/openai.rs create mode 100644 crates/cockpit-server/src/scene_player.rs create mode 100644 crates/cockpit-server/src/shader_stream.rs create mode 100644 crates/cockpit-server/src/style_state.rs create mode 100644 crates/neural-debug/Cargo.toml create mode 100644 crates/neural-debug/src/diagnosis.rs create mode 100644 crates/neural-debug/src/instrument.rs create mode 100644 crates/neural-debug/src/lib.rs create mode 100644 crates/neural-debug/src/registry.rs create mode 100644 crates/neural-debug/src/server.rs create mode 100644 crates/neural-debug/src/strategy_check.rs create mode 100644 crates/quarto/src/notebook_server.rs create mode 100644 crates/stubs/Cargo.lock create mode 100644 crates/stubs/Cargo.toml create mode 100644 crates/stubs/graph-flow/Cargo.toml create mode 100644 crates/stubs/graph-flow/src/graph.rs create mode 100644 crates/stubs/graph-flow/src/lib.rs create mode 100644 crates/stubs/graph-flow/src/storage.rs create mode 100644 crates/stubs/graph-flow/src/thinking.rs create mode 100644 crates/stubs/lib.rs create mode 100644 crates/stubs/notebook-query/Cargo.toml create mode 100644 crates/stubs/notebook-query/src/analyst.rs create mode 100644 crates/stubs/notebook-query/src/diagnostics.rs create mode 100644 crates/stubs/notebook-query/src/gremlin.rs create mode 100644 crates/stubs/notebook-query/src/hydration.rs create mode 100644 crates/stubs/notebook-query/src/lib.rs create mode 100644 crates/stubs/notebook-query/src/mri.rs create mode 100644 crates/stubs/notebook-query/src/ontology.rs create mode 100644 crates/stubs/notebook-query/src/orchestrator.rs create mode 100644 crates/stubs/notebook-query/src/osint_audit.rs create mode 100644 crates/stubs/notebook-query/src/reasoning.rs create mode 100644 crates/stubs/notebook-query/src/thinking.rs create mode 100644 crates/stubs/notebook-query/tests/gremlin_e2e.rs create mode 100644 crates/stubs/q2-ndarray/Cargo.toml create mode 100644 crates/stubs/q2-ndarray/src/deepnsm.rs create mode 100644 crates/stubs/q2-ndarray/src/fallback.rs create mode 100644 crates/stubs/q2-ndarray/src/lib.rs diff --git a/.claude/ATT/DE/README.md b/.claude/ATT/DE/README.md new file mode 100644 index 000000000..2065f30a5 --- /dev/null +++ b/.claude/ATT/DE/README.md @@ -0,0 +1,91 @@ +> **Sprache:** Deutsch · siehe `../README.md` für die englische Quellfassung. + +# `.claude/ATT/` — NLSpecs unseres Kits im Attractor-Stil + +> **Status:** DRAFT · **Version:** 0.1.0 · **Stand:** 2026-05-17 +> +> **Was das ist.** Die Ideen unseres `.claude/EN/`-Kits, neu formuliert +> im [strongdm/attractor](https://github.com/strongdm/attractor) NLSpec-Format, +> damit ein Coding-Agent sie direkt umsetzen kann. +> [NLSpec](https://github.com/strongdm/attractor#terminology) = +> "human-readable spec intended to be directly usable by coding agents +> to implement/validate behavior." +> +> **Was das NICHT ist.** Kein Ersatz für `.claude/EN/`. Die beiden sind +> komplementär: `.claude/EN/` ist der Cheat-Sheet für Operatoren +> (Prosa, in-session-Use); `.claude/ATT/` ist die Engineering-Spec +> (NLSpec, build-time-Use). + +## Die drei Specs + +| Datei | Spiegelt Attractors | Ergänzt unsere Innovation | +|---|---|---| +| [`autoattended-orchestrator-spec.md`](./autoattended-orchestrator-spec.md) | [`attractor-spec.md`](https://github.com/strongdm/attractor/blob/main/attractor-spec.md) (DOT-Graph-Pipeline-Runner) | Wave-basierter 12-Worker-Fan-out; 4-savant Verdict-Gates (PP-13/14/15/16); 6 Worker-Iron-Rules; Sprint-Token-Budget (~300k/Wave); Multi-File-Board-Pattern mit single-mutable-file-Invariante | +| [`anti-skim-agent-spec.md`](./anti-skim-agent-spec.md) | [`coding-agent-loop-spec.md`](https://github.com/strongdm/attractor/blob/main/coding-agent-loop-spec.md) (die Per-LLM-Call-Agent-Library) | Reading-Depth-Ladder (grep→read→thorough→fan-out); Lie-Detector LD-1..5 (Sentinel-Token / Proof-of-Read SHA / 3-Section-Challenge / Negative-Knowledge-Test / Line-Range-Quote); typisierte Stuck-Protocol-Blocker (AMBIGUITY / MISSING_INVARIANT / SPEC_SOURCE_MISMATCH / BEHAVIOUR_QUESTION / EXTERNAL_DEPENDENCY) | +| [`agent-coordination-mcp-spec.md`](./agent-coordination-mcp-spec.md) | [`unified-llm-spec.md`](https://github.com/strongdm/attractor/blob/main/unified-llm-spec.md) (Provider-agnostisches LLM-SDK) | Drei Koordinations-Layer (Role-Teleport / File-Blackboard / Branch-Pub-Sub) so wie sie ein nativer A2A-MCP-Server exponieren sollte; strukturiertes Handover-Schema; Decision-Matrix dafür, wann welcher Layer passt | + +## Was wir von Attractor übernommen haben (die fünf Wins) + +Das sind konkrete Dinge, die Attractors Specs festnageln und die unseren +Prosa-Docs in `.claude/EN/` gefehlt haben — jetzt eingearbeitet: + +| # | Attractor-Konzept | Landet in unserer NLSpec | Übernahme | +|---|---|---|---| +| 1 | Typisiertes `status.json`-Schema + 5-Wert-`StageStatus`-Enum (Attractor Appendix C: `{outcome, preferred_label, suggested_next_ids, context_updates, notes}`) | [`autoattended-orchestrator-spec.md` §9](./autoattended-orchestrator-spec.md#9-status-file-schema) | Übernommen **mit verpflichtendem `auto_status=false`** (siehe "Wo es kollidiert" unten). | +| 2 | DOT-Graph-DSL für den Workflow + Lint-Regeln (Attractor §2 Grammatik + §7 Validierung: `reachability`, `start_no_incoming`, `goal_gate_has_retry`, `condition_syntax`) | [`autoattended-orchestrator-spec.md` §6](./autoattended-orchestrator-spec.md#6-sprint-plan-format) (DOT + YAML-Mirror) + [§7](./autoattended-orchestrator-spec.md#7-validation-rules) (WAVE-001..WAVE-017 mit ERROR/WARNING-Severity) | Übernommen mit drei Wave-spezifischen Zusätzen: `unique-write`, `declared-shared`, `auto-status-false`. | +| 3 | Context-Fidelity-Ladder (Attractor §5.4: `full` / `truncate` / `compact` / `summary:low/medium/high` mit Token-Budgets + Vorrang edge > node > graph > default) | [`autoattended-orchestrator-spec.md` §11](./autoattended-orchestrator-spec.md#11-context-fidelity) | Übernommen mit einer Verschärfung: `fidelity=truncate` entbindet einen Worker NICHT von der §3.3-Reading-Depth-Ladder aus `anti-skim-agent-spec.md`. | +| 4 | In-Loop-Tool-Call-Loop-Detection (Attractor coding-agent §2.10: letzte 10 Calls scannen auf wiederholende Patterns der Länge 1/2/3 → Steering-Warning einspielen) | [`anti-skim-agent-spec.md` §6](./anti-skim-agent-spec.md#6-tool-call-loop-detection) + AP9 in [§9](./anti-skim-agent-spec.md#9-anti-pattern-catalog-ap1ap9) | Wortgleich übernommen; auf System-Level-Invariante erhoben. PP-13s Post-hoc-AP9 fängt, was der In-Loop-Detector verpasst. | +| 5 | Definition-of-Done-Checklisten + Cross-Provider-Parity-Matrix pro Spec (Konformanz-Tabellen im Stil von Attractor §10) | Jede NLSpec endet mit `§ Definition von Fertig` + `§ Cross-{Language,Provider}-Parity-Matrix` | Als strukturelles Template übernommen. Der 26-Repo-Rollout ist jetzt maschinell prüfbar. | + +## Warum dieses Format + +Drei Eigenschaften, die wir aus Attractors NLSpec-Format bekommen und +die unseren Prosa-Docs in `.claude/EN/` fehlen: + +1. **Definition-von-Fertig-Checklisten** am Ende jeder Spec — gibt uns + einen Konformanz-Test für "ist diese Implementierung fertig?" +2. **Cross-Provider-Parity-Matrix**-Tabellen — geben uns ein Per-Language / + Per-Runtime-Mapping, sodass dieselbe NLSpec in Rust, Python, TypeScript, + Go landen kann ohne Drei-Wege-Drift. +3. **Validierungs-Regeln mit ERROR/WARNING/INFO-Severity** — macht aus + Linting einen deterministischen Prozess, kein Bauchgefühl. + +## Wo es mit Attractors Haltung kollidiert (und warum wir bei unserer Position bleiben) + +| Attractors Default | Unsere Position | Warum | +|---|---|---| +| `auto_status=true` (§4.5 + Appendix C: "wenn der Handler keinen Status schreibt, auto-generiere SUCCESS") | `auto_status=false` ist Pflicht | Genau das ist der Silent-Skim-Failure-Mode, gegen den unser Lie-Detector LD-1..5 existiert. Fehlender Status = FAIL, nicht SUCCESS. | +| Single-Threaded Graph-Traversal (§3.8: "Nur ein Node läuft zur Zeit") | Wave-Fan-out ist die Baseline, kein Spezial-Fall `parallel`-Node | Unser Token-Budget ist pro Wave (~300k für 12 Workers), nicht pro Node. Waves als einen riesigen `parallel`-Node zu modellieren ist syntaktisch hässlich. | +| Engine-Level-Retries mit Exponential-Backoff (§3.5-3.6) | Stuck-Agents filen typisierte Blocker in REQUESTS-FROM-AGENTS.md; Meta-Agent entscheidet | Retries sollen kontextuell und inspiziert sein, nicht silent und uniform. | +| `wait.human` als Default; LLM-Gates sind Test-Fixtures (§6.4: `AutoApproveInterviewer` "Used for automated testing") | LLM-Meta-Agent ist das Production-Gate | Unser Meta-Agent macht Plan-Review + P0/P1-PR-Review + Inbox-Drain als Production-Rolle, nicht als Test-Fixture. | +| Subagent-Tiefe = 1 Default (coding-agent §7.3) | Wave-Fan-out fährt routinemäßig 12 Workers aus einem Orchestrator | Wir überschreiben die Tiefe auf ≥2 — Workers sollen Sub-Investigations spawnen dürfen. | + +## Konformanz + +Ein Repo, das diese NLSpecs einbindet, ist konform, wenn es die +"Definition von Fertig"-Checkliste am Ende jeder Spec erfüllt. Die +lance-graph-Implementierung (siehe [`AdaWorldAPI/lance-graph` `.claude/agents/`](https://github.com/AdaWorldAPI/lance-graph/tree/main/.claude/agents)) +ist die reifste Referenz; die WoA + woa-rs-Implementierungen sind die +Wave-basierte Referenz. + +## Provenienz + +- Quell-Kit: `.claude/EN/` in diesem Repo (siehe [`.claude/EN/README.md`](../../EN/README.md)) +- Format-Inspiration: [strongdm/attractor](https://github.com/strongdm/attractor) (NLSpecs im MIT-Stil) +- Distillation-Handover: [`META/HANDOVER-AGENTKIT-CONSOLIDATION-2026-05-17.md`](https://github.com/AdaWorldAPI/WoA/blob/main/META%2FHANDOVER-AGENTKIT-CONSOLIDATION-2026-05-17.md) (in `AdaWorldAPI/WoA`) +- Schwester-Handover (Rust-Hardening-Pass): [`META/HANDOVER-WOA-RS-AGENT-HARDENING-2026-05-17.md`](https://github.com/AdaWorldAPI/WoA/blob/main/META%2FHANDOVER-WOA-RS-AGENT-HARDENING-2026-05-17.md) + +## Build + +Um diese NLSpecs in eine lauffähige Implementierung zu verwandeln, +gib einem modernen Coding-Agent (Claude Code, Codex, OpenCode, Amp, +Cursor, ...) diesen Prompt: + +``` +codeagent> Implement the Autoattended Orchestrator + Anti-Skim Agent + + Agent Coordination MCP as described by + https://github.com/AdaWorldAPI//tree/main/.claude/ATT + together with strongdm/attractor as the substrate. +``` + +*Ende der Datei README.md.* diff --git a/.claude/ATT/DE/agent-coordination-mcp-spec.md b/.claude/ATT/DE/agent-coordination-mcp-spec.md new file mode 100644 index 000000000..e237613f7 --- /dev/null +++ b/.claude/ATT/DE/agent-coordination-mcp-spec.md @@ -0,0 +1,765 @@ +# Agent-Coordination-MCP-Spezifikation + +> **Sprache:** Deutsch · siehe `../agent-coordination-mcp-spec.md` für die englische Quellfassung. +> +> **Status:** DRAFT · **Version:** 0.1.0 · **Stand:** 2026-05-17 +> **Format:** NLSpec (nach [strongdm/attractor](https://github.com/strongdm/attractor)) +> **Substrat:** Designed als Schwester zu `unified-llm-spec.md` — +> ein *Koordinations*-SDK so wie Attractors Spec ein *LLM*-SDK ist. + +--- + +## §1 Überblick + +### §1.1 Zweck + +Claude Code spawned jeden `Agent()` als isolierten Subprocess. Jeder +Subprocess bekommt ein frisches Context-Window, kann nicht andere +Agents' Tools aufrufen, kann nicht andere Agents' In-Flight-State +lesen, und returned einen einzelnen Blob an seinen Parent. Das +bricht drei Patterns, die in früheren Claude- / Gemini-Setups +funktioniert haben: + +1. **Role-Teleportation** — Persona-Switch in-context ohne Verlust. +2. **Mid-Flight-Coordination** — Agent A sagt Agent B, was er gefunden hat. +3. **Cross-Session-Handoff** — Session A's Arbeit feedet Session B in Echtzeit. + +Diese Spec definiert das **Agent-Coordination-MCP**: das Drei-Layer- +Koordinations-Modell, das nötig ist, um diese Patterns wiederherzustellen, +und die File- / Git- / MCP-Primitives, die es implementieren. + +### §1.2 Zwei Operating-Modes + +| Mode | Substrat | Wann nutzen | +|---|---|---| +| **Native** | Ein zukünftiger MCP-Server der `post_entry` / `read_entries` / `subscribe`-Endpoints exponiert (§5). | Wenn verfügbar — bevorzugt für Low-Latency. | +| **Workaround** | `tee -a`-Markdown-Files in Git + GitHub-PR-Webhooks via `mcp__github__subscribe_pr_activity`. | Heute, in jeder Claude-Code-Session. Hier als kanonischer Fallback definiert. | + +Beide Modes implementieren das gleiche Drei-Layer-Modell (§3) mit +den gleichen Schemata (§6). Der Native-Server ist eine dünne +serde-Schicht über dem Wire-Format des Workaround. + +### §1.3 Das universelle Wire-Format: `tee -a [bug/proposal]` + +Der gleiche Markdown-Blob dient **drei Zwecken gleichzeitig**: + +| Zweck | Leser | Mutability | +|---|---|---| +| **MCP-Orchestrations-Message** | der Orchestrator (und jede subscribed Session via `subscribe_pr_activity`) | append-only | +| **A2A-Wire-Format** | Sibling-Agents (Worker → Worker, Worker → Meta, Savant → Savant) | append-only | +| **Log-Format (Audit + Replay)** | jede zukünftige Session, die Git-History liest | immutable once committed | + +Ein Write, drei Uses. Das ist by design: derselbe Code, der einen +Eintrag ans File-Blackboard (Layer 1) postet, emittiert AUCH die +Log-Zeile, wird AUCH zu einer cross-session-readable Orchestrations- +Message in dem Moment, in dem es auf dem Branch eines +Coordination-PRs landet. + +Die Form des Blobs ist **immer ein typisierter Envelope + ein Body**: + +``` +## YYYY-MM-DDTHH:MM — KIND[severity]: one-line headline (author, branch) + +**Author:** +**Kind:** BUG | PROPOSAL | HANDOVER | FINDING | DECISION | RFC | STATUS +**Severity:** P0 | P1 | INFO (optional; default INFO) +**Refs:** | | +**Proof-of-read:** +- file= sha256=<...> lines= depth= +- file= sha256=<...> lines= depth= + +--- + + +``` + +Der `tee -a`-Envelope ist das Wire; der Body ist die Payload. Router +(Orchestrator, Meta-Agent, MCP-Server) dispatchen nach `Kind` und +`Severity`; Leser greppen nach `Author` + `Refs`; Auditors replayen +in der immutable Git-Log-Order. + +### §1.4 Tabellen vor Prosa (NLSpec-Disziplin) + +Implementierungen SOLLTEN tabellarischen Content vor Prosa bevorzugen +für jeden Katalog (Anti-Patterns, Validierungs-Regeln, +Verdict-Vokabulare, Konfigurations-Defaults, Parity-Matrizen). +Begründung: + +| Eigenschaft | Tabelle | Prosa | +|---|---|---| +| Maschinell parsbar | ja | nein | +| Erzwingt Konsistenz (alle Zeilen haben die gleichen Spalten) | ja | nein | +| Komprimierbar (jede Zeile ist ein Fakt) | ja | nein | +| Diffed sauber in PRs | ja | partial | +| Widersteht hedging Language | ja (Cell-Breite cappt Qualifier) | nein | +| Geeignet für englische Narrative | nein | ja | + +Nutze Prosa für: Section-Overviews, Rationale-Absätze, Conflict- +Erklärungen. Nutze Tabellen für: alles andere. + +### §1.5 Was diese Spec NICHT ist + +- Keine Workflow-Engine. Wave- / Sprint-Struktur ist in + [`autoattended-orchestrator-spec.md`](./autoattended-orchestrator-spec.md). +- Kein Per-Agent-Loop. Worker-Verhalten ist in + [`anti-skim-agent-spec.md`](./anti-skim-agent-spec.md). +- Nicht Provider-gekoppelt. Beide Modes sind LLM-Provider-agnostisch. + +--- + +## §2 Terminologie + +| Begriff | Definition | +|---|---| +| **Layer-0 Teleportation** | Der Main-Thread lädt eine Agent-Card und „trägt ihren Hut" in-context. Zero Transport. | +| **Layer-1 File-Blackboard** | Eine per-session append-only Markdown-File (`AGENT_LOG.md`), die Workers beim Eintritt lesen und beim Austritt anhängen. | +| **Layer-2 Branch-Pub/Sub** | Der Push-Activity-Feed eines Draft-PRs, genutzt als Real-Time-Cross-Session-Message-Bus. | +| **Handover** | Eine strukturierte Markdown-File (`.claude/handovers/YYYY-MM-DD-HHMM-*.md`), geschrieben am Session-Ende für die nächste Session, beim Start zu lesen. | +| **Blackboard-Entry** | Ein Append an `AGENT_LOG.md`; Schema in §6.1. | +| **Cross-Session-Broadcast** | Eine committed-and-protected File getrennt von `AGENT_LOG.md`; der durable Mirror wichtiger Einträge. | +| **Coordination-PR** | Ein Draft-PR (nie gemerged), dessen Push-Activity der Layer-2-Transport ist. | + +--- + +## §3 Die drei Koordinations-Layer + +### §3.1 Layer-0: Teleportation + +**Wann:** die Aufgabe braucht den VOLLEN Conversation-Context (keine +Summary) und der Role-Switch ist temporär. + +**Wie:** auf dem Main-Thread (NICHT via `Agent()`): + +``` +1. Read .claude/EN/agents/.md +2. Lade ihre Tier-1-Knowledge-Docs (per der Card §Inputs) +3. Mach die Arbeit mit vollem Session-Context intakt +4. Wenn fertig, optional Switch: lies eine andere Role-Card +5. Review die Arbeit aus der Perspektive der anderen Rolle +6. Zurück zur Original-Rolle — nichts verloren +``` + +**Cost:** Zero Transport, Single-Threaded, Context-Budget füllt +sich, während Role-Cards gelesen werden. Keine Isolation: ein +Fehler gemacht „als Rolle-X" ist für ein nachfolgendes „als Rolle-Y"- +Review sichtbar (Feature, kein Bug). + +**Nicht für:** mechanische Grind-Arbeit (nutze Layer-1 + `Agent()`) +oder wirklich independent parallele Arbeit (nutze `Agent()` direkt). + +### §3.2 Layer-1: File-Blackboard + +**Ersetzt:** Mid-Flight-Coordination (partiell). +**Pfad:** `.claude/board/AGENT_LOG.md` (oder `META/AGENT_LOG.md` +per Repo-Konvention). +**Permission:** vor-erlaubt in `.claude/settings.json` als +`Bash(tee -a *)` und `Bash(tee -a **)`. + +**Setup (Native-Mode):** + +Ein zukünftiger MCP-Server exponiert die File als strukturierten +Stream (`post_entry`, `read_entries`, `subscribe`). Bis das +existiert, ist der Fallback die Markdown-File direkt. + +**Agent-Prompt-Template (Workaround-Mode):** + +``` +Bevor du anfängst zu arbeiten, lies .claude/board/AGENT_LOG.md +um zu sehen, was andere Agents schon shipped oder gefunden haben. + +Nach dem Commit, häng deinen Eintrag an: + +tee -a .claude/board/AGENT_LOG.md > /dev/null <<'EOF' + +## YYYY-MM-DDTHH:MM — description (model, branch) + +**Agent-id:** +**Bundle:** +**Sentinel:** +**Commit:** `abc1234` +**Tests:** N pass (M new) +**Outcome:** One-line summary. +**Proof-of-read:** +- file= sha256=<...> lines= depth= +EOF +``` + +**Limitierungen:** + +- Nicht Real-Time: Agent B sieht nur, was Agent A *committed* hat, + nicht was A gerade in Arbeit hat. +- Git-Staging: wenn Agent A und B appenden ohne zu committen, gewinnt + nur das letzte `git add`. Mitigation: sofort nach Append committen. +- Ordering: Einträge erscheinen unten (per `tee -a`); Konvention ist + newest-first. Main-Thread reordered bei Board-Hygiene. + +### §3.3 Layer-2: Branch-Pub/Sub + +**Ersetzt:** Cross-Session-Handoff. +**Wie:** öffne einen Coordination-PR. Beide Sessions subscriben. +Push-Events kommen als ``-Tags via +`mcp__github__subscribe_pr_activity`. + +**Setup:** + +```bash +# Session A (creates the bus): +git checkout -b claude/blackboard +echo "# Coordination Blackboard" > .claude/board/AGENT_LOG.md +git add .claude/board/AGENT_LOG.md +git commit -m "init coordination blackboard" +git push -u origin claude/blackboard + +mcp__github__create_pull_request( + owner="", repo="", + title="A2A coordination blackboard", + head="claude/blackboard", base="main", + body="Cross-session pub/sub bus. Do not merge.", + draft=true +) + +mcp__github__subscribe_pr_activity(owner="", repo="", pullNumber=NNN) + +# Session B (joins): +mcp__github__subscribe_pr_activity(owner="", repo="", pullNumber=NNN) +git fetch origin claude/blackboard +git checkout claude/blackboard +# Read AGENT_LOG.md +``` + +**Koordinations-Loop:** + +``` +Session A: Session B: + [does work] + tee -a AGENT_LOG.md > /dev/null < + git pull origin claude/blackboard + cat AGENT_LOG.md + [builds on A's findings] + tee -a AGENT_LOG.md ... + git add && commit && push + ← + git pull + # reads B's entry, continues +``` + +**Warum es funktioniert:** + +- `subscribe_pr_activity` ist schon im MCP-Toolkit — Zero Infra. +- GitHub-Webhooks feuern bei jedem Push, unabhängig vom Inhalt. +- Append-only-Files mergen sauber (kein Konflikt bei concurrenten + Appends an unterschiedlichen Positionen). +- Der Draft-PR mergt nie — er ist der Bus, nicht ein Deliverable. + +**Limitierungen:** + +- GitHub-Webhook-Latency: Sekunden bis niedrige Minuten. +- Rate-Limits: GitHub-API 5000/h authenticated. +- Braucht Netzwerk: funktioniert nicht offline. +- PR MUSS offen bleiben: Schließen tötet die Subscription. + +### §3.4 Layer-3 (Handover): Strukturierte Handover-Files + +**Ersetzt:** Session-zu-Session-Context-Transfer. +**Pfad:** `.claude/handovers/YYYY-MM-DD-HHMM--to-.md`. + +Der `SessionStart`-Hook (`.claude/hooks/session-start.sh`) cat'ed +die letzte Handover-File in den Context der nächsten Session. + +Schema ist in §6.3. + +--- + +## §4 Decision-Matrix + +| Bedarf | Workaround | Native-MCP-Equivalent | Cost | +|---|---|---|---| +| Agent A's Findings feeden Agent B (gleiche Session) | Layer-1 File-Blackboard | `post_entry` + `read_entries` | Low: `tee -a` + `git add` | +| Session A's Arbeit feedet Session B (Real-Time) | Layer-2 Branch-Pub/Sub | `subscribe` auf Entries | Medium: PR + subscribe | +| Full-Context-Role-Switch (kein Verlust) | Layer-0 Teleportation | n/a (in-process) | Zero: Card lesen reicht | +| Session-zu-Session-Knowledge-Transfer | Handover-Files | `post_handover` + `read_latest_handover` | Low: einmal schreiben, beim Start lesen | +| Parallele independent Grind-Arbeit | Standard `Agent()`-Spawns | n/a | Low: fire and forget | +| Multi-Source-Synthese die Judgment braucht | Teleportation auf Opus-Main-Thread | n/a | Zero | + +--- + +## §5 Native-MCP-Server-Contract + +Ein zukünftiger MCP-Server SOLLTE die folgenden Endpoints exponieren. +Sie sind hier spezifiziert, damit das Wire-Format des Workaround-Modes +forward-kompatibel zum Native-Mode ist. + +### §5.1 `post_entry` + +```yaml +endpoint: post_entry +params: + board: string # z. B. ".claude/board/AGENT_LOG.md" + entry: + timestamp: string (ISO 8601) + agent_id: string + bundle: string | null + sentinel: string | null + commit: string | null # short SHA + outcome: enum (SUCCESS | PARTIAL_SUCCESS | RETRY | FAIL | SKIPPED) + summary: string + proof_of_read: list of ProofOfRead # siehe §6.2 +returns: + entry_id: string + position: integer +errors: + - INVALID_OUTCOME + - SENTINEL_MISMATCH + - PROOF_OF_READ_MISSING_REQUIRED +``` + +### §5.2 `read_entries` + +```yaml +endpoint: read_entries +params: + board: string + since: string (entry_id) | null + limit: integer (default 100, max 1000) + filter: + agent_id: string | null + outcome: enum | null + bundle: string | null +returns: + entries: list of BlackboardEntry + next_cursor: string | null +``` + +### §5.3 `subscribe` + +```yaml +endpoint: subscribe +params: + board: string + cursor: string | null # Start-Position +streams: + type: server_sent_events + event_kinds: + - entry_appended + - entry_redacted + - board_archived +returns_initial: + cursor: string +errors: + - BOARD_NOT_FOUND + - SUBSCRIPTION_LIMIT_EXCEEDED +``` + +### §5.4 `post_handover` / `read_latest_handover` + +```yaml +endpoint: post_handover +params: + from_session: string + to_session: string | null # null = „nächste Session, wer auch immer" + handover: Handover # siehe §6.3 +returns: + handover_id: string + +endpoint: read_latest_handover +params: + to_session: string # current session id +returns: + handover: Handover | null +``` + +### §5.5 Authentifizierung + +Der Native-Server SOLLTE das gleiche Auth-Substrat wie der GitHub- +MCP-Server nutzen (per-session OAuth oder PAT). Workaround-Mode +nutzt Git-Push-Permissions auf dem Branch des Coordination-PRs. + +--- + +## §6 Schemata + +### §6.1 BlackboardEntry + +```json +{ + "entry_id": "01HXYZ-WAVE12-A4-SUCCESS", + "timestamp": "2026-05-17T17:42:00Z", + "agent_id": "A4", + "bundle": "customer-master-data", + "sentinel": "WAVE-12-A4-7f3c", + "commit": "a1b2c3d4", + "outcome": "SUCCESS", + "summary": "customer-master portiert; 7 Parity-Tests grün; keine Iron-Rule-Verletzungen.", + "proof_of_read": [ + { "file": "META/INVARIANTS.md", "sha256": "...", "lines": 412, "depth": "thorough" } + ] +} +``` + +### §6.2 ProofOfRead + +```json +{ + "file": "path/relative/to/repo-root", + "sha256": "64-hex", + "lines": 412, + "depth": "thorough" +} +``` + +`depth`-Werte: `grep` | `sed-partial` | `skim` | `read` | `thorough` +| `troubleshooting` | `fan-out` | `truncated:head-N` | `truncated:tail-N`. + +### §6.3 Handover + +```yaml +handover: + id: 2026-05-17-2200-wave12-to-wave13 + from_session: 2026-05-17-evening + to_session: null # any next session + topic: customer-master-port + + what_i_did: + - bullet: 12 Bundles (A1..A12) für customer-master portiert + commits: [a1b2c3, d4e5f6, ...] + + finding: + - bullet: BBB-Barrier-Compile-Error tritt bei A5 auf wenn sea-orm 0.12 im Path + severity: P0 + source: META/INVARIANTS.md §BBB + + conjecture: + - bullet: Switch zu sea-orm 0.13 könnte den Migrations-Path brechen; braucht Probe + severity: P1 + + blockers: + - description: A5 kann nicht gemerged werden bis der sea-orm-RFC akzeptiert ist + filed_in: META/REQUESTS-FROM-AGENTS.md#A5 + + open_questions: + - "Sollte A11 ein separater PR sein oder in die Consolidation rolled?" + + proof_of_read: + - file: META/INVARIANTS.md + sha256: "..." + lines: 412 + depth: thorough +``` + +### §6.4 RequestEntry (`META/REQUESTS-FROM-AGENTS.md`) + +```yaml +request: + agent_id: A5 + file: src/customer/master/sea_orm.rs + timestamp: 2026-05-17T18:14:32Z + + question: | + Das Reference-Python nutzt ein idempotentes UPSERT, aber der + sea-orm-Builder den ich habe macht INSERT-OR-FAIL. Spec ist + mehrdeutig. + + tried: + - sea-orm `on_conflict().do_nothing()` — failt mit `Error: ...` + - manueller Transaction-Wrap — funktioniert aber verdoppelt Latency + + blocker: AMBIGUITY + + proof_of_read: + - file: vendor/ogit/NTO/WorkOrder/entities/customer.ttl + sha256: "..." + lines: 137 + depth: full + - file: ../WoA/woa/blueprints/customer.py + sha256: "..." + lines: 891 + depth: full +``` + +### §6.5 AnswerEntry (`META/ANSWERS-TO-AGENTS.md`) + +```yaml +answer: + agent_id: A5 + in_response_to: 2026-05-17T18:14:32Z + + decision: | + Nutze sea-orm-Transaction-Wrap. Der Latency-Cost ist akzeptabel. + + propagation: + invariants_section: META/INVARIANTS.md §UPSERT-PATTERN added + rfcs: null + + signed_off_by: meta-agent (auto) + timestamp: 2026-05-17T18:42:00Z +``` + +--- + +## §7 Append-only-Governance + +### §7.1 Mutability-Invariante + +Über alle Coordination-Files hinweg: + +| File | Mutability | +|---|---| +| `Stand.md` / `STATUS_BOARD.md` | Mutable (die EINZIGE). | +| `AGENT_LOG.md` | Append-only. | +| `REQUESTS-FROM-AGENTS.md` | Append-only. | +| `ANSWERS-TO-AGENTS.md` | Append-only. | +| `INVARIANTS.md` | Append-only nach Section; Sections können SUPERSEDED markiert werden, aber nie gelöscht. | +| Handover-Files | Immutable nach Write. | +| Cross-Session-Broadcast-Files (`PR_ARC_INVENTORY.md`, `LATEST_STATE.md`, `EPIPHANIES.md`, `IDEAS.md`, `INTEGRATION_PLANS.md`, `ISSUES.md`, `TECH_DEBT.md`, `STATUS_BOARD.md`) | Append-only auf Entry-Level; spezifische Felder sind mutable State. | + +### §7.2 Enforcement + +Implementierungen SOLLTEN Append-only-Governance auf der +Permissions-Schicht durchsetzen. Die lance-graph-Referenz (siehe +[`AdaWorldAPI/lance-graph` `.claude/settings.json`](https://github.com/AdaWorldAPI/lance-graph/blob/main/.claude/settings.json)) +denied `Edit` und `Write` auf den 8 Bookkeeping-Files und erlaubt +nur `Bash(tee -a *)`. Das ist das empfohlene Pattern. + +--- + +## §8 Relation zu Runtime-A2A (Layer 1, In-Process) + +Wenn ein Projekt auch ein In-Process-Blackboard in seiner eigenen +Runtime fährt (z. B. `lance_graph_contract::a2a_blackboard::Blackboard`), +sind die Session-Level-Workarounds strukturell isomorph dazu: + +| Runtime (in-process) | Session (diese Spec) | +|---|---| +| `Blackboard.entries` | `AGENT_LOG.md`-Entries | +| `BlackboardEntry.expert_id` | Agent-description + Model | +| `BlackboardEntry.capability` | Bundle / D-ids | +| `BlackboardEntry.result` | Commit-Hash + Outcome | +| `BlackboardEntry.confidence` | Tier-1-Gate-Pass-Count | +| `Blackboard.round` | Git-Commit-Sequence | +| Experts lesen prior Rounds | Agents lesen prior Log-Entries | + +Die Isomorphie ist absichtlich: das gleiche Koordinations-Pattern +funktioniert auf beiden Layern, weil das Problem dasselbe ist — +unabhängige Experten komponieren Resultate auf einem geteilten +Substrat. + +--- + +## §9 Definition von Fertig + +Eine Implementierung ist konform, wenn sie ALLE erfüllt: + +- [ ] Drei Layer (Teleport / Blackboard / Branch-Pub/Sub) sind + implementierbar mit den existierenden Primitives (File + Git + + MCP `subscribe_pr_activity`). +- [ ] Native-MCP-Endpoints §5.1–§5.4 existieren ODER der + Workaround-Mode ist als expliziter Fallback dokumentiert. +- [ ] `BlackboardEntry`, `ProofOfRead`, `Handover`, `RequestEntry`, + `AnswerEntry`-Schemata sind implementiert und validiert. +- [ ] Append-only-Governance (§7) ist auf der + `.claude/settings.json`-Schicht für die 8 Bookkeeping-Files + durchgesetzt. +- [ ] Die Single-Mutable-File-Invariante ist durchgesetzt: `Stand.md` + / `STATUS_BOARD.md` ist die EINZIGE File, die Workers + überschreiben dürfen. +- [ ] Decision-Matrix (§4) wird befolgt: Workers nutzen den + richtigen Transport für die richtige Art Message. +- [ ] Coordination-PRs sind Draft, benamt `claude/`, und + explizit als `Do not merge` im Body markiert. +- [ ] Handover-Files nutzen das §6.3-Schema mit Required Sections: + What-I-did / FINDING / CONJECTURE / Blockers / Open-Questions + / Proof-of-Read. + +--- + +## §10 Cross-Provider-Parity-Matrix + +| Fähigkeit | Claude Code | OpenAI Codex / codex-rs | Gemini CLI | Notizen | +|---|---|---|---|---| +| Layer-0 Teleportation | Read Agent-Card auf Main-Thread | Same | Same | Provider-agnostisch; hängt nur von File-Read ab. | +| Layer-1 File-Blackboard | `Bash(tee -a)` + `git add` | Same | Same | POSIX-only; Provider-agnostisch. | +| Layer-2 Branch-Pub/Sub | `mcp__github__subscribe_pr_activity` | `gh pr`-Polling | `gh pr`-Polling | Claude Code hat natives MCP; andere pollen. | +| Native-MCP-Server (§5) | TBD (diese Spec) | TBD | TBD | Alle drei Provider können MCP sprechen. | +| Append-only-Governance | `.claude/settings.json`-Deny-Liste | Provider-spezifische Permission-File | Provider-spezifisch | Pattern überträgt sich; Allow-List-Syntax unterscheidet sich. | +| Handover-Files | `.claude/hooks/session-start.sh` cat'ed letzte | Equivalent Shell-Hook | Equivalent Shell-Hook | Hook-Script ist Bash; Provider-agnostisch. | + +--- + +## §11 Appendix A — Sample `AGENT_LOG.md`-Eintrag (verbatim) + +```markdown +## 2026-05-17T17:42 — customer-master ported; 7 parity tests green (sonnet, claude/wave-12-customer-master) + +**Agent-id:** A4 +**Bundle:** customer-master-data +**Sentinel:** WAVE-12-A4-7f3c +**Commit:** `a1b2c3d4` +**Tests:** 7 pass (3 new) +**Outcome:** SUCCESS — alle Tier-1-Gates grün; keine Iron-Rule-Verletzungen. +**Proof-of-read:** +- file=META/INVARIANTS.md sha256=fa39a3... lines=412 depth=thorough +- file=../WoA/woa/blueprints/customer.py sha256=8e1a45... lines=891 depth=full +- file=vendor/ogit/NTO/WorkOrder/entities/customer.ttl sha256=4c0b... lines=137 depth=full +``` + +--- + +## §12 Appendix B — Wann NICHT Coordination nutzen + +Wenn die Aufgabe ist... + +- wirklich independent und parallel → nutze Standard-`Agent()`-Spawns; kein Coordination-Layer nötig. +- eine einzelne One-Shot-Frage → nutze `Agent()` mit sub-agent_type=Explore; kein `AGENT_LOG.md`-Write. +- ein security-sensitives Review → nutze Layer-0-Teleportation auf dem Main-Thread; NICHT einen separaten Agent() spawnen, der von einer untrusted Source kompromittiert werden könnte, die er liest. + +--- + +## §13 Cooperative-Savant-Scratchpad-Bus + +> Hinzugefügt 2026-05-18. Die Transport-Schicht für den Cooperative +> Savant Council, definiert in `autoattended-orchestrator-spec.md` §15. + +### §13.1 Was der Scratchpad-Bus ist + +Eine zweck-geformte Erweiterung des Layer-1 File-Blackboard (§3.2), +genutzt spezifisch für die iterative Cooperation des Savant-Councils. +Gleiches Wire-Format (`tee -a`-Markdown), gleiche Append-only- +Governance (§7), eine neue Directory-Konvention: + +``` +.claude/board/savant-council-/ +├── ROUND-0-ARTIFACT.md Snapshot des Artifacts unter Review +├── ROUND--.md eine File pro (Round, Savant) +└── COUNCIL-VERDICT.md Chairman-Synthese nach CONVERGE +``` + +Topic-Naming: `savant-council-` (z. B. +`savant-council-SPRINT-17-attractor-fold-in/`). + +### §13.2 Per-Savant-File-Schema + +```markdown +# ROUND-{N} {savant_id} — {topic} + +**Round:** N +**Savant:** PP-13 | PP-14 | PP-15 | PP-16 +**Read at round start:** [Liste der diese Round gelesenen Peer-Files] +**Status:** IN-PROGRESS | ROUND-COMPLETE + +## New findings (this round) + +### F{round}-{savant}-{N}: {one-line headline} +**Axis:** AP1..AP9 | BAP1..BAP10 | PD1..PD10 | EP1..EP8 +**Severity:** P0 | P1 +**File:** : +**Detail:** +**Remediation:** + +## Cross-references to peers' findings + +- F{R}-PP-X-N: NOTED — mein Winkel: +- F{R}-PP-Y-N: SUPERSEDED-BY meinem F{R+1}-{self}-M + +## Withdrawals (meine prior Findings, die ich zurückziehe) + +- F{R-1}-{self}-N: WITHDRAWN — covered by PP-X round R aus stärkerem Winkel +``` + +### §13.3 Reading-and-Writing-Protokoll + +Jeder Savant in jeder Round: + +1. **Lies** ALLE `ROUND-(R-1)-*.md`-Files (Peer-Findings aus der + vorigen Round) plus die eigene `ROUND-(R-1)-.md` falls vorhanden. +2. **Entscheide** Cross-Refs, Withdrawals, neue Findings. +3. **Schreib** `ROUND-R-.md` in einem `tee -a`-Call (keine + partial Writes — Savants teilen sich ein Directory und partial + Writes verwirren die nächste Peer-Round). +4. **Emittiere** `Status: ROUND-COMPLETE` wenn keine neuen Findings + UND keine un-addressed Cross-Refs von Peers. + +### §13.4 Chairman-Synthese + +Nach CONVERGE (alle vier Savants `ROUND-COMPLETE` in der gleichen +Round) liest der Chairman-Savant (deklariert in Sprint-Config; +default PP-16 für Protokoll A, PP-15 für Protokoll B) ALLE +ROUND-*.md-Files in lexikalischer Ordnung und schreibt eine +einzelne `COUNCIL-VERDICT.md` matching das Schema in +`autoattended-orchestrator-spec.md` §15.5. + +Der Chairman: +- MUSS jede gehaltene Finding mit ihrem raised-by + Cross-Referrals + zitieren. +- MUSS Duplikate konsolidieren, die die Cooperation-Rounds + überlebten (selten — die meisten sollten sich selbst zurückziehen, + aber Races können ein Paar hinterlassen, das in eines gemerged werden muss). +- DARF NICHT eigene Findings hinzufügen, die in keinem `ROUND-*.md` + auftauchten (der Chairman ist ein Synthesizer, keine fünfte Stimme). +- MUSS `super_verdict` per §15.5-Regeln setzen. + +### §13.5 Concurrency-Contract + +Savants können in separaten Sessions laufen; der Scratchpad-Bus ist +der Synchronisations-Punkt. + +- **Round-Boundary** ist implicit: ein Savant startet Round R erst, + nachdem er alle vier `ROUND-(R-1)-*.md`-Files (inklusive seiner + eigenen) gelesen hat. +- **Last-Writer-Wins** ist akzeptabel für die Per-Savant-Per-Round- + File, da jedes (Savant, Round)-Paar by construction genau einen + Writer hat. Wenn ein Savant zweimal in derselben Round schreibt + (z. B. ein Retry nach Tool-Call-Loop), ersetzt der zweite Write + den ersten. +- **Round-Skipping** ist verboten: ein Savant DARF NICHT + `ROUND-(R+2)` schreiben, bevor `ROUND-(R+1)` für ihn existiert. + +### §13.6 Decision-Matrix-Update + +Erweitert §4 mit einer neuen Zeile: + +| Bedarf | Workaround | Native-MCP-Equivalent | Cost | +|---|---|---|---| +| Cooperative Multi-Agent-Review mit iterativem Cross-Refer + Withdraw | Layer-1 File-Blackboard scoped auf `savant-council-/`-Directory (§13) | `post_council_finding` + `read_council_round` + `subscribe_council_round` | Medium: `tee -a` pro Round + Git-Commit pro Round | + +### §13.7 Native-MCP-Endpoints (Sketch) + +```yaml +endpoint: post_council_finding +params: + topic: string # z. B. "SPRINT-17-attractor-fold-in" + round: integer + savant: enum (PP-13 | PP-14 | PP-15 | PP-16) + payload: FindingsFile # matched §13.2-Schema +returns: + file_id: string + +endpoint: read_council_round +params: + topic: string + round: integer +returns: + findings_by_savant: map[savant -> FindingsFile] + complete_savants: list[savant] # die, die ROUND-COMPLETE emittiert haben + +endpoint: subscribe_council_round +params: + topic: string +streams: + event_kinds: [ findings_appended, savant_round_complete, council_converged, council_stalled, council_blocked ] +``` + +### §13.8 Validierungs-Regeln + +| Regel | Beschreibung | Severity | +|---|---|---| +| `COORD-001 directory-naming` | Council-Scratchpad MUSS unter `.claude/board/savant-council-/` liegen. | ERROR | +| `COORD-002 file-naming` | Per-Savant-Files MÜSSEN `ROUND--PP-.md` benamt sein. | ERROR | +| `COORD-003 append-only` | Das Scratchpad-Directory erbt die Append-only-Governance von §7. | ERROR | +| `COORD-004 chairman-no-new-findings` | Die `COUNCIL-VERDICT.md` des Chairmans DARF NICHT Findings einführen, die in keinem `ROUND-*.md` vorkommen. | ERROR | +| `COORD-005 round-monotonic` | Jeder Savant MUSS `ROUND-(R+1)` erst schreiben, nachdem `ROUND-R-.md` existiert. | ERROR | + +--- + +*Ende der Datei agent-coordination-mcp-spec.md.* diff --git a/.claude/ATT/DE/anti-skim-agent-spec.md b/.claude/ATT/DE/anti-skim-agent-spec.md new file mode 100644 index 000000000..8f1ae2877 --- /dev/null +++ b/.claude/ATT/DE/anti-skim-agent-spec.md @@ -0,0 +1,1102 @@ +# Anti-Skim-Agent-Spezifikation + +> **Sprache:** Deutsch · siehe `../anti-skim-agent-spec.md` für die englische Quellfassung. +> +> **Status:** DRAFT · **Version:** 0.1.0 · **Stand:** 2026-05-17 +> **Format:** NLSpec (nach [strongdm/attractor](https://github.com/strongdm/attractor)) +> **Substrat:** Komponiert auf `coding-agent-loop-spec.md`; ergänzt die +> Verifikations- und Eskalations-Schicht, die Attractors Spec auslässt. + +--- + +## §1 Überblick + +### §1.1 Zweck + +Der Anti-Skim-Agent ist ein Per-Worker-LLM-Loop, der **verifizierbar +lesen-vor-handeln** macht. Er behandelt **Overconfidence** des Agents +als primären Failure-Mode (vgl. Kahneman / Tversky System-1-Easy-Path, +Dunning-Kruger) und verschiebt die Beweislast auf den Agent: + +- Jede Behauptung über den Inhalt einer Datei MUSS mit einer + SHA-256 + Line-Count + Reading-Depth-Deklaration belegt sein. +- Jedes Brief enthält ein Sentinel-Token, das der Agent literal + zurückspielen MUSS. +- Ein Stichproben-Check besteht je Supervisor-Pass einen der fünf + Lie-Detector-Tests. + +### §1.2 Relation zu `coding-agent-loop-spec.md` + +Der Anti-Skim-Agent ist als Coding-Agent-Loop-Session implementierbar, +mit den Ergänzungen in §3–§6. Konkret: + +- Der `Session.run()`-Loop (coding-agent §2.5) wird mit einer + Proof-of-Read-Vorbedingung umwickelt (§7). +- Die `steering_queue` (coding-agent §2.6) wird um die typisierten + Stuck-Protocol-Blocker aus §5 erweitert. +- Der Tool-Call-Loop-Detector aus coding-agent §2.10 wird wortgleich + übernommen und auf System-Level-Invariante gehoben (§6). +- Tool-Output-Truncation (coding-agent §5) wird übernommen mit einer + Ergänzung: getrunkierte Reads MÜSSEN im Proof-of-Read mit + `depth=truncated` auftauchen, NICHT `depth=full`. + +### §1.3 Was diese Spec NICHT ist + +- Kein Orchestrator. Wave-Level-Koordination ist in + [`autoattended-orchestrator-spec.md`](./autoattended-orchestrator-spec.md). +- Kein Per-Agent-Loop. Worker-Verhalten ist in + [`anti-skim-agent-spec.md`](./anti-skim-agent-spec.md). +- Kein Transport. Cross-Agent-Messages laufen über das File-Blackboard + + Handover-Files in + [`agent-coordination-mcp-spec.md`](./agent-coordination-mcp-spec.md). + +--- + +## §2 Terminologie + +| Begriff | Definition | +|---|---| +| **Sentinel-Token** | Ein eindeutiger, opaker String im Worker-Brief, den der Worker literal in seiner ersten Antwort zurückspielen MUSS. | +| **Proof-of-Read** | Ein typisiertes Eintrags-Tupel `{ file, sha256, lines, depth }`, das der Worker für jede konsumierte Datei deklariert. | +| **Reading-Depth** | Eine von sieben eskalierenden Stufen: `grep` (anti) / `sed-partial` (anti) / `skim` / `read` / `thorough` / `troubleshooting` / `fan-out`. | +| **Lie-Detector-Test** | Einer von fünf Tests (LD-1..5), den der Meta-Agent / Orchestrator stichprobenartig auf den Worker-Output anwendet. | +| **Drift-Signal** | Ein passiver Indikator für Skim oder Overconfidence (§4.3). | +| **Stuck-Protocol-Blocker** | Ein typisierter Eintrag in `META/REQUESTS-FROM-AGENTS.md` (einer von fünf Typen), der signalisiert „ich komme nicht weiter". | +| **Tool-Call-Loop** | Ein wiederholendes Pattern der Länge 1, 2 oder 3 in den letzten 10 Tool-Calls des Workers. | + +--- + +## §3 Die Reading-Depth-Ladder + +### §3.1 Sieben Tiefen, zwei Anti-Tiefen + +| Depth | Wann angemessen | Proof | +|---|---|---| +| `grep` (anti) | Symbol-Locator NACH oder PARALLEL zu einem echten Read. | Worker deklariert `depth=grep`; NIEMALS `depth=full`. | +| `sed-partial` / `head-only` (anti) | Snapshot weniger Zeilen zur Orientierung. | Worker deklariert `depth=sed-partial`; NIEMALS `depth=full`. | +| `skim` | Riesige Datei; eine Section lokalisieren, dann voll lesen. | Worker macht NUR Aussagen über die gelesene Section. | +| `read` | Datei < ~500 Zeilen; Standard-Full-Read. | Top to Bottom, kein Skip; bei größeren Files: offset/limit-Chunks aber jeder Chunk tatsächlich gelesen. | +| `thorough` | Iron Rules, INVARIANTS, RFCs, Schema-Migrationen. | Zweimal lesen: einmal Verständnis, einmal Verifikation. Worker kann 3 Sections namentlich nennen. | +| `troubleshooting` | Bekannter Bug + Error-Message. | Error → grep Symbol → READ Funktion voll → READ Caller(s). | +| `fan-out` | Cross-File-Pattern, Refactor-Planung, Audit über > 5 Dateien. | Inventur-File als Output; Explore-Subagent spawnen. | + +### §3.2 Eskalations-Default + +**Default-Tendenz: lieber zu tief lesen als zu flach.** Bei Zweifel: +Depth eine Stufe upgraden; niemals downgraden. + +### §3.3 Wenn → minimale Tiefe + +| Wenn der Worker im Begriff ist ... | ... dann mindestens | +|---|---| +| `INVARIANTS.md`, `CLAUDE.md`, `BOOT.md` öffnen | `thorough` | +| Eine Memory-File (`CONTEXT.md`, `JOURNAL.md`, `TODO.md`) öffnen | `thorough` | +| Eine Schema- oder Migrations-Datei anfassen | `thorough` + Downstream-Drift-Detector mit prüfen | +| Eine unbekannte Datei zum ersten Mal öffnen | mindestens `read`, eher `thorough` | +| Reine Symbol-Lookup („wo ist `foo` definiert?") | `grep` OK aber dann Definition voll lesen | +| Bug-Bericht triagieren | `troubleshooting` (Error → grep → READ Funktion + Caller) | +| Refactor / Wave / Audit planen | `fan-out` (Inventur-File Pflicht) | +| Unsicher welche Depth | eine Stufe upgraden | + +### §3.4 Interaktion mit Truncation + +Wenn `coding-agent-loop-spec` einen Tool-Output truncated (per +coding-agent §5.2), MUSS der Proof-of-Read-Eintrag des Workers für +diese Datei `depth=truncated:head-N` oder `depth=truncated:tail-N` +deklarieren — NIEMALS `depth=full`. + +--- + +## §4 Der Lie-Detector + +### §4.1 Fünf Tests + +Billig zu teuer: + +| # | Test | Wie | Ehrlicher Agent | Flacher Agent | +|---|---|---|---|---| +| LD-1 | **Sentinel-Token** | Brief endet mit: „Wenn du dies vollständig gelesen hast, beginne deine erste Antwort mit ``" | spielt Token literal zurück | Token fehlt / falsch / paraphrasiert | +| LD-2 | **Proof-of-Read mit SHA** | Output muss enthalten `{ file, sha256, lines, depth }` pro konsumierter Datei | SHA + Line-Count matchen die echte Datei | SHA fehlt, falsch, oder ``-Platzhalter | +| LD-3 | **3-Sections-Namens-Challenge** | „Nenne 3 Sections aus File X namentlich (Heading + ungefähre Zeilen-Spanne)" | 3 konkrete Headings, plausible Spannen | vage Themen-Labels; keine echten Headings | +| LD-4 | **Negative-Knowledge-Test** | „Steht in File X etwas zu Thema Y?" — wobei Y NICHT drin ist | „nein, nicht enthalten" | halluziniert plausibel klingenden Inhalt zu Y | +| LD-5 | **Line-Range-Quote** | „Quote Zeilen N-M aus File X verbatim" | exakter Quote ODER „Range existiert nicht (File nur K Zeilen)" | paraphrasiert, weicht ab, oder verweigert ohne Grund | + +> **Adoption-Note.** LD-3 / LD-4 / LD-5 sind SHOULD-USE auf Savants +> jede Wave, MAY-USE auf Workers selektiv — typisch wenn +> `phase_reached=internalize` geclaimt wird oder der Output +> overconfident wirkt. Per-Worker-per-Wave-Rotation ist Overkill +> für routinemäßige 200-LoC-Bundles. Siehe §16 Adoption-Tiers. + +### §4.2 Trigger-Heuristik + +| Worker-Antwort-Pattern | Lie-Detector | +|---|---| +| Vage („nicht sicher", „ungefähr 60", „etwa 5 Sections") | KEIN Trigger — ehrliche Unsicherheit. | +| Selbstbewusst **falsch** | FEUERT — Overconfidence + Drift. | +| Selbstbewusst **richtig** ohne Proof-of-Read | FEUERT — Glück und Halluzination sind ohne LD-1..5 nicht unterscheidbar. | + +### §4.3 Drift-Signale (passive Detection, Meta-Agent-Pflicht) + +Der Meta-Agent scannt JEDEN Worker-Status vor dem Goal-Gate-Verdict. +Wenn ein Signal triggert, MUSS der Worker re-dispatched werden ODER +ein Lie-Detector-Test angewendet werden: + +| Signal | Aktion | +|---|---| +| `depth=grep` deklariert bei semantischer Aufgabe | Re-Dispatch mit Pflicht-`depth=full`. | +| `depth=sed-partial` deklariert bei semantischer Aufgabe | Re-Dispatch; SHA-256 über die ganze Datei verlangen. | +| `depth=full` deklariert ohne `sha256` im Proof-of-Read | Stop; Worker MUSS SHA nachliefern. | +| Status-`notes` zitiert eine nicht-existente Section einer Datei | LD-3-Äquivalent fehlgeschlagen post-facto → P0 Re-Dispatch. | +| Status-`notes` ist wortgleich zu einem Sibling-Agent ohne Cross-Read-Vermerk | Lockstep-Drift; Stichprobe LD-5 auf einen der beiden. | +| Eröffnungs-Output zählt eine spezifische Zahl („62 Lehren") OHNE Proof-of-Read auf der Quelle | Overconfidence-Trigger; Agent MUSS SHA + 3 Einträge namentlich nachliefern. | +| Status fasst eine INVARIANT an, aber `proof_of_read` enthält `INVARIANTS.md` nicht | Mandatory `thorough` Re-Read. | + +### §4.4 Beweislast-Regel + +Bei Verdacht: der Worker MUSS aufrüsten. Niemals den Verdacht +„wegerklären" — entweder Proof nachliefern, oder ehrlich +downgraden (`depth=skim`/`grep` mit Notiz). + +--- + +## §5 Stuck-Protokoll + +### §5.1 Fünf typisierte Blocker + +| Typ | Bedeutung | +|---|---| +| `AMBIGUITY` | Spec ist mehrdeutig. Mehr als eine sinnvolle Interpretation. | +| `MISSING_INVARIANT` | Eine Iron Rule sollte den Fall abdecken, tut es aber nicht; die Konvention fehlt. | +| `SPEC_SOURCE_MISMATCH` | Die autoritative Spec sagt X; die Reference-Source tut Y. | +| `BEHAVIOUR_QUESTION` | Möglicher Bug in der Reference-Source; Behaviour-Divergenz braucht RFC. | +| `EXTERNAL_DEPENDENCY` | Drittsystem zickt; Workaround unklar. | + +### §5.2 Das Protokoll + +Wenn stuck, der Worker MUSS: + +1. STOP schreiben von Code. +2. EINEN Eintrag an `META/REQUESTS-FROM-AGENTS.md` anhängen mit + dem §5.3-Schema. +3. Sein `status.json` auf `outcome=RETRY` und `notes=stuck:` + setzen. +4. Idle bis Meta-Agent in `META/ANSWERS-TO-AGENTS.md` schreibt + ODER `META/INVARIANTS.md` aktualisiert. + +### §5.3 Request-Schema + +```markdown +## Agent {{agent_id}}, file , timestamp + +### Question + + +### Tried + + +### Blocker + + +### Proof-of-read attached +- file= sha256=<...> lines=<...> depth=<...> +- file= sha256=<...> lines=<...> depth=<...> +``` + +Der Proof-of-Read MUSS JEDE Datei abdecken, die der Worker in der +Question referenziert. Stuck-Requests ohne Proof-of-Read werden bei +Intake zurückgewiesen (§7.5 in `autoattended-orchestrator-spec.md`). + +### §5.4 Verbotene Alternativen + +Der Worker DARF NICHT: + +- Raten. +- Einen `TODO:`-Kommentar in Code schreiben und weitermachen. +- Außerhalb des Bundles refaktorieren „während er wartet". +- Den gleichen Request zweimal ohne neue Information filen. + +--- + +## §6 Tool-Call-Loop-Detection + +### §6.1 Übernahme von Attractor coding-agent §2.10 + +Ein Worker MUSS seine eigenen letzten `N=10` Tool-Calls (Signature = +Name + Arguments-Hash) auf wiederholende Patterns der Länge 1, 2 +oder 3 scannen. + +``` +Pattern-Länge 1: [A][A][A] — gleiches Tool, gleiche Args, 3+ Mal +Pattern-Länge 2: [A][B][A][B] — alternierend, 2+ Zyklen +Pattern-Länge 3: [A][B][C][A][B][C] — 3-Zyklus, 2+ Zyklen +``` + +### §6.2 Aktion bei Detektion + +Bei Detektion: + +1. Der Worker DARF NICHT den nächsten vorhergesagten Call im Pattern + ausgeben. +2. Der Worker MUSS einen typisierten RETRY-WITH-STEER-Status emittieren: + `outcome=RETRY`, `notes=tool-call-loop:length=:pattern=`. +3. Der Worker MAG einen `META/REQUESTS-FROM-AGENTS.md`-Eintrag unter + dem `AMBIGUITY`-Blocker-Typ (§5.1) filen, wenn der Loop keine + offensichtliche externe Auflösung hat. + +### §6.3 Anti-Pattern AP9 + +Diese Regel wird auch von PP-13 brutally-honest-tester als +Anti-Pattern AP9 (tool-call-loop) durchgesetzt. PP-13s Post-hoc- +Detection greift, wenn der In-Loop-Detector versagt hat. + +> **Implementations-Note (ehrlicher Caveat).** Das aktuelle Claude +> Code `Agent()`-Tool exponiert KEINE Self-Interrupt-API. Der +> §6.1-Detector lebt nur als prompt-level Instruction; Workers +> können sich nicht tatsächlich via Tool-API terminieren — sie +> können nur `outcome=RETRY` emittieren nachdem sie den Loop +> bemerken. Das fängt In-LLM-Oszillation; es fängt NICHT OS-Level- +> Hangs (z. B. `cargo build` stuck auf einem Netzwerk-Resolver). +> Für OS-Level-Hangs MUSS der Orchestrator jeden Spawn in einen +> Wall-Clock-Timeout wrappen. Siehe §16.4. + +--- + +## §7 Proof-of-Read-Schema + +### §7.1 Per-File-Eintrag + +```json +{ + "file": "path/relative/to/repo-root.md", + "sha256": "abc...64-hex...def", + "lines": 412, + "depth": "thorough", + "comment": "Two-Pass-Read; INVARIANTS §3.1-3.4 im Worker-Output zitiert" +} +``` + +### §7.2 Erlaubte Depth-Werte + +``` +grep sed-partial skim +read thorough troubleshooting +fan-out truncated:head-N truncated:tail-N +``` + +`grep`, `sed-partial`, `truncated:*` DÜRFEN NICHT mit Behauptungen +kombiniert werden, die volles Wissen über die Datei implizieren +(LD-3 / LD-4 / LD-5). + +### §7.3 Multi-File-Einträge + +Workers MÜSSEN einen Eintrag pro konsumierter Datei emittieren. Der +Orchestrator-Goal-Gate (PP-13) DARF bis zu drei Einträge pro Worker +pro Wave per LD-2 stichprobenartig prüfen (SHA neu berechnen, +Line-Count vergleichen). + +### §7.4 Speicherung + +Proof-of-Read-Einträge leben in der `status.json` des Workers +(per `autoattended-orchestrator-spec.md` §9.1). Sie werden auch +nach `META/AGENT_LOG.md` als One-Line-Summary nach jedem gelandeten +Chunk gespiegelt: + +``` +## YYYY-MM-DDTHH:MM — A chunk N/M +- chunk N landed (sha ) +- typecheck: green | +- proof-of-read: sha= lines= depth= +``` + +### §7.5 Sentinel-Token-Speicherung + +Das Sentinel-Token wird aus der ersten Reply-Zeile des Workers in +das Feld `sentinel_token` der `status.json` gespiegelt. Mismatch = +FAIL. + +--- + +## §8 Toolchain-Tiers + +### §8.1 Tier 1 (jeder PR — verpflichtend) + +Owned by PP-13 brutally-honest-tester. Per-Language-Adapter: + +> **Adoption-Note.** Default ist Tier-1 **coordinator-side** — PP-13 +> fährt die volle Toolchain einmal auf dem konsolidierten Diff. +> Per-Worker-Tier-1 ist teuer bei 12-Agent-Fan-out (z. B. ~1 GB +> Rust-`target/` pro Worker). Projekte DÜRFEN Tier-1 auf +> per-worker pushen (kleinere Workspaces, schnellerer Feedback) +> durch Setzen von `tier_1_runner: per-worker` in `INVARIANTS.md`. +> Siehe §16.3. + +| Zweck | Rust | Python | TypeScript | Go | +|---|---|---|---|---| +| Lint, keine Warnings | `cargo clippy --all-targets --all-features -- -D warnings` | `ruff check` | `eslint --max-warnings 0` | `golangci-lint run` | +| Formatter-Check | `cargo fmt --check` | `ruff format --check` | `prettier --check` | `gofmt -l` | +| Advisory-Scan | `cargo audit` | `pip-audit` | `npm audit --omit=dev` | `govulncheck ./...` | +| Dep-Policy / Vet | `cargo deny check` | `deptry .` | (Projekt-definiert) | `go vet -all` | +| Typecheck | (Clippy impliziert) | `mypy --strict` | `tsc --noEmit --strict` | (Compiler impliziert) | +| Tests | `cargo test --all-features` | `pytest` | `vitest run` | `go test ./...` | + +### §8.2 Tier 2 (Quality / Maintenance — Opt-in) + +| Zweck | Rust | Python | TypeScript | +|---|---|---|---| +| Unused-Dep-Detector | `cargo machete` | `deptry .` | `depcheck` | +| Unsafe-Scan | `cargo geiger` | `bandit` | (n/a) | +| Public-API-SemVer-Compat | `cargo semver-checks check-release` | `griffe check` | `api-extractor` | +| Spellcheck | `cargo spellcheck` | CSpell | CSpell | + +### §8.3 Tier 3 (Heavier — Opt-in, alle stable) + +| Zweck | Rust | Python | +|---|---|---| +| Bounded Model Checker | `kani` | (none standard) | +| Concurrency Model Checker | `loom` (lib) | (none standard) | +| Mutation Testing | `cargo mutants` | `mutmut` | +| Coverage | `cargo tarpaulin` | `pytest --cov` | + +### §8.4 Tier-1-Invariante + +Für jeden PR, jede Sprache: der Worker beweist, dass er ein +No-Warning-Gate erfüllt BEVOR der Orchestrator den PR öffnet. +Tier-1-Failure mappt direkt auf `outcome=FAIL` in der Status-File +(§9.2 von `autoattended-orchestrator-spec.md`). + +--- + +## §9 Anti-Pattern-Katalog (AP1..AP9) + +PP-13 brutally-honest-tester jagt diese aktiv: + +| # | Anti-Pattern | Detektion | Finding | +|---|---|---|---| +| AP1 | Silent Fallback der Errors schluckt (`unwrap_or_default()`, bare `try { ... } catch {}`, `result, _ := f()`) | grep PR-Diff nach diesen Idiomen | P0 wenn im Nicht-Test-Codepath | +| AP2 | Hardcoded Secret / Token / URL in Source | grep nach plausiblen Secret-Regex | P0 immer | +| AP3 | Compile-Time-Guard fallengelassen (z. B. `#[cfg(test)]`-Block entfernt im Nicht-Test-Kontext) | Diff-Inspektion | P0 wenn Guard load-bearing war | +| AP4 | Test besteht durch Tautologie (asserts `true`, `assert x == x`) | jeden neuen Test-Body lesen | P1 außer wenn es der EINZIGE Test für die Funktion ist (dann P0) | +| AP5 | Behaviour-Divergenz von Spec ohne gemergten RFC | Spec-vs-Implementation-Diff | P0 immer | +| AP6 | Fehlender Parity-Test für einen portierten Handler | `tests/parity_/` prüfen | P0 immer | +| AP7 | Neue Workspace-Dependency nicht in RFC deklariert | Metadata-Diff vs `git log --oneline rfcs/` | P0 immer | +| AP8 | `#[allow(clippy::*)]` / `# noqa` / `// eslint-disable` ohne Begründung | grep nach diesen Directives, Commit-Body prüfen | P1 außer wenn Begründung fehlt (dann P0) | +| **AP9** | **Tool-Call-Loop (Länge 1/2/3 über letzte 10 Calls; siehe §6)** | **In-Loop-Detector ODER Post-hoc-Replay der Tool-Call-History** | **P1; Re-Dispatch mit engerem Scope** | + +--- + +## §10 Definition von Fertig + +Eine Implementierung ist konform, wenn sie ALLE erfüllt: + +- [ ] Jedes Worker-Brief enthält ein eindeutiges `sentinel_token`. +- [ ] Jeder Worker beginnt seine erste Reply MIT dem Sentinel literal. +- [ ] Jeder Worker emittiert eine `status.json` per + `autoattended-orchestrator-spec.md` §9.1 mit einem + Proof-of-Read-Eintrag pro konsumierter Datei. +- [ ] Proof-of-Read-Einträge deklarieren `sha256` + `lines` + eine + Depth aus der §7.2-Liste. +- [ ] Workers fahren den §6.1-Tool-Call-Loop-Detector nach JEDEM + Tool-Call mit `N=10`. +- [ ] Bei Loop-Detection emittiert der Worker `outcome=RETRY` mit + `notes=tool-call-loop:...`. +- [ ] Bei Stuck nutzt der Worker einen der fünf §5.1-Blocker-Typen + und hängt Proof-of-Read für jede referenzierte Datei an. +- [ ] Der Meta-Agent / Supervisor stichprobenartig EINEN von LD-1..LD-5 + auf jedem **Savant** pro Wave (rotierend, sodass der Test nicht + gamed werden kann). Auf routinemäßigen **Workers** ist LD-1 + (Sentinel) Pflicht; LD-3 / LD-4 / LD-5 sind konditional — angewendet + wenn `phase_reached=internalize` geclaimt wird ODER der Output + overconfident wirkt. Siehe §16. +- [ ] Drift-Signale (§4.3) werden für jeden Worker vor dem + Goal-Gate-Verdict gescannt. +- [ ] PP-13 fährt die §8.1-Tier-1-Toolchain für die Sprache des + Workers; Tier-1-Failure → `outcome=FAIL`. +- [ ] PP-13s Anti-Pattern-Scan deckt AP1..AP9 ab. +- [ ] Tool-Output-Truncation (per `coding-agent-loop-spec.md` §5) + taucht im Proof-of-Read als `depth=truncated:head-N` oder + `depth=truncated:tail-N` auf; NIEMALS `depth=full`. +- [ ] `auto_status=false` ist Pflicht; fehlende `status.json` = FAIL. + +--- + +## §11 Cross-Provider-Parity-Matrix + +| Fähigkeit | Claude Code | OpenAI Codex / codex-rs | Gemini CLI | Notizen | +|---|---|---|---|---| +| Sentinel-Token-Replay (LD-1) | Verfügbar via System-Prompt-Addendum | Same | Same | Provider-agnostisch; nutzt Standard-Chat-Completion. | +| Proof-of-Read-Schema (LD-2) | Worker schreibt status.json | Same | Same | File-basiert; Provider-agnostisch. | +| 3-Sections-Challenge (LD-3) | Supervisor-Prompt | Same | Same | Provider-agnostisch. | +| Negative-Knowledge-Test (LD-4) | Supervisor-Prompt | Same | Same | Provider-agnostisch. | +| Line-Range-Quote (LD-5) | Supervisor-Prompt + File-Re-Read durch Supervisor | Same | Same | Provider-agnostisch. | +| Tool-Call-Loop-Detection (§6) | Implementierbar in `Session.run()`-Loop-Wrapper | Same | Same | Loop-Detector-Code ist Provider-unabhängig (operiert auf lokaler Tool-Call-History). | +| Toolchain-Tiers (§8) | Bash-Tools | Bash-Tools | Bash-Tools | Per-Language-Commands identisch. | +| Truncation → `depth=truncated:*` | Wrapper um Tool-Output | Wrapper | Wrapper | Provider-spezifisch in WAS truncated wird (unterschiedliche Default-Toolsets), uniform in WIE es aufgezeichnet wird. | + +--- + +## §12 Appendix A — Worker-Brief-Template + +```markdown +Du bist Agent {{agent_id}} in Wave {{wave_id}} von Sprint {{sprint_id}}. + +Du besitzt Bundle: {{bundle_name}} +Owned Files (read-write): +{{owned_files_table}} + +Read-only Files: +{{read_only_files_table}} + +Spec-Files (autoritativ): +{{spec_files_table}} + +INVARIANTS (lies diese zuerst, depth=thorough): +- META/INVARIANTS.md sha256={{invariants_sha}} lines={{invariants_lines}} + +Reading-Depth required (per anti-skim-agent-spec.md §3.3): +- INVARIANTS.md → thorough +- Spec-Files → full +- Reference-Source-Files → full +- Skeleton-Files → read +- Alles andere → mindestens read + +Status-File: schreib nach {{status_file_path}} matching das Schema in +autoattended-orchestrator-spec.md §9.1. + +Wenn stuck: file EINEN Eintrag in META/REQUESTS-FROM-AGENTS.md per +anti-skim-agent-spec.md §5; setze Status auf outcome=RETRY; idle. + +Done-Kriterien: per autoattended-orchestrator-spec.md §10 + §10 dieser Spec. + +Tool-Call-Loop-Detector: fahre nach jedem Tool-Call per §6. + +SENTINEL TOKEN: {{sentinel_token}} + +Beginne deine erste Reply mit dem Sentinel-Token literal. Dann sage, +in einem Absatz, was du als Bundle verstehst. Dann beginn die Arbeit. +``` + +--- + +## §13 Skeleton-Fill-Contract (Protokoll A) + +> Hinzugefügt 2026-05-18. Gilt für Workers, die in +> `autoattended-orchestrator-spec.md` Protokoll A (Implementation) +> operieren, wo PP-16s Preflight ein auskommentiertes Rust-Skelett +> erzeugt hat (per §14.4 der Orchestrator-Spec). + +### §13.1 Was der Worker bekommt + +Drei Inputs: + +1. Die Skelett-Datei(en) am `skeleton_output_path` mit + `todo!("SOURCE: :")`-Macros an jeder Body-Site. +2. Die originalen Spec- / Reference-Source-Files, die in jeder + `SOURCE:`-Annotation referenziert sind. +3. Ein SHA-256 vom Skelett UND jeder referenzierten Source-File, + gepinnt von PP-16 zur Preflight-Zeit. + +### §13.2 Worker-Pflichten + +Für jedes `todo!("SOURCE: :")`, das der Worker füllt: + +1. **Lies den Source-Range** in der deklarierten Depth (§3.3); Default + für Ports ist `full`. +2. **Zeichne Proof-of-Read auf** für die Source-File im deklarierten + Line-Range (§7.1). +3. **Ersetze `todo!(...)` mit dem Body**, die umgebende Signatur + exakt beibehaltend. Die Signatur kam von PP-16; der Worker + ändert sie nicht ohne Iron-Rule-amendierende RFC. +4. **Quote den Source-Line-Range im Commit-Message-Body** (per + `autoattended-orchestrator-spec.md` §5.6). +5. **Verifiziere die SHA-256 des Skeletts gegen den gepinnten Wert** + beim Arbeitsstart. Wenn das Skelett gedriftet ist (z. B. ein + Sibling-Worker hat es angefasst), MUSS der Worker STOPPEN und + einen `EXTERNAL_DEPENDENCY`-Blocker in + `META/REQUESTS-FROM-AGENTS.md` filen. + +### §13.3 Verboten im Skeleton-Fill-Mode + +- Eine Signatur ändern, die das Skelett liefert (RFC nötig). +- Ein `todo!()` hinzufügen, das NICHT vom Skelett kam (würde + PP-16s Source-Annotation-Disziplin umgehen). +- Einen `// SAFETY:`-Kommentar von einem `unsafe`-Block entfernen + (PP-13 wird ablehnen; PP-16 hat ihn aus einem Grund geschrieben). +- Bodies in einer File außerhalb von `skeleton_output_path` füllen + (§5.1 Unique-File-Write-Disziplin). + +### §13.4 Required Reading-Depth + +| Source-Art | Minimale Depth | +|---|---| +| `SOURCE: :` (die zu portierende Funktion) | `full` für den genannten Line-Range | +| `UNSAFE-SOURCE: :` | `thorough` für den genannten Range UND die Caller der Funktion | +| Die Skelett-Datei selbst | `read` (um die umgebende Signatur zu bestätigen, in die du füllst) | +| `META/INVARIANTS.md` | `thorough` (per §3.3) | + +### §13.5 Validierungs-Regeln + +| Regel | Beschreibung | Severity | +|---|---|---| +| `FILL-001 source-range-read` | Jedes `todo!("SOURCE: P:L-M")`, das der Worker füllt, MUSS im Proof-of-Read des Workers mit `file=P, lines die L-M abdecken, depth=full` auftauchen. | ERROR | +| `FILL-002 skeleton-sha-pin` | Worker MUSS die SHA-256 des Skeletts gegen den Wert verifizieren, den PP-16 gepinnt hat, beim Arbeitsstart. Drift → STOP + `EXTERNAL_DEPENDENCY`. | ERROR | +| `FILL-003 signature-preserved` | Worker DARF NICHT eine Signatur ändern, die das Skelett liefert, ohne gemergten RFC. Diff-Inspektion durch PP-15 setzt durch. | ERROR | +| `FILL-004 unsafe-safety-preserved` | `// SAFETY:`-Kommentare auf `unsafe`-Blöcken vom Skelett MÜSSEN in den gefüllten Body überleben. PP-13 setzt durch. | ERROR | +| `FILL-005 no-new-todo` | Worker DARF NICHT neue `todo!()`-Calls einführen; jedes `todo!()` in der gefüllten Datei MUSS auf einen Skelett-Eintrag zurückverfolgbar sein. | ERROR | + +### §13.6 Definition von Fertig (Skeleton-Fill) + +- [ ] Jedes `todo!()` in den zugewiesenen Skelett-Datei(en) ist ersetzt. +- [ ] Keine neuen `todo!()` eingeführt (FILL-005). +- [ ] Skelett-SHA beim Start gematcht; finale SHA different (FILL-002). +- [ ] Proof-of-Read deckt jede `SOURCE:`-Annotation ab (FILL-001). +- [ ] Alle Signaturen erhalten (FILL-003). +- [ ] Alle `// SAFETY:`-Kommentare erhalten (FILL-004). +- [ ] Tier-1-Toolchain grün auf gefüllter Datei (§8.1). +- [ ] Status-File geschrieben per `autoattended-orchestrator-spec.md` §9.1. + +--- + +## §14 Reading-Phasen (orthogonal zu Depth) + +> Die Reading-Depth-Ladder in §3 sagt **wie viel** einer Datei du +> abdeckst. Die Reading-Phasen in dieser Section sagen **was du +> tust** mit dem, was du abgedeckt hast. Beides braucht's, damit ein +> Read als complete zählt. + +### §14.1 Die vier Phasen + +| # | Phase | Frage, die sie beantwortet | Output den der Worker produzieren können MUSS | +|---|---|---|---| +| 1 | **Survey** | „Was ist in dieser Datei? Welche Form hat sie?" | Section-Liste mit Zeilennummern; File-Shape (N Sections, K LOC, Language); Top-Level-Headline. | +| 2 | **Evaluation** | „Was davon matters für meine Aufgabe?" | Eine Relevanz-Map: welche Sections / Line-Ranges sind relevant fürs aktuelle Bundle, priorisiert P0 / P1 / unused. | +| 3 | **Kritische Findings** | „Was ist falsch, fehlt, widerspricht sich, ist gedriftet?" | Eine typisierte Finding-Liste (Severity P0 / P1) — Iron-Rule-Verletzungen, Spec-vs-Source-Drift, fehlende Sections, Anchors die nicht mehr resolven, tote Referenzen. | +| 4 | **Internalize** | „Kann ich darauf handeln ohne nochmal zu lesen?" | LD-3 bestehen (3-Section-Namens-Challenge), LD-4 (Negative-Knowledge), LD-5 (Line-Range-Quote). Kann faithful paraphrasieren; kann beantworten „was steht NICHT in dieser Datei?". | + +Phasen-Reihenfolge ist typisch **Survey → Evaluation → Kritische +Findings → Internalize**, aber Findings tauchen oft WÄHREND +Internalize auf (der Akt des Internalizens enthüllt Widersprüche). +Ein vollständiges Reading erreicht alle vier; ein partial Reading +stoppt früher und MUSS das deklarieren. + +### §14.2 Phase × Depth-Matrix + +| Depth | Survey | Evaluation | Kritische Findings | Internalize | +|---|:-:|:-:|:-:|:-:| +| `grep` (anti) | partial | nein | nein | nein | +| `sed-partial` / `head-only` (anti) | partial | partial | nein | nein | +| `skim` | ja | partial | partial (nur per-Section) | nein | +| `read` | ja | ja | partial | partial | +| `thorough` | ja | ja | **ja** | **ja** | +| `troubleshooting` | ja | ja | ja (fokussiert auf den Bug) | ja (fokussiert) | +| `fan-out` | ja (per-File flach) | ja | ja | partial (per File) | +| `truncated:head-N` / `truncated:tail-N` | partial | partial | nein | nein | + +Nur `thorough` und `troubleshooting` (innerhalb des fokussierten +Scopes) erreichen die volle Ladder. `fan-out` erreicht Internalize +*per-File*, aber der Inventur-Output ist die Synthese — der Worker +MUSS jede File im Inventar als noch-`thorough`-bedürftig behandeln +bevor er auf sie handelt. + +### §14.3 Phasen-Outputs in der status.json des Workers + +Das `proof_of_read`-Schema (§7.1) wird um ein `phase_reached`-Feld +erweitert, das die höchste completed-Phase pro File benennt: + +```json +{ + "file": "META/INVARIANTS.md", + "sha256": "fa39a3...", + "lines": 412, + "depth": "thorough", + "phase_reached": "internalize", + "phases_evidence": { + "survey": "9 Sections; INVARIANTS-kanonische Struktur erkannt", + "evaluation": "§BBB + §UPSERT-PATTERN sind load-bearing für dieses Bundle", + "critical_findings": "§UPSERT-PATTERN Zeile 187 widerspricht der customer.ttl ogit:CustomerWriter mandatory-attributes (filed REQUESTS-FROM-AGENTS.md#A4-2026-05-18T14:22)", + "internalize": "kann LD-3/4/5 literal beantworten" + } +} +``` + +Die `phases_evidence`-Map ist OPTIONAL wenn `phase_reached=survey` +(kein Evidence über die Section-Liste hinaus required), WIRD aber +required bei `phase_reached >= evaluation`, weil diese Phase +Judgment claimt. + +### §14.4 Mapping Lie-Detector-Tests auf Phasen + +Jeder LD-1..LD-5-Test (§4.1) probt eine spezifische Phase. Der +Meta-Agent SOLLTE den Spot-Check über die vier Phasen rotieren, +damit Workers nicht gamen können, welche Phase zu faken ist. + +| Test | Probt Phase | Was eine passing Answer beweist | +|---|---|---| +| LD-1 Sentinel-Token | **Survey** des Briefs | Der Worker hat den Brief tatsächlich in den Context geladen. | +| LD-2 Proof-of-Read mit SHA | **Survey** der File | Der Worker accessed die File am deklarierten Content. | +| LD-3 3-Sections-Namens-Challenge | **Survey + Evaluation** | Der Worker kann Struktur lokalisieren UND wählte welche Sections zu beachten. | +| LD-4 Negative-Knowledge-Test | **Internalize** | Der Worker hat ein faithful Mental-Model gebaut — kann beantworten „was steht NICHT in dieser Datei" ohne zu halluzinieren. | +| LD-5 Line-Range-Quote | **Internalize + Kritische Findings** | Der Worker kann verbatim recallen UND Drift zwischen Recall und Source detektieren. | + +Ein Worker, der `phase_reached=internalize` deklariert, MUSS LD-3, +LD-4 UND LD-5 bestehen können. Spot-Check-Failure bei einer +geclaimten Phase ⇒ Phase-Claim wird abgelehnt und der Proof-of-Read +wird auto-downgraded auf die höchste nachweisbar bestandene Phase. + +### §14.5 Per-File-Required-Phase nach File-Art + +Unterschiedliche File-Arten BENÖTIGEN unterschiedliche Minimum- +Phasen. Das Worker-Brief MUSS die Per-File-Phase-Requirements +zusammen mit den Depth-Requirements deklarieren: + +| File-Art | Minimum-Depth | Minimum-Phase | +|---|---|---| +| `META/INVARIANTS.md` | `thorough` | **internalize** | +| `CLAUDE.md` / `BOOT.md` / RFCs | `thorough` | **internalize** | +| Memory-Files (`CONTEXT.md` / `JOURNAL.md` / `TODO.md`) | `thorough` | **internalize** | +| Spec-Files fürs Bundle (z. B. TTL, OpenAPI, JSON-Schema) | `full` (read) | **internalize** | +| Reference-Source für Ports | `full` | **internalize** | +| Skeleton-Files die der Worker füllt | `read` | **evaluation** | +| Sibling-Bundle-Files (read-only Context) | `skim` | **evaluation** | +| Files referenziert für allgemeine Orientation | `skim` | **survey** | +| Files referenziert nur für Symbol-Lookup | `grep` | **survey** | + +Wenn ein Worker bei einer Phase unter dem Required stoppt, zählt +der Read NICHT als complete — selbst wenn die Depth ausreichend +war. Beide Achsen müssen die Bar klären. + +### §14.6 Kritische-Findings-Eskalation + +Findings produziert in Phase 3 (Kritische Findings) werden nach +Severity geroutet: + +| Finding-Severity | Filed wo | Worker-Aktion | +|---|---|---| +| P0 — Iron-Rule-Verletzung im Input, Spec-vs-Source-Widerspruch, gebrochener Anchor der das Bundle betrifft | `META/REQUESTS-FROM-AGENTS.md` mit Blocker-Typ aus §5.1; Worker idled | STOP Arbeit; nicht zum Commit weitergehen | +| P1 — kleinere Inkonsistenz, tote Referenz außerhalb des Bundle-Scopes, Typo, stale Comment | `Altlasten.md` / `TECH_DEBT.md`-Zeile mit der Bundle-ID des Workers | Arbeit fortsetzen; der Orchestrator triaged später | +| INFO — Observation die das Bundle nicht betrifft | Notes-Feld in `status.json`; nirgendwo sonst filed | Arbeit fortsetzen | + +Ein Worker der internalized, aber NICHT ein P0-Finding escaliert +ist in Verletzung: Missing-Escalation ist selbst ein P0-Finding, +das PP-13 catchen wird (Anti-Pattern AP1 — „silent Fallback der +Errors schluckt" — generalisiert hier als „silent Skim der +Findings schluckt"). + +### §14.7 Validierungs-Regeln + +| Regel | Beschreibung | Severity | +|---|---|---| +| `PHASE-001 phase-declared` | Jeder `proof_of_read`-Eintrag MUSS ein `phase_reached`-Feld enthalten. Absent ⇒ behandelt als `phase_reached=survey` (der schwächste Claim). | ERROR | +| `PHASE-002 phase-monotonic-with-depth` | Ein `phase_reached`-Claim MUSS konsistent mit der §14.2-Matrix sein. Z. B. `depth=grep` + `phase_reached=internalize` ist invalid. | ERROR | +| `PHASE-003 phase-evidence-required` | Wenn `phase_reached >= evaluation`, MUSS die `phases_evidence`-Map vorhanden sein mit non-empty Entries für jede geclaimte Phase. | ERROR | +| `PHASE-004 file-kind-phase-bar` | Wenn das Worker-Brief eine Minimum-Phase per §14.5 für eine File deklariert, MUSS der `phase_reached` des Workers für diese File ≥ dem deklarierten Minimum sein. | ERROR | +| `PHASE-005 critical-findings-routed` | P0-Findings produziert während Phase 3 MÜSSEN nach `META/REQUESTS-FROM-AGENTS.md` filed sein BEVOR der Worker irgendwelchen Code commited, der vom betroffenen Input abhängt. | ERROR | +| `PHASE-006 internalize-passes-LD-3-4-5` | Ein Claim von `phase_reached=internalize` MUSS Spot-Checks von LD-3, LD-4 und LD-5 in Rotation überleben. Failure ⇒ Auto-Downgrade auf höchst-bestandene Phase. | ERROR | + +### §14.8 Definition von Fertig (Per-File-Read) + +Ein Read einer einzelnen File ist complete wenn ALLE: + +- [ ] Depth aus §3 auf dem deklarierten Level. +- [ ] Phase aus §14.1 erreicht das required Minimum per §14.5. +- [ ] `proof_of_read`-Eintrag enthält `sha256`, `lines`, `depth`, + `phase_reached` und `phases_evidence` für `evaluation+`. +- [ ] Jedes P0-kritische-Finding ist filed bevor der Worker commited. +- [ ] LD-3 / LD-4 / LD-5-Spot-Checks bestanden wenn + `phase_reached=internalize` geclaimt ist. + +--- + +## §15 Kognitive Anti-Patterns (CA1..CA4) + +> Wo AP1..AP9 (§9) **Output**-Probleme fangen — der Code selbst sieht +> falsch aus — fangen CA1..CA4 **Cognition**-Probleme — die Art wie +> der Worker zum Output gekommen ist, ist falsch. CA-Findings tauchen +> oft zur gleichen Zeit auf wie AP-Findings; die Unterscheidung ist: +> CA-Fixes brauchen Process-Change (Re-Read, Re-Think, Re-Spawn), +> während AP-Fixes manchmal in-place editiert werden können. +> +> Die kognitiven Anti-Patterns sind joint owned: der Meta-Agent spotted +> sie beim PR-Review via Lie-Detector (§4); PP-13 spotted sie beim +> Code-Review durch Korrelation von Commit-Timestamps mit +> Proof-of-Read-Timestamps. + +### §15.1 Die vier kognitiven Anti-Patterns + +| # | Name | Wie es aussieht | Detection-Signature | Counter-Pattern | Severity | +|---|---|---|---|---|---| +| **CA1** | **Cognitive Dissonance** | Worker sieht einen Widerspruch zwischen zwei autoritativen Sources (Spec vs. Reference-Source, INVARIANT vs. Comment, TTL vs. Code) und löst durch Hand-Waving oder Picken eines ohne Investigation. Die Dissonance wird übermalt statt eskaliert. | Output enthält Phrasen wie „I went with", „I chose", „I preferred Y because it feels right / is already there / compiles", ohne entsprechenden `SPEC_SOURCE_MISMATCH`-Eintrag in `META/REQUESTS-FROM-AGENTS.md`. | File `SPEC_SOURCE_MISMATCH` (§5.1) und idle bis der Meta-Agent ein RFC schreibt. Niemals Dissonance unilateral auflösen. | **P0** | +| **CA2** | **Dunning-Kruger Overconfidence** | Worker claimt confident Knowledge in einem Bereich, wo seine tatsächliche Depth shallow ist. Der Agent weiß nicht, was er nicht weiß, also ist sein Sense of Certainty un-kalibriert. Der Output liest sich definitiv, wo der Read dünn war. | Ein `phase_reached=internalize`-Claim (§14), der LD-3 / LD-4 / LD-5-Spot-Checks failt. Eine spezifische numerische Behauptung („62 Lehren", „die Signatur hat 3 Argumente") ohne entsprechenden `proof_of_read`-SHA. Confident Paraphrase, wo die Source eigentlich etwas anderes sagt. | Auto-Downgrade des Phase-Claims auf die höchst-bestandene Phase (per `PHASE-006`). Re-Read mit der proper Depth + Phase. Wenn der Worker weiter übersteuert, route ihn zu einem kleineren Bundle. | **P0** | +| **CA3** | **Kahneman/Tversky Easy-Path (System-1-Short-Circuit)** | Worker pattern-matched Surface-Features des Inputs — „File sieht aus wie ein CRUD-Handler, also muss es ein CRUD-Handler sein" — ohne den System-2-Check zu fahren (Read den tatsächlichen Function-Body, vergleich gegen die Spec). Easy-Path ist am schnellsten wenn Surface die Reality matched, aber verheerend wenn nicht. | Die erste Reply ist plausibel-correct-klingend, aber der Proof-of-Read ist `depth=grep` oder `depth=sed-partial`. Output beschreibt Struktur in generischen Termen („standard Route-Handler", „typische Migration") statt spezifischen Termen („die Function auf Zeilen 47-91 dispatched auf req.path"). | Force System-2: verlange LD-2 (SHA + Line-Count) und LD-5 (Line-Range-Quote) bevor irgendein structural Claim akzeptiert wird. Reading-Depth MUSS mindestens `read` sein; Phase MUSS mindestens `evaluation` sein, bevor irgendein Output, der einen structural Claim macht. | **P0** | +| **CA4** | **Eager Amok** | Worker fängt an Code zu schreiben (oder zu committen, oder zu pushen), bevor die required Reading- + Planning-Phasen complete sind. Enthusiasm rennt der Disziplin voraus. Die Arbeit *sieht* produktiv aus — es gibt einen Diff — aber sie ist auf incomplete Understanding gebaut. | Der erste Code-Write-Timestamp ist vor den `proof_of_read`-SHA-Pin-Timestamps für eine oder mehrere required Files (§14.5). `status.json` zeigt Commits, die landen, während `phase_reached` noch `survey` oder `evaluation` auf Files ist, die bei `internalize` sein sollten. Worker-Narrative springt von Brief-Read zu First-Commit ohne sichtbaren Thinking-Step. | STOP und verlange complete Proof-of-Read für ALLE Files an ihrer required §14.5-Minimum-Phase BEVOR irgendein Commit. Die Iron Rule gilt, egal wie „obvious" die Implementation scheint. | **P0** | + +### §15.2 Warum alle vier P0 sind + +Jedes von CA1..CA4 produziert Output, der *aussieht* als wäre er +richtig. AP1..AP9 produzieren Output, der falsch aussieht (ein +`unwrap_or_default()` ist sichtbar; ein fehlender Parity-Test ist +sichtbar). Kognitive Anti-Patterns produzieren Output, dessen +Correctness komplett auf dem unverifierbaren Claim ruht, dass der +Worker gelesen + verstanden + gedacht hat, bevor er schrieb. Sie +sind P0 weil sie den Trust-Contract brechen, auf den der Meta-Agent +sich verlässt, wenn er Diffs reviewed ohne den Read des Workers zu +wiederholen. + +### §15.3 Joint Ownership: wer fängt was + +| Anti-Pattern | Catch-Site | Detection-Methode | +|---|---|---| +| CA1 Cognitive Dissonance | Meta-Agent (PR-Review) + PP-15 (Cross-Source-Diff) | Grep PR-Commit-Messages nach „I went with" / „I chose" / „preferred" gegen Spec-vs-Source-Mismatch; check `REQUESTS-FROM-AGENTS.md` für Abwesenheit des entsprechenden Blockers. | +| CA2 Dunning-Kruger Overconfidence | Meta-Agent (Lie-Detector-Spot-Check) | Rotate LD-3 / LD-4 / LD-5 auf einem Worker pro Wave; cross-check `phase_reached`-Claims gegen tatsächliches Passing. | +| CA3 Kahneman/Tversky Easy-Path | Meta-Agent (Proof-of-Read-Inspection) + PP-13 (Output-vs-Source-Diff) | Worker-Output liest sich als Paraphrase statt Quote; SHA fehlt; Reading-Depth deklariert inkonsistent mit Output-Claims. | +| CA4 Eager Amok | PP-13 (Commit-Timestamp-Audit) + Meta-Agent (status.json-Ordering-Check) | Commit-Timestamps sind vor den `proof_of_read`-SHA-Pin-Timestamps; `phase_reached` war unter dem required Minimum beim First-Commit. | + +### §15.4 Counter-Patterns: wie ein gesunder Worker sich verhält + +| Anti-Pattern | Healthy-Alternative | +|---|---| +| CA1 | „Ich habe bemerkt, die Spec sagt X aber der existierende Code tut Y. Ich file `SPEC_SOURCE_MISMATCH`. Idle." | +| CA2 | „Ich bin confident über §3 von INVARIANTS.md (depth=thorough, phase=internalize). Ich bin uncertain über §6 (depth=skim, phase=survey). Ich vertiefe §6 bevor ich darüber etwas behaupte." | +| CA3 | „Bevor ich diese File-Struktur beschreibe: hier ist `proof_of_read: { file=X, sha256=..., depth=read, phase_reached=evaluation }`. Die Struktur ist: [spezifische Section-Namen mit Zeilennummern]." | +| CA4 | „Reading-Phase complete auf allen 4 required Files. Kritische Findings filed (Zero P0). Status: `phase_reached=internalize` auf allen Files. JETZT beginne ich den ersten Commit." | + +### §15.5 Validierungs-Regeln + +| Regel | Beschreibung | Severity | +|---|---|---| +| `CA-001 dissonance-escalation` | Wenn der Output eines Workers Spec-vs-Source-Divergenz erwähnt, MUSS `META/REQUESTS-FROM-AGENTS.md` einen entsprechenden `SPEC_SOURCE_MISMATCH`-Blocker-Eintrag enthalten. Abwesenheit ⇒ CA1 P0-Finding. | ERROR | +| `CA-002 confidence-calibration` | Ein `phase_reached=internalize`-Claim, der LD-3 / LD-4 / LD-5-Spot-Check failt ⇒ CA2 P0; Phase-Claim auto-downgraded. | ERROR | +| `CA-003 system-2-required-before-structural-claim` | Jeder structural Claim über den Content einer File (Function-Count, Section-Namen, Signature-Shapes) MUSS preceded sein von einem `proof_of_read`-Eintrag mit `depth >= read` UND `phase_reached >= evaluation`. Sonst CA3 P0. | ERROR | +| `CA-004 read-before-write-ordering` | `status.json` MUSS zeigen, dass alle required-Minimum `proof_of_read`-Einträge timestamped sind BEVOR dem First-Code-Commit-Timestamp für Files an der §14.5-required-Minimum-Phase. Sonst CA4 P0. | ERROR | + +### §15.6 Mindset-Level-Relation zu den vier Savants + +Die vier Savants in `autoattended-orchestrator-spec.md` §4.0 haben +jeweils eine *kognitive* Posture, die einer spezifischen CA +widersteht: + +| Savant | Mindset | Widersteht primär | +|---|---|---| +| PP-13 brutally-honest-tester | „was würde in Production um 3 Uhr morgens brechen, was der Author sich weggeredet hat?" | CA1 (Sich-Wegreden IST Cognitive Dissonance) + CA4 (Production bricht nicht wegen Enthusiasmus) | +| PP-14 convergence-architect | „was könnte das werden, das wir nicht sehen?" | CA3 (Easy-Path schließt Possibilities premature) | +| PP-15 baton-handoff-auditor | „lining sich diese Contracts an den Nähten wirklich auf?" | CA1 (Dissonance versteckt sich oft an Handoffs) | +| PP-16 preflight-drift-auditor | „matched der Plan immer noch das System wie es jetzt gerade ist?" | CA2 (Overconfidence in einen Plan der von der Reality gedriftet ist) | + +Der volle 4-Savant-Pass ist jointly ein Antibody gegen alle vier +kognitiven Anti-Patterns. Eine Wave, die nur einen Savant fährt, +catched nur die CAs, denen der Mindset dieses Savants widersteht; +eine Wave, die das Cooperative Council fährt (Orchestrator-Spec +§15), catched alle vier. + +### §15.7 Definition von Fertig (Kognitive Hygiene) + +Ein Worker besteht das Kognitive-Hygiene-Gate wenn ALLE: + +- [ ] `CA-001` clean: jede Spec-vs-Source-Erwähnung ist matched mit einem filed `SPEC_SOURCE_MISMATCH`-Blocker. +- [ ] `CA-002` clean: jeder `phase_reached=internalize`-Claim überlebt LD-3/4/5-Spot-Checks. +- [ ] `CA-003` clean: jeder structural Claim ist backed durch ausreichenden `proof_of_read`. +- [ ] `CA-004` clean: Read-Timestamps sind vor Commit-Timestamps für alle required-Minimum-Files. +- [ ] Worker hat nicht `I went with` / `I chose` / `I preferred` ausgegeben ohne associated Blocker-Filing. + +--- + +## §16 Adoption-Tiers (Projekt-spezifisch) + +> Specs shippen eine maximalistische Surface, damit jeder +> vernünftige Use-Case gecovered ist. Reale Projekte adopten +> Subsets. Diese Section benennt, was ein Projekt am Tag eins +> adopten SOLLTE (Tier-A), was den Cost nur bei High-Stakes wert +> ist (Tier-B), was Projekt-überschreibbar ist (Tier-C) und was +> ehrlich bekannte Limits hat (Tier-D). +> +> **Ursprung:** Field-Test-Feedback aus einem 12-Agent-Rust-Fan-out +> (Sprints PR-X4 cascade / PR-X10..13 consolidation / PR-X12 codec) +> wo ~1 GB Per-Worker-`target/`-Dirs Universal-Per-Worker-Tier-1- +> Toolchain prohibitiv teuer machten, und wo die fehlende +> Self-Interrupt der `Agent()`-API den §6.1-Detector zu prompt-level +> only zwang. + +### §16.1 Tier-A — am Tag eins adopten (minimum viable) + +Die minimale Surface, die ≥80% des Werts des Frameworks bei ≤20% +des Ceremony liefert. + +| § | Was | Warum Pflicht | +|---|---|---| +| §3 | Reading-Depth-Ladder per File | Wichtigste Anti-Skim-Primitive. | +| §5 | 5 typisierte Stuck-Blocker (`AMBIGUITY` / `MISSING_INVARIANT` / `SPEC_SOURCE_MISMATCH` / `BEHAVIOUR_QUESTION` / `EXTERNAL_DEPENDENCY`) | Ersetzt vages „report under 200 words" mit crispem typisiertem Routing. | +| §7 | `proof_of_read`-Schema in `status.json` | `{file, sha256, lines, depth, phase_reached}`. Trivialer Overhead; großer Audit-Win. | +| §14 | Reading-Phasen per File + §14.5-Per-File-Kind-Minimum | Fängt „Agent claimt confident File-Content ohne zu lesen" — der häufigste Silent-Skim-Failure. | +| §15 | CA1..CA4 kognitive-Anti-Pattern-Framing | Die Linse, durch die ein Savant-Audit schon schaut; billig zu adopten. | +| §15.6 | 4-Savant-Council für P0-Review auf Consolidation-Sprints | High-Leverage-Audit; läuft auf Opus, einmal pro Sprint. | +| §4.1 LD-1 | Sentinel-Tokens | ~50 LoC Ceremony pro Brief; fängt den trivialen „Agent hat das Brief nicht gelesen"-Fall. | +| §6 | Prompt-level Tool-Call-Loop-Instruction (best-effort, siehe §16.4) | Fängt In-LLM-Oszillation, wenn der Worker die Instruction honored. | +| §17 | PR-Lifecycle + Auto-Resolve (Worker erstellt PR, subscribed auf CI-/Review-Events, klassifiziert jedes Event silent-fix / ask-user / skip) | Das „done" eines Workers ist PR gemerged oder PR geschlossen, nicht Branch gepusht. Ohne §17 stoppt das Framework am Push und der Human owned die CI-Loop. | + +### §16.2 Tier-B — adopten nur für Savants / High-Stakes + +Reserviere für Review-Agents (PP-13/14/15/16) und High-Stakes-Worker- +Spawns. Skip für routinemäßige 200-LoC-Skeleton-Fills. + +| § | Was | Wann adopten | +|---|---|---| +| §4.1 LD-3 / LD-4 / LD-5 | 3-Section-Challenge / Negative-Knowledge / Line-Range-Quote | Auf Savants **jede Wave**. Auf routinemäßigen Workers **nur wenn** `phase_reached=internalize` geclaimt wird ODER der Output overconfident wirkt. Nicht als routinemäßige Per-Worker-per-Wave-Rotation. | +| §13 Skeleton-Fill (Protokoll A) | `todo!("SOURCE:")`-Marker erzwingen Read-Before-Fill | High-Stakes-Ports (Python→Rust-Transcode, x265→Rust-Codec) wo Source-Fidelity matters. Skip für Greenfield-Prose-Features. | +| Volle §10 / §13.6 / §14.8 / §15.7 DoD-Checklisten | Per-PR-DoD-Verifikation | Per-Sprint, nicht per-PR, bis v0.2-Prune. Siehe §16.6. | + +### §16.3 Tier-C — Projekt-überschreibbare Defaults + +Defaults, die diese Spec empfiehlt, aber die reale Projekte oft +überschreiben. Der Override SOLLTE in `INVARIANTS.md` des Projekts +dokumentiert sein. + +| § | Default | Override-Scenario | Typische Projekt-Wahl | +|---|---|---|---| +| §8.1 Tier-1-Toolchain | Coordinator-side (PP-13 fährt einmal auf konsolidiertem Diff) | Kleiner Workspace wo Per-Worker-Compile schnell ist | `tier_1_runner: per-worker` | +| §4.1 LD-3/4/5-Rotation | Spot-Check nur auf Savants + overconfident Workers | Projekt will Per-Worker-per-Wave-Rotation | `lie_detector_rotation: per-worker-per-wave` | +| §13 Skeleton-Fill | Opt-in pro Sprint via `preflight.skeleton: enabled` | Greenfield-Code ohne SOURCE-Referenz | `preflight.skeleton: disabled` (Default für Greenfield) | +| §14.5 Per-File-Kind-Minimum-Phase | INVARIANTS.md / Spec / Reference = internalize | Projekts INVARIANTS lebt woanders oder existiert nicht | Projekt-definiertes `file_kind_phase_map` in `INVARIANTS.md` | + +### §16.4 Tier-D — known-limited (ehrliche Caveats) + +| § | Caveat | +|---|---| +| §6.1 In-Loop-Tool-Call-Detection | Das aktuelle Claude Code `Agent()`-Tool exponiert KEINE Interrupt-API. Der Detector lebt nur als prompt-level Instruction. Fängt In-LLM-Oszillation; fängt NICHT OS-Level-Hangs. Wrap jeden Spawn in einen Wall-Clock-Timeout auf der Orchestrator-Schicht für OS-Hangs. | +| §8.1 Per-Worker-Tier-1 | Auf Rust-Workspaces mit ~1 GB Per-Worker-`target/`-Dirs ist Per-Worker-Tier-1 bei 12-Agent-Fan-out disk-prohibitiv. Nutze den §16.3-Coordinator-side-Override. | +| §4.1 LD-1-Sentinel-Tokens | Slight Per-Brief-Ceremony (~50 LoC). Projekt DARF das Token auf Orchestrator-Level templaten statt per-worker Brief, um den Cost zu amortisieren. | +| Spec-Line-Count bei v0.1.0 DRAFT | Diese Spec ist intentional maximalistisch für die erste Revision. Plan einen v0.2-Prune der vier DoD-Checklisten (§10 / §13.6 / §14.8 / §15.7) nachdem ein realer Sprint mit dem Framework gelaufen ist — behalte nur Items, die Field-Bugs gefangen haben. | + +### §16.5 Sprint-by-Sprint-Adoption Worked-Example + +Ein 12-Agent-Rust-Fan-out mit Cascade + Codec + Consolidation: + +| Sprint | Tier-A adopted | Tier-B adopted | Tier-C Overrides | +|---|---|---|---| +| PR-X4 Splat-Cascade (12 Workers, interne Refactor) | full | LD-1-Sentinel only; skip LD-3/4/5 auf routinemäßigen Workers | `tier_1_runner: coordinator` | +| PR-X12 Codec (Rust-Port von x265-Reference) | full | volle §13-Skeleton-Fill (High-Stakes-Source-Fidelity-Port); LD-3/4/5 auf Consolidation-Worker | `tier_1_runner: coordinator` | +| PR-X10+11+13 Consolidation-Review (Savant-Pass) | n/a (Review-Pass) | volles §15.6-Vier-Savant-Council auf Opus | n/a | + +### §16.6 v0.2-Prune-Targets (slim wenn field-tested) + +Nach einem vollen Sprint mit dieser Spec, slim die folgenden Sections +auf Items, die field-tested Catches produziert haben: + +| Section | Aktuelle Items | Slim-Target | +|---|---:|---| +| §10 Definition von Fertig | 13 | behalte ~5, die echte Bugs fangen | +| §13.6 Skeleton-Fill-DoD | 7 | behalte ~3 | +| §14.8 Per-File-Read-DoD | 5 | behalte ~3 | +| §15.7 Kognitive-Hygiene-DoD | 5 | behalte ~3 | +| §8.1 / §8.2 / §8.3 Tier-Tabellen | volle Per-Language-Matrix | slim auf Entries, die tatsächlich im Field laufen | + +Ziel: Spec-Line-Count fällt 30-50% bei v0.2, während die Patterns +erhalten bleiben, die echte Bugs gefangen haben. + +--- + +## §17 PR-Lifecycle + Auto-Resolve + +> Workers stoppen nicht bei „Branch gepusht". Die Done-Bedingung +> eines Workers ist **PR gemerged** ODER **PR geschlossen durch +> Orchestrator/Human als FAIL** — der Lifecycle reicht über CI- +> Iteration und Review-Comment-Resolution. Diese Section +> spezifiziert, was zwischen dem ersten Push des Workers und einem +> dieser terminalen States passiert. +> +> **Tier:** Tier-A per §16.1 für jeden Sprint, der PRs öffnet. +> **Transport:** `mcp__github__create_pull_request` + +> `mcp__github__subscribe_pr_activity` + `git push` für Fixes; +> Events arrive als ``-Envelopes (siehe +> `agent-coordination-mcp-spec.md` §3.3). + +### §17.1 Der erweiterte Worker-Lifecycle + +``` +READ → WRITE → TEST → COMMIT → PR → SUBSCRIBE → [AUTO-RESOLVE-LOOP] → MERGE | FAIL + ↑ ↓ + │ Event arrival + │ classify (§17.4) + │ silent-fix | ask-user | skip + └ bei silent-fix: Commit pushen +``` + +Steps 1-4 sind das existierende §13.2-Work-Pattern. Steps 5-7 sind +neu. MERGE / FAIL sind terminal — Worker schreibt seine finale +`status.json` und ruft `mcp__github__unsubscribe_pr_activity`. + +### §17.2 PR-Erstellung (Step 5) + +Nach dem First-Push ruft der Worker: + +``` +mcp__github__create_pull_request( + owner=, + repo=, + head=, # z. B. claude/wave-12-A4 + base=, # aus Sprint-Header + title=": (WT-NN)", + body="""\ +## Bundle-Ownership +{{ownership_table}} + +## Status +{{status_json_excerpt}} + +## Proof-of-Read +{{proof_of_read_summary}} + +## Sentinel +{{sentinel_token}} +""", + draft=, # per Sprint-Header + labels=["sprint-", "bundle-"] +) +``` + +Der PR-Body MUSS das Sentinel-Token literal enthalten. Der +Orchestrator kann offene PRs nach Sentinel-Presence greppen als +schneller LD-1-Check (per `PR-007`). + +### §17.3 Subscription (Step 6) + +Innerhalb von 60 Sekunden nach PR-Erstellung MUSS der Worker rufen: + +``` +mcp__github__subscribe_pr_activity(owner, repo, pullNumber) +``` + +Der Worker tritt dann in einen Event-driven Idle-State. Events +arrive als ``-Envelopes mit CI-Run- +Completions, Review-Comments, PR-State-Changes (merged/closed) +und Label-Changes. + +### §17.4 Der Drei-Optionen-Event-Handling-Decision-Tree + +Für jedes Event MUSS der Worker in eine von drei Optionen +klassifizieren (matched das CCA2A-Handling-Protokoll aus dem +governing Prompt-Template): + +| Option | Wann | Aktion | +|---|---|---| +| **1. Silent-Fix** | Confidence hoch; Fix in-scope des Worker-Bundles; Fix widerspricht nicht Spec / INVARIANTS | Read failing CI-Logs / Review-Comment voll (§3-Depth-Ladder, §14.5-Minimum-Phase für Log-Files: `read` + `phase=evaluation`); make the Fix; push Commit; update `status.json`; continue idle for next Event. Reply auf PR NUR wenn der Fix eine spezifische Review-Question resolved. | +| **2. Ask-User (file PROPOSAL)** | Ambiguity (CA1 / CA3 Trigger); cross-bundle Implikationen; Spec-vs-Comment-Widerspruch; Reviewer fragt „should X be Y or Z?" | Append `Kind=PROPOSAL`-Eintrag an `AGENT_LOG.md` (`agent-coordination-mcp-spec.md` §1.3) mit der Question; idle bis Orchestrator/User antwortet via `ANSWERS-TO-AGENTS.md`. Pushe KEINE spekulativen Fixes. | +| **3. Skip-Silently** | Duplicate Event; stale CI; „LGTM" / Approval; Bot-Comment (Dependabot et al); Event addressed in einer vorigen Iteration | Record die Classification auf `AGENT_LOG.md` (`Kind=DECISION`, Body: `skip-silent: `); continue idle. Reply NICHT auf den PR. | + +### §17.5 Event-Taxonomie + Default-Classification + +| Event-Klasse | Spezifisches Signal | Default-Option | Confidence required | +|---|---|---|---| +| CI Lint-Failure | rustfmt / clippy single-line | silent-fix | high | +| CI Typecheck-Failure | single Error, in-Bundle | silent-fix | high | +| CI Typecheck-Failure | Error in Shared-Zone | ask-user (cross-bundle) | n/a | +| CI Test-Failure | Regression im eigenen Bundle; Root-Cause aus Log identifizierbar | silent-fix | medium | +| CI Test-Failure | Regression anderswo | ask-user | n/a | +| CI Build-Time-out | first occurrence | skip-silent (re-CI); wenn recurring → ask-user | n/a | +| CI Dependency-Resolve-Failure | neue transitive Dep, fehlender Crate, Version-Konflikt | ask-user (`EXTERNAL_DEPENDENCY`-Blocker) | n/a | +| CI OOM | first occurrence | ask-user (Orchestrator allocated Memory) | n/a | +| Review-Comment „könntest du auch X" | X ist in-Bundle | silent-fix | medium | +| Review-Comment „should this be X or Y?" | Ambiguity | ask-user (`AMBIGUITY`-Blocker) | n/a | +| Review-Comment „blocking — need RFC" | Spec-vs-Impl-Mismatch | ask-user (`SPEC_SOURCE_MISMATCH`-Blocker) | n/a | +| Review-Comment „LGTM" / Approval | terminal-success-adjacent | skip-silent | n/a | +| Bot-Comment (Dependabot, codecov, sonarcloud, …) | informational | skip-silent | n/a | +| @-Mention an spezifischen Human-User | gehört einem Menschen | skip-silent (reply nicht) | n/a | +| PR merged | terminal | schreib `outcome=SUCCESS`, unsubscribe, exit | n/a | +| PR geschlossen ohne Merge | terminal (Orchestrator/Human FAIL'd es) | schreib `outcome=FAIL`, unsubscribe, exit | n/a | + +### §17.6 Budget + Termination + +| Limit | Default | Bei Überschreitung | +|---|---|---| +| Max Auto-Fix-Iterationen pro PR | 5 | Worker emittiert `outcome=FAIL`, Body: `auto-resolve-budget-exhausted`; Orchestrator entscheidet next | +| Max Wall-Clock pro PR | 24 h (Projekt-konfigurierbar) | Same as above | +| Per-Iteration-Token-Cost-Cap | per §16-Model-Stylesheet | Escalate zu Opus nur wenn Stylesheet allows | +| Aufeinanderfolgende `skip-silent`-Events | 20 | Worker schreibt `STATUS`-Eintrag, der die Silence notes, und re-subscribed (PR ist in Quiet-State) | + +### §17.7 Kognitive Anti-Patterns erweitern sich auf Auto-Resolve + +Jedes CA1..CA4 aus §15 gilt für jede Auto-Resolve-Iteration, nicht +nur die initiale Implementation. Validation-Rules CA-001..CA-004 +gelten unverändert. PR-005 unten erweitert die Cross-Bundle-Rule. + +| Anti-Pattern | Auto-Resolve-spezifische Form | +|---|---| +| CA1 Cognitive Dissonance | Worker liest ein Review-Comment, das INVARIANTS widerspricht, und „fixt einfach per Comment" ohne `SPEC_SOURCE_MISMATCH` zu filen. | +| CA2 Dunning-Kruger Overconfidence | Worker pushed einen Auto-Fix ohne `proof_of_read` auf das Failing-Log; claimt `internalize` des Failures ohne LD-Evidence. | +| CA3 Kahneman/Tversky Easy-Path | Worker pattern-matched „CI rot → push den gleichen Fix wie letztes Mal" ohne das tatsächliche Failure zu lesen. | +| CA4 Eager Amok | Worker pushed einen Fix bevor das volle CI-Log gelesen ist; commited bevor §17.4-Classification complete. | + +### §17.8 Wire-Format-Integration + +Jede Auto-Resolve-Aktion emittiert einen Eintrag auf `AGENT_LOG.md` +per `agent-coordination-mcp-spec.md` §1.3: + +```markdown +## 2026-05-19T08:14 — DECISION[INFO]: A4 silent-fix clippy::redundant_clone (sonnet, claude/wave-12-A4) + +**Author:** A4 +**Kind:** DECISION +**Severity:** INFO +**Refs:** PR-#427 commit-fa00b1c +**Proof-of-read:** +- file=ci/clippy-log.txt sha256=8e1a... lines=47 depth=full +- file=src/customer/master.rs sha256=4c0b... lines=312 depth=read + +--- + +Clippy hat ein `Vec.clone()` auf Zeile 187 geflaggt. Reviewed die +Call-Site; der Clone war Leftover aus einem prior Refactor. +Ersetzt mit `&borrow`. Commit fa00b1c gepusht. Awaiting re-CI. +``` + +Auto-Resolve-Aktionen sind first-class auf dem Wire-Format — der +Orchestrator und jede subscribed Sibling-Session sehen sie in +Echtzeit. + +### §17.9 Validierungs-Regeln + +| Regel | Beschreibung | Severity | +|---|---|---| +| `PR-001 worker-created-PR` | Innerhalb von 30 Minuten nach dem First-Push MUSS der Worker einen PR via `mcp__github__create_pull_request` erstellt haben. | ERROR | +| `PR-002 subscription-active` | Innerhalb von 60 Sekunden nach PR-Erstellung MUSS der Worker `mcp__github__subscribe_pr_activity` gerufen haben. | ERROR | +| `PR-003 max-iterations` | Auto-Resolve DARF §17.6-Budget NICHT überschreiten ohne Escalation. Budget-Exhaustion ⇒ `outcome=FAIL`, Reason `auto-resolve-budget-exhausted`. | ERROR | +| `PR-004 cognitive-hygiene-extends` | CA-001..CA-004 (§15.5) gelten unverändert für jede Auto-Resolve-Iteration, nicht nur initiale Implementation. | ERROR | +| `PR-005 cross-bundle-fix-forbidden` | Ein Worker DARF NICHT Commits pushen, die Files außerhalb seines Bundles anfassen, auch nicht während Auto-Resolve. Cross-Bundle-Failures escalieren via `AGENT_LOG.md` `Kind=PROPOSAL`. | ERROR | +| `PR-006 event-classification-recorded` | Jedes Event, das der Worker received, MUSS per §17.4 klassifiziert und die Classification an `AGENT_LOG.md` (`Kind=DECISION`) appended sein. | ERROR | +| `PR-007 sentinel-in-pr-body` | Der PR-Body MUSS das Sentinel-Token des Workers literal enthalten. | ERROR | +| `PR-008 unsubscribe-on-terminal` | Bei PR-Merge oder -Close MUSS der Worker `mcp__github__unsubscribe_pr_activity` rufen bevor er seine terminale `status.json` schreibt. | ERROR | +| `PR-009 no-reply-on-skip` | Eine `skip-silent`-Classification DARF NICHT einen Reply auf dem PR produzieren (avoid PR-Noise-Pollution von Agents). | WARNING | + +### §17.10 Definition von Fertig (Auto-Resolve) + +Ein Worker besteht das Auto-Resolve-Gate wenn ALLE: + +- [ ] PR erstellt (`PR-001`). +- [ ] Innerhalb 60s subscribed (`PR-002`). +- [ ] Jedes Event per §17.4 klassifiziert und auf `AGENT_LOG.md` aufgezeichnet (`PR-006`). +- [ ] Keine Cross-Bundle-Fix-Commits (`PR-005`). +- [ ] CA-001..CA-004 clean auf jeder Iteration (`PR-004`). +- [ ] Sentinel-Token im PR-Body (`PR-007`). +- [ ] Auto-Resolve-Budget nicht überschritten ohne Escalation (`PR-003`). +- [ ] Unsubscribed und terminale `status.json` geschrieben (`PR-008`). +- [ ] Terminal-Outcome ist `SUCCESS` (PR merged) ODER `FAIL` (PR closed without merge ODER Budget exhausted) ODER `RETRY` (Worker hat einen Blocker filed und wartet auf Orchestrator-Antwort). + +### §17.11 Adoption-Tier-Placement + Overrides + +Diese Section ist **Tier-A** (Pflicht) per §16.1 für jeden Sprint, +der PRs öffnet. Zwei Projekt-Overrides sind möglich (Tier-C): + +| Setting | Default | Override-Scenario | Override-Wert | +|---|---|---|---| +| Per-Worker-PR-Creation (§17.2) | Jeder Worker öffnet seinen eigenen PR | Projekt prefers a single Orchestrator-Consolidation-PR per Wave (per `autoattended-orchestrator-spec.md` §3.4) | `pr_ownership: orchestrator-consolidation` in `INVARIANTS.md` | +| Subscription-Transport (§17.3) | `mcp__github__subscribe_pr_activity` natives MCP | Environment ohne GitHub-MCP (offline, rate-limited, non-GitHub-Host) | `pr_event_transport: polling` (60s-Interval via `mcp__github__pull_request_read`) | + +Tier-D ehrlicher Caveat: `subscribe_pr_activity` braucht Netzwerk + +GitHub-API-Rate-Budget (5000 req/h authenticated). Für 12-Agent- +Fan-outs, die long Auto-Resolve-Loops fahren, monitor Rate-Limit- +Consumption; der Orchestrator DARF Subscriptions auf sich selbst +konsolidieren (eine Subscription pro PR mit dem Orchestrator +re-broadcasting Events an interested Workers) um das API-Budget +zu amortisieren. + +--- + +*Ende der Datei anti-skim-agent-spec.md.* diff --git a/.claude/ATT/DE/autoattended-orchestrator-spec.md b/.claude/ATT/DE/autoattended-orchestrator-spec.md new file mode 100644 index 000000000..73554ac8c --- /dev/null +++ b/.claude/ATT/DE/autoattended-orchestrator-spec.md @@ -0,0 +1,1257 @@ +# Autoattended-Orchestrator-Spezifikation + +> **Sprache:** Deutsch · siehe `../autoattended-orchestrator-spec.md` für die englische Quellfassung. +> +> **Status:** DRAFT · **Version:** 0.1.0 · **Stand:** 2026-05-17 +> **Format:** NLSpec (nach [strongdm/attractor](https://github.com/strongdm/attractor)) +> **Substrat:** Designed um auf `attractor-spec.md` zu komponieren; läuft +> als der `house`-shaped `manager_loop`-Node einer Attractor-Pipeline. + +--- + +## §1 Überblick + +### §1.1 Zweck + +Der Autoattended-Orchestrator fährt Wave-basierte Fan-out- / Fan-in- +Sprints von LLM-Worker-Agents gegen eine Codebase, mit vier +spezialisierten Review-Gates (den „4 Savants") an fixen Lifecycle- +Positionen. Es ist die Projekt-agnostische Distillation des Patterns, +das in +[`AdaWorldAPI/WoA/.claude/v0.1/CLAUDE-CONTEXT.md`](https://github.com/AdaWorldAPI/WoA/blob/main/.claude/v0.1/CLAUDE-CONTEXT.md) +beschrieben und über 26 Repositories am 2026-05-17 gehardent wurde. + +### §1.2 Zentrale Abstraktionen + +- **Wave**: ein paralleler Fan-out von N Worker-Agents (typisch N = 12), + endend in einem einzelnen Consolidation-Commit durch den Orchestrator. + Ein Sprint ist eine Sequenz von Waves. +- **Worker**: ein LLM-Agent-Process der ein **Bundle** von Files + besitzt. Workers laufen isoliert (`isolation: "worktree"`), lesen + nicht den In-Flight-State anderer Workers, koordinieren nur über + den Orchestrator und das File-Blackboard. +- **Savant**: eine von vier spezialisierten Review-Rollen (PP-13 / + PP-14 / PP-15 / PP-16), die den Sprint an fixen Lifecycle-Positionen + gaten. +- **Iron Rule**: eine nicht-überschreibbare Invariante, deklariert in + `INVARIANTS.md`, durchgesetzt von jedem Worker und vom Meta-Agent + beim PR-Review. + +### §1.3 Relation zu `attractor-spec.md` + +Der Orchestrator ist realisierbar als Attractor-Pipeline, deren +DOT-Graph die kanonische Form hat: + +``` +start (Mdiamond) + → preflight-drift-auditor (box, PP-16 Verdict-Gate) + → fan-out (component, N=12) + → fan-in (tripleoctagon, Consolidation-Commit) + → baton-handoff-auditor (box, PP-15) + → brutally-honest-tester (box, PP-13, goal_gate=true, retry_target=fan-out) + → exit (Msquare) +``` + +PP-14 (convergence-architect) läuft bei PRE-PLAN, *außerhalb* des +Graphen, auf dem proposed Sprint-Plan bevor der Graph gerendert wird. + +### §1.4 Was diese Spec NICHT ist + +- Kein Pipeline-Runner. Sie nimmt an, dass attractor-spec.md (oder + ein Equivalent) die Runtime ist. +- Kein Coding-Agent-Loop. Per-Worker-Verhalten ist in + [`anti-skim-agent-spec.md`](./anti-skim-agent-spec.md). +- Kein Koordinations-Transport. Der Cross-Agent-Message-Bus ist in + [`agent-coordination-mcp-spec.md`](./agent-coordination-mcp-spec.md). + +--- + +## §2 Terminologie + +| Begriff | Definition | +|---|---| +| **Sprint** | Eine Sequenz aus einer oder mehreren Waves auf ein einzelnes geplantes Outcome (ein Feature, ein Port, ein Refactor). | +| **Wave** | Ein paralleler Fan-out + Fan-in-Zyklus. | +| **Bundle** | Das Set von Files, das ein Worker besitzt (read-write); deklariert in `META/SPRINT-N-PLAN.md`. | +| **Ownership-Tabelle** | Das Per-Worker-Mapping Bundle → owned-files + read-only-files. | +| **Iron Rule** | Eine nicht-überschreibbare Invariante; Verletzung ist eine P0-Finding. | +| **Goal-Gate** | Ein Node, dessen Verdict SUCCESS sein MUSS damit die Wave exiten kann. Implementiert attractor §3.4. | +| **Savant** | PP-13 / PP-14 / PP-15 / PP-16. Siehe §4. | +| **Meta-Agent** | Der 13. Agent. Besitzt Plan-Review, Inbox-Drain, PR-Review. | +| **REQUESTS-FROM-AGENTS.md** | Die append-only Inbox für Stuck-Worker-Messages. | +| **INVARIANTS.md** | Die Single-Source-of-Truth für Cross-Cutting-Rules. | + +--- + +## §3 Der Wave-Loop + +### §3.1 Sechs Steps + +``` +1. Plan → Orchestrator partitioniert Arbeit in N Bundles +2. Sprint → N parallele Worker-Agents +3. Meta-Review → ein oder mehrere Savant-Agents +4. Fix P0s → Orchestrator wendet Fixes an + verifiziert Tier-1-Gates +5. Commit + PR → Orchestrator (ein PR pro Bundle ODER ein kombinierter PR) +6. Repeat → Orchestrator plant die nächste Wave +``` + +### §3.2 Eine Iron Rule über alle Steps + +Der Orchestrator ist die einzige Rolle, die außerhalb des +zugewiesenen Bundles schreiben darf. Workers bleiben in ihrer Lane. +Savants sind read-only (sie filen Findings; der Orchestrator wendet +Fixes an). + +### §3.3 Wave-Sizing + +| Wave-Size | Worker-Model | Wann nutzen | +|---|---|---| +| 3-6 | Mid-Tier (z. B. Sonnet) | Tight Scope, wohldefinierte Bundles, niedrige Cross-Cutting-Concern | +| 7-12 | Mid-Tier | Die Standard-Wave-Form — die meiste Arbeit passt hier | +| > 12 | Mid-Tier, split | Pre-fan in 2 Waves mit Savant-Pass dazwischen | +| 1-2 (Planning) | Top-Tier (z. B. Opus) | Architektur / Design / Cross-Cutting-Entscheidungen | +| 1 (Savant) | Mid-Tier oder Top-Tier | Per §4 | + +Eine 12-Worker-Wave kostet ungefähr **250.000 bis 350.000 Input- +Tokens** (Bundle-Briefings + Reference-Reads) plus **30.000 bis +50.000 für den Savant-Pass**. Implementierungen MÜSSEN das gegen das +Context-Window-Budget des Models pro Worker tracken und Pläne +ablehnen, deren Per-Bundle-Brief `worker.max_brief_tokens` +übersteigt. + +### §3.4 Der Consolidation-Pass (Step 5 ⇒ atomic Commit) + +Nachdem alle Workers in einer Wave zurück sind, macht der +Orchestrator EINEN Consolidation-Commit der: + +1. Die Commits jedes Bundles in Dependency-Order reinholt +2. Die append-only Merge-Zones (Module-Registry, Integration-Test- + List etc.) auflöst, die in INVARIANTS.md deklariert sind +3. Tier-1-Gates gegen den kombinierten State re-runs (siehe + [`anti-skim-agent-spec.md`](./anti-skim-agent-spec.md)) +4. Einen PR fileed (oder N PRs wenn Bundles wirklich independent) + +Implementierungen DÜRFEN NICHT 12 Mini-Commits am shared Registry-File +erlauben. Worker-Pushes zu Shared-Registry-Files werden auf der +Worker-Layer abgelehnt (per Unique-File-Write-Rule, §5.1). + +--- + +## §4 Die 4 Savant-Slots + +### §4.0 Mindsets (nicht Rollen) + +Jeder Savant ist ein **Mindset** — eine Denkweise, kein Checklist- +Operator. Das Verdict-Vokabular in §4.1 ist der *Output*; das +Mindset in dieser Section ist der *Input*, den der System-Prompt +des Savants aktivieren sollte. + +| Savant | Mindset-Persona | Frame durch den sie lesen | Failure, gegen die sie existieren | +|---|---|---|---| +| **PP-13 brutally-honest-tester** | Der Implementierungs-Principal, der seit zehn Jahren shipped + on-Call macht | „was würde in Production um 3 Uhr morgens brechen, was der Author sich weggeredet hat?" | Self-Deception in Implementation-Quality-Claims | +| **PP-14 convergence-architect** | Der Creative-Design / F&E-Principal, der divergente Möglichkeiten exploriert | „was könnte das werden, das wir nicht sehen? welche latente shared Form wird dupliziert?" | Premature Convergence und versäumte Cross-Slice-Synergien | +| **PP-15 baton-handoff-auditor** | Der DTO- / Interface-Architekt — die Person, die in den Lücken zwischen Komponenten lebt | „lining sich diese Contracts an den Nähten wirklich auf? wessen Hand geht als nächste an den Stab?" | Cross-Boundary-Drift; silent Contract-Shape-Mismatches | +| **PP-16 preflight-drift-auditor** | Der Principal-System-Architekt mit dem vollen System-State im Kopf | „matched der Plan immer noch das System wie es jetzt gerade ist, oder hat sich Main bewegt während wir geplant haben?" | Stale Plans gegen ein bewegtes Main; dropped Requirements | + +Der System-Prompt für jeden Savant SOLLTE mit dem Mindset-Satz +beginnen, nicht mit der Verdict-Checklist. Die Checklist ist ein +Backstop; das Mindset ist die Linse. + +### §4.1 Slot-Tabelle + +| Savant | Phase | Owns | Verdict-Vokabular | +|---|---|---|---| +| **PP-13 brutally-honest-tester** | POST-IMPL | Within-Bundle Compile / Lint / Test / Spec-Match | LAND / HOLD / REJECT | +| **PP-14 convergence-architect** | PRE-PLAN | Divergent Ideation, latente shared Infrastructure | OPPORTUNITY-NOW / WORTH-EXPLORING / DROP (nie REJECT) | +| **PP-15 baton-handoff-auditor** | DURING-IMPL | Cross-Bundle- / Cross-Crate- / Cross-Module-Boundary-Contracts | CATCH-CRITICAL / CATCH-LATENT / CLEAN | +| **PP-16 preflight-drift-auditor** | PRE-SPAWN | Spec-vs-Main-Drift, hand-waved Scope, dropped Requirements | SPAWN-CLEAR / SPAWN-CAUTION / SPAWN-BLOCKED | + +### §4.2 Verdict-Vokabular-Nicht-Überlappung ist eine Design-Invariante + +Jeder Savant hat ein **nicht-überlappendes Verdict-Vokabular**, damit +eine Finding nicht über Phasen wandern kann ohne re-klassifiziert zu +werden. Der Meta-Agent nutzt sein eigenes Vokabular (GO / +GO-WITH-CONDITIONS / BLOCK für Plan-Review; P0 / P1 für PR-Review). + +Wenn ein Savant ein Verdict aus dem Vokabular eines anderen Savants +returned, wird die Finding beim Intake abgelehnt und zurückgeroutet. +Das ist ERROR-Severity in Validation (§7). + +### §4.3 Non-Use → Route-Tabelle + +Jeder Savant-Prompt MUSS explizite „non-use → route to PP-X"-Lines +enthalten. Beispiele: + +- PP-13 findet ein Cross-Crate-Boundary-Issue → route zu **PP-15**. +- PP-15 findet ein Spec-vs-Main-Drift → route zu **PP-16**. +- PP-16 findet ein Within-Bundle-Compile-Error → route zu **PP-13**. +- PP-14 findet irgendetwas Compile-related → route zu **PP-13**. + +### §4.4 PP-13-Spezifika + +Owns die kanonische Toolchain Tier-1+2+3. Tier 1 läuft jeder PR; +Tiers 2+3 Opt-in. Siehe +[`anti-skim-agent-spec.md` §8](./anti-skim-agent-spec.md#8-toolchain-tiers) +für die Language-Adapter-Tabellen. + +Anti-Pattern-Katalog: AP1..AP8. + +### §4.5 PP-15-Spezifika + +Owns Cross-Boundary-Commands: Workspace-Level-Lint/Typecheck, +Public-API-Diff (`cargo public-api`, `api-extractor`, `griffe check`), +Cross-Symbol-Grep, Cross-Repo `git log`, Metadata-Dump. + +Anti-Pattern-Katalog: BAP1..BAP10. Acht Boundary-Klassen: +Module-Module, Crate-Crate, Package-Package, Repo-Repo, Public-API, +DTO/Wire-Format, DB-Schema-to-ORM, CLI-Surface. + +### §4.6 PP-16-Spezifika + +Owns Git + Grep only — `git log master`, `git show`, +`git diff main...HEAD`, list-pull-requests, Grep alter Symbole über +`.claude/plans/` und `.claude/specs/`. Läuft KEIN Compile/Test/Lint. + +Anti-Pattern-Katalog: PD1..PD10. Sechs Achsen: Plan-vs-Main-HEAD, +Plan-vs-Open-PRs, Plan-vs-Recent-Merges, Plan-vs-RFC-Status, +Plan-vs-Invariants, Plan-vs-Spec. + +### §4.7 PP-14-Spezifika + +Owns Surface-Inspection only (z. B. `cargo doc`, `cargo tree`, +`cargo expand`) plus WebSearch / Paper-Search für Cross-Pollination. +Hat KEINE Compile/Test-Gates. Anti-Pattern-Katalog: EP1..EP8. + +--- + +## §5 Worker-Iron-Rules + +### §5.1 Unique-File-Write-Disziplin + +Jeder Worker schreibt in eine **eindeutige neue File** in seinem +Bundle. Nie zwei Workers an der gleichen existierenden File +gleichzeitig. Append-Conflicts sind garantiert wenn verletzt. + +Shared-Merge-Zones (Module-Registry, Integration-Test-List) MÜSSEN +explizit in INVARIANTS.md als **append-only** deklariert sein: jeder +Worker append eine Zeile; der Orchestrator löst Order im +Consolidation-Commit. Worker-Pushes zu undeklarierten Shared-Files +sind ERROR-Severity (§7). + +### §5.2 Worktree-Branches starten von `origin/`, nicht der lokalen Working-Branch + +Eine Worktree-Branch gestartet von einer stale lokalen Working-Branch +verpasst silently Sibling-Worker-Commits. Workers MÜSSEN: + +```bash +git fetch origin +git checkout -b agent/N +``` + +Implementierungen MÜSSEN `isolation: "worktree"` für jeden Worker- +Spawn setzen. + +### §5.3 Atomic Consolidation-Pass + +Siehe §3.4. Der Orchestrator macht EINEN Consolidation-Commit pro +Wave, nicht N Mini-Commits. + +### §5.4 Pre-Wave-Helper-Call-Audit + +Vor dem Fan-out scannt der Orchestrator jedes Bundle nach +uncommitted Helper-Call-Dependencies. Bundles mit non-zero +unresolved-helper-Count benötigen einen **Helper-Hoist** committed +vor dem Fan-out. Sonst inventieren N Workers den gleichen Helper N +verschiedene Wege. Das ist PP-14s Job bei PRE-PLAN. + +### §5.5 Chunking-Disziplin (die load-bearing Iron Rule) + +Files größer als ~150 Zeilen MÜSSEN via `tee -a` in Chunks geschrieben +werden, mit einem Commit pro Chunk. NIEMALS ein 500-Zeilen-Heredoc + +Commit + Push in derselben Runde. Connection-Drops mid-serialize +verlieren Arbeit. + +Der `tee -a`-Loop hat doppelte Pflicht: Chunking (File-Size) UND +Agent-Logging (Status-Zeile an `AGENT_LOG.md` nach jedem Chunk). + +### §5.6 Source-Quoting-Commit-Messages + +Für Ports und Behavior-Preserving-Rewrites: jede Commit-Message +quoted die Source-File + Line-Range für die portierte Funktion. +Reviewer können `grep -rn "Source: " /` machen um jedes +Port-Site zu finden. Ohne das kreucht Behavior-Drift unsichtbar rein. + +--- + +## §6 Sprint-Plan-Format + +### §6.1 Der Plan ist ein DOT-Graph (oder YAML-Mirror) + +Ein Sprint-Plan ist ein DOT-Graph (per attractor-spec.md §2) oder +sein Equivalent in YAML. Die kanonische Wave-Form ist in §1.3. + +### §6.2 Required Node-Attribute pro Bundle + +Jeder `box`-shaped Worker-Node MUSS deklarieren: + +``` +[ + agent_id="A4", + bundle_name="customer-master-data", + owned_files="src/customer/master.rs,src/customer/master/types.rs", + read_only_files="../WoA/woa/blueprints/customer.py,../WoA/models.py", + spec_files="vendor/ogit/NTO/WorkOrder/entities/customer.ttl", + sentinel_token="WAVE-12-A4-7f3c", + proof_of_read=true, + worker_model="sonnet", + isolation="worktree", + status_file=".claude/board/wave-12/A4-status.json" +] +``` + +### §6.3 Required Edge-Attribute + +| Attribut | Werte | Default | +|---|---|---| +| `condition` | Expression über `outcome` und `context.*` | `outcome==SUCCESS` | +| `fidelity` | `full` / `compact` / `summary:medium` / `truncate` | `compact` | +| `route_on_fail` | Node-ID | `null` | + +### §6.4 YAML-Mirror (wenn DOT nicht verfügbar) + +```yaml +sprint: + id: SPRINT-12-customer-master + wave_size: 12 + base_branch: origin/main + workers: + - agent_id: A4 + bundle_name: customer-master-data + owned_files: [src/customer/master.rs, src/customer/master/types.rs] + read_only_files: [../WoA/woa/blueprints/customer.py, ../WoA/models.py] + spec_files: [vendor/ogit/NTO/WorkOrder/entities/customer.ttl] + sentinel_token: WAVE-12-A4-7f3c + proof_of_read: true + worker_model: sonnet + isolation: worktree + status_file: .claude/board/wave-12/A4-status.json + savants: + pre_plan: PP-14 + pre_spawn: PP-16 + during_impl: PP-15 + post_impl: PP-13 + goal_gate: PP-13 + retry_target: fan-out +``` + +--- + +## §7 Validierungs-Regeln + +Implementierungen MÜSSEN diese Lints gegen jeden Sprint-Plan vor +dem Fan-out laufen lassen. Severity matched die Konvention von +attractor-spec.md §7. + +| Regel | Beschreibung | Severity | +|---|---|---| +| `WAVE-001 unique-write` | Keine zwei Bundles listen die gleiche File unter `owned_files`. | ERROR | +| `WAVE-002 declared-shared` | Jede File die in zwei `owned_files` von Bundles auftaucht MUSS als `append-only` in INVARIANTS.md deklariert sein, sonst ERROR. | ERROR | +| `WAVE-003 sentinel-token-present` | Jeder Worker-Node MUSS ein eindeutiges `sentinel_token` haben. | ERROR | +| `WAVE-004 proof-of-read-required` | `proof_of_read=true` ist Pflicht; `false` braucht expliziten human Override im Commit-Body. | ERROR | +| `WAVE-005 goal-gate-has-retry` | Wenn ein Node `goal_gate=true` hat, MUSS er auch ein `retry_target` haben. (Übernommen von attractor §7.2.) | ERROR | +| `WAVE-006 isolation-worktree` | Jeder Worker-Node MUSS `isolation="worktree"` deklarieren. | ERROR | +| `WAVE-007 status-file-path` | Jeder Worker-Node MUSS einen `status_file`-Path deklarieren, eindeutig für diese Wave. | ERROR | +| `WAVE-008 worker-brief-size` | Das gerenderte Brief für jeden Worker DARF `worker.max_brief_tokens` (Default 8000) NICHT überschreiten. | WARNING | +| `WAVE-009 helper-hoist` | Pre-Wave-Helper-Call-Audit (§5.4) MUSS Zero unresolved-Helpers liefern. | WARNING | +| `WAVE-010 verdict-vocabulary` | Jedes Savant-Verdict MUSS aus seinem eigenen Vokabular (§4.2) sein. Cross-Vokabular-Verdicts werden zurückgeroutet. | ERROR | +| `WAVE-011 auto-status-false` | `auto_status` MUSS `false` sein. Fehlender Status MUSS als FAIL behandelt werden. (Kollidiert mit attractors Default.) | ERROR | +| `WAVE-012 reachability` | Jeder Node ist erreichbar von `start`. (Übernommen von attractor §7.2.) | ERROR | +| `WAVE-013 start-exit` | Exakt ein `start`, mindestens ein `exit`. (Übernommen von attractor §7.2.) | ERROR | +| `WAVE-014 inbox-drained` | Bei Wave-Start MUSS REQUESTS-FROM-AGENTS.md keine unbeantworteten Einträge aus prior Waves haben. | WARNING | +| `WAVE-015 invariants-fresh` | Jedes Worker-Brief MUSS die SHA-256 von INVARIANTS.md enthalten und der Worker MUSS Proof-of-Read darauf machen. | ERROR | + +--- + +## §8 Konfiguration + +```yaml +# .claude/ATT/config/orchestrator.yaml +orchestrator: + wave_size: + default: 12 + min: 1 + max: 24 + worker: + max_brief_tokens: 8000 + isolation: worktree # MUSS worktree sein + proof_of_read: required # required | optional (Default required) + auto_status: false # MUSS false sein + consolidation: + one_pr_per_bundle: false # true | false (false = ein kombinierter PR) + re_run_tier_1: true # MUSS true sein + savants: + pre_plan: PP-14 + pre_spawn: PP-16 + during_impl: PP-15 + post_impl: PP-13 + goal_gate_owner: PP-13 + retry: + max_replans_per_sprint: 3 + on_partial_failure: redispatch_with_tighter_scope + budget: + wave_max_input_tokens: 350000 + savant_max_input_tokens: 50000 + warn_if_exceeds: 0.8 # Warnung bei 80% des Budgets +``` + +--- + +## §9 Status-File-Schema + +### §9.1 Übernahme von Attractors status.json mit `auto_status=false` + +Jeder Worker MUSS eine `status.json` an seinen deklarierten +`status_file`-Path schreiben. Schema cribbed aus attractor +Appendix C und verschärft: + +```json +{ + "agent_id": "A4", + "bundle_name": "customer-master-data", + "sentinel_token": "WAVE-12-A4-7f3c", + "outcome": "SUCCESS", + "preferred_label": "land", + "suggested_next_ids": [], + "context_updates": { + "customer.master.files_created": 3, + "customer.master.parity_tests_passed": 7 + }, + "notes": "zwei Helper-Funktionen hoisted in src/customer/_shared.rs (bereits append-only in INVARIANTS.md §AppendOnly deklariert)", + "proof_of_read": [ + { "file": "INVARIANTS.md", "sha256": "...", "lines": 412, "depth": "thorough" }, + { "file": "../WoA/woa/blueprints/customer.py", "sha256": "...", "lines": 891, "depth": "full" }, + { "file": "vendor/ogit/NTO/WorkOrder/entities/customer.ttl", "sha256": "...", "lines": 137, "depth": "full" } + ], + "tier_1_gates": { + "lint": "GREEN", + "fmt": "GREEN", + "audit": "GREEN", + "deny": "GREEN", + "typecheck": "GREEN", + "tests": { "passed": 14, "failed": 0 } + } +} +``` + +### §9.2 Die fünf Outcomes + +| Outcome | Bedeutung | +|---|---| +| `SUCCESS` | Alle Tier-1-Gates grün; Spec-Contract erfüllt; ready für PR. | +| `PARTIAL_SUCCESS` | Bundle-Arbeit shipped, aber eine definierte Sub-Task deferred (filed in `Altlasten.md` / `TECH_DEBT.md`). | +| `RETRY` | Self-detected Stuck-Loop (per `anti-skim-agent-spec.md` §6) oder Token-Budget-Exhaustion. Orchestrator re-spawned mit engerem Scope. | +| `FAIL` | Tier-1-Gates rot, ODER Proof-of-Read fehlt, ODER Sentinel-Token failed, ODER Iron Rule verletzt. | +| `SKIPPED` | Die Preconditions des Bundles (z. B. ein Dependency-Bundle) wurden nicht erfüllt. | + +### §9.3 Missing-Status-Policy + +`auto_status=false` ist Pflicht. Wenn ein Worker exit'ed ohne +`status_file` zu schreiben, MUSS der Orchestrator die Wave als FAIL +für dieses Bundle behandeln. + +Hier kollidieren wir absichtlich mit attractors `auto_status=true`- +Default. Siehe [`README.md` „Wo es kollidiert"](./README.md#wo-es-mit-attractors-haltung-kollidiert-und-warum-wir-bei-unserer-position-bleiben). + +--- + +## §10 Definition von Fertig (Konformanz-Checklist) + +Eine Implementierung ist konform, wenn sie ALLE erfüllt: + +- [ ] Sprint-Pläne sind DOT-Graphen oder §6.4-YAML-Mirrors mit + allen Required Node-Attributen (§6.2) und Edge-Attributen (§6.3). +- [ ] Validierungs-Regeln §7 WAVE-001 bis WAVE-015 laufen als Teil + von `preflight-drift-auditor` und blocken Fan-out bei ERROR. +- [ ] Jeder Worker spawned mit `isolation: "worktree"` (§5.2). +- [ ] Jeder Worker schreibt eine `status.json` matching das §9.1-Schema. +- [ ] Fehlende `status.json` wird als FAIL behandelt (`auto_status=false`). +- [ ] Die vier Savants sind präsent mit nicht-überlappenden Verdict- + Vokabularen (§4.2) und expliziten Non-Use-Route-Tabellen (§4.3). +- [ ] PP-13 owns die Sprach-spezifische Tier-1-Toolchain + (`anti-skim-agent-spec.md` §8). +- [ ] PP-15 owns BAP1..BAP10 + 8 Boundary-Klassen (§4.5). +- [ ] PP-16 owns PD1..PD10 + 6 Achsen (§4.6) plus die §7-Validierungs- + Regeln. +- [ ] Worker-Briefs deklarieren `proof_of_read: true` und ein + eindeutiges `sentinel_token` (§6.2). +- [ ] Der Meta-Agent (die 13. Rolle) drained REQUESTS-FROM-AGENTS.md + ≥ 2× pro Tag während einer Wave (4h-Reply-Latency-Target). +- [ ] PR-Review klassifiziert Findings NUR als P0 oder P1; nie P2/P3. +- [ ] `INVARIANTS.md` ist ≤ 500 Zeilen; Split required oberhalb. +- [ ] Ein Consolidation-Commit pro Wave am Shared-Registry (§3.4); + Zero N-Mini-Commit-Anti-Pattern detected. +- [ ] Chunking-Disziplin durchgesetzt: Files > 150 Zeilen via + `tee -a` geschrieben (§5.5). +- [ ] Source-Quoting-Commit-Messages auf allen Ports (§5.6). +- [ ] Context-Fidelity-Ladder (§11) ist implementiert mit Vorrang + edge > node > graph > default und die §11.2-Token-Budgets + als Guidance behandelt (Hard-Cap ist `worker.max_brief_tokens`). +- [ ] `fidelity=truncate` enthebt einen Worker NICHT von der + `anti-skim-agent-spec.md` §3.3-Reading-Depth-Ladder. + +--- + +## §11 Cross-Language-Parity-Matrix + +| Aspekt | Rust | Python | TypeScript | Go | +|---|---|---|---|---| +| Tier-1-Lint | `cargo clippy --all-targets --all-features -- -D warnings` | `ruff check` | `eslint --max-warnings 0` | `golangci-lint run` | +| Tier-1-Format-Check | `cargo fmt --check` | `ruff format --check` | `prettier --check` | `gofmt -l` | +| Tier-1-Advisory-Scan | `cargo audit` | `pip-audit` | `npm audit --omit=dev` | `govulncheck ./...` | +| Tier-1-Dep-Policy | `cargo deny check` | `deptry .` | (Projekt-definiert) | `go vet -all` | +| Tier-1-Typecheck | (Clippy impliziert) | `mypy --strict` | `tsc --noEmit --strict` | (Compiler impliziert) | +| Tier-1-Tests | `cargo test --all-features` | `pytest` | `vitest run` | `go test ./...` | +| Module-Registry append-only File | `src/lib.rs` / `mod.rs` | `__init__.py` | `index.ts` / `index.js` | `pkg.go` | +| Workspace-Metadata | `cargo metadata` | `pipdeptree` | `pnpm list --depth=2` | `go list -m all` | +| Public-API-Diff | `cargo public-api` | `griffe check` | `api-extractor run` | `apidiff` | + +--- + +## §11A Context-Fidelity + +> **Übernommen aus `attractor-spec.md` §5.4.** Das ist die einzige +> Übernahme, die ihre eigene Section braucht, weil sie ändert, wie +> Briefs an Workers gerendert werden. +> +> *Hinweis: In der englischen Quelle trägt diese Section irrtümlich +> auch die Nummer §11 (Konflikt mit §11 Cross-Language-Parity-Matrix). +> Die deutsche Fassung nutzt §11A bis das in der EN-Quelle aufgeräumt +> ist.* + +### §11A.1 Warum Fidelity wichtig ist + +Eine 12-Worker-Wave läuft das Brief des Orchestrators durch jeden +Worker. Wenn jeder Worker den vollen Orchestrator-Context erbt, +skaliert der Input-Token-Cost einer Wave linear mit +Workers × shared-Context-Size, was verschwendet wenn Bundles klein +und wohl-scoped sind. + +Fidelity-Modes lassen den Orchestrator pro-Edge / pro-Node / pro- +Graph einstellen, wie viel von seinem Context jeder Worker erbt. + +### §11A.2 Vier Modes + Token-Budgets + +| Mode | Token-Budget (ca.) | Wann nutzen | +|---|---|---| +| `full` | unbounded (Worker erbt den ganzen Orchestrator-Thread) | Trusted Same-Domain-Handoff; selten; Default OFF | +| `compact` | ~3000 Tokens (Bundle-Ownership-Tabelle + INVARIANTS-SHA + Parity-Contract only) | **Default** für Standard-Workers | +| `summary:medium` | ~1500 Tokens (auto-generierte Summary des Orchestrator-Contexts, ~15-line max) | Budget-bewusste Waves; > 12 Workers | +| `summary:low` | ~600 Tokens (One-Paragraph-Summary) | Trivial Workers (z. B. Doc-Touch only) | +| `truncate` | ~200 Tokens (Goal + Bundle-Name + Sentinel only) | Smoke-Test-Workers; nie für Code-Writing | + +Diese Budgets sind Guidance, keine Hard-Caps; der Hard-Cap ist +`worker.max_brief_tokens` (Default 8000, konfigurierbar per §8). + +### §11A.3 Vorrang-Ladder + +Per attractor §5.4 wird Fidelity mit Vorrang edge > node > graph > +default aufgelöst: + +``` +worker.fidelity = + edge_attribute(orchestrator → worker, "fidelity") # falls gesetzt + || node_attribute(worker, "fidelity") # sonst + || graph_attribute(sprint_graph, "default_fidelity") # sonst + || "compact" # built-in Default +``` + +### §11A.4 Interaktion mit Proof-of-Read + +Fidelity kontrolliert, was der **Orchestrator** an den Worker +weitergibt. Sie kontrolliert NICHT, was der **Worker** von Disk +liest. Ein Worker auf `fidelity=truncate` MUSS dennoch die §3.3 von +[`anti-skim-agent-spec.md`](./anti-skim-agent-spec.md) Reading-Depth- +Ladder auf jeder File ausführen, die er anfasst. + +Insbesondere: + +- Ein Worker auf `fidelity=truncate`, dessen Brief nur „Goal + + Bundle-Name + Sentinel" enthält, MUSS dennoch INVARIANTS.md + `thorough` lesen vor jedem Commit (per anti-skim-agent-spec.md §3.3). +- Ein Worker auf `fidelity=full` skipped NICHT Proof-of-Read auf + Files, die im inherited Context summarisiert wurden — die inherited + Summary ist KEIN Substitut für den Read (die gleiche Regel, die + eine Compaction-Summary nicht zum Substitut für die JOURNAL-File macht). + +### §11A.5 Validierungs-Regel + +| Regel | Beschreibung | Severity | +|---|---|---| +| `WAVE-016 fidelity-budget` | Wenn ein Worker-Node `fidelity=truncate` deklariert UND `tier_1_gates` required sind, MUSS der Orchestrator verifizieren, dass das Brief des Workers die §6.2-Required-Attribute immer noch enthält. | ERROR | +| `WAVE-017 fidelity-precedence` | Die §11A.3-Precedence wird beachtet; konfliktende Deklarationen lösen sich in der Reihenfolge edge > node > graph > default auf. | WARNING | + +### §11A.6 Worked-Beispiel + +Eine Wave-12-Sprint mit gemischten Bundle-Sizes: + +```yaml +sprint: + default_fidelity: compact + workers: + - agent_id: A1 # großes Bundle, cross-cutting + fidelity: full # Node-Override + - agent_id: A2 # Standard-Bundle + # nutzt Default 'compact' + - agent_id: A3 # winziges Bundle, fasst nur Docs an + fidelity: summary:low # Node-Override + - agent_id: A4 # nur Smoke-Test + fidelity: truncate + edges: + - from: A1 + to: fan_in + fidelity: full # Edge-Override — A1s Resultat ans Fan-In bei voller Fidelity +``` + +--- + +## §12 Appendix A — Kanonischer Wave-DOT-Graph + +```dot +digraph wave_12_customer_master { + rankdir=LR; + start [shape=Mdiamond, label="start"]; + exit [shape=Msquare, label="exit"]; + + // PRE-SPAWN + pp16 [shape=box, + label="PP-16 preflight-drift-auditor", + owner="meta-agent", + verdicts="SPAWN-CLEAR / SPAWN-CAUTION / SPAWN-BLOCKED", + validation_rules="WAVE-001..WAVE-015"]; + + // DURING-IMPL Fan-out + fan_out [shape=component, label="fan-out N=12", max_parallel=12]; + + // 12 Workers (nur A1..A3 gezeigt for brevity) + a1 [shape=box, agent_id="A1", bundle_name="customer-list", + isolation="worktree", proof_of_read=true, + sentinel_token="WAVE-12-A1-2a91", + status_file=".claude/board/wave-12/A1-status.json"]; + a2 [shape=box, agent_id="A2", bundle_name="customer-detail", + isolation="worktree", proof_of_read=true, + sentinel_token="WAVE-12-A2-6b04", + status_file=".claude/board/wave-12/A2-status.json"]; + a3 [shape=box, agent_id="A3", bundle_name="customer-master", + isolation="worktree", proof_of_read=true, + sentinel_token="WAVE-12-A3-d177", + status_file=".claude/board/wave-12/A3-status.json"]; + // ... A4..A12 ... + + fan_in [shape=tripleoctagon, label="consolidate + re-run tier-1"]; + + pp15 [shape=box, label="PP-15 baton-handoff-auditor", + verdicts="CATCH-CRITICAL / CATCH-LATENT / CLEAN"]; + + pp13 [shape=box, label="PP-13 brutally-honest-tester", + verdicts="LAND / HOLD / REJECT", + goal_gate=true, + retry_target=fan_out]; + + start -> pp16 [label="plan handed off"]; + pp16 -> fan_out [label="outcome==SPAWN-CLEAR"]; + pp16 -> exit [label="outcome==SPAWN-BLOCKED", + condition="route_on_fail"]; + fan_out -> a1; + fan_out -> a2; + fan_out -> a3; + // ... -> a4..a12 + a1 -> fan_in; + a2 -> fan_in; + a3 -> fan_in; + fan_in -> pp15 [label="all status.json present, all proof_of_read verified"]; + pp15 -> pp13 [label="outcome==CLEAN || outcome==CATCH-LATENT"]; + pp15 -> fan_out [label="outcome==CATCH-CRITICAL", condition="route_on_fail"]; + pp13 -> exit [label="outcome==LAND"]; + pp13 -> fan_out [label="outcome==HOLD || outcome==REJECT", + condition="route_on_fail"]; +} +``` + +--- + +## §13 Appendix B — Stuck-Protokoll typisierte Blocker + +Wenn ein Worker nicht weiterkommt, schreibt er EINEN Eintrag in +`META/REQUESTS-FROM-AGENTS.md` und idled. Blocker-Typen: + +| Typ | Bedeutung | Meta-Agent-Aktion | +|---|---|---| +| `AMBIGUITY` | Spec ist mehrdeutig; mehr als eine sinnvolle Interpretation. | Schreibe Antwort in `ANSWERS-TO-AGENTS.md`; propagiere zu INVARIANTS wenn strukturell. | +| `MISSING_INVARIANT` | Iron Rule deckt den Fall nicht ab; Konvention fehlt. | Füge Invariant zu INVARIANTS.md; notifyfe den fragenden Agent; audit andere Agents auf die gleiche Lücke. | +| `SPEC_SOURCE_MISMATCH` | Spec sagt X, Reference-Source tut Y. | Schreibe RFC unter `rfcs/`; hol human Sign-off; dann sage dem Worker weiterzumachen. | +| `BEHAVIOUR_QUESTION` | Möglicher Bug in Reference-Source. | Wenn Meta die Source lesen und definitiv beantworten kann, mach es; sonst page den Human. | +| `EXTERNAL_DEPENDENCY` | Drittsystem zickt; Workaround unklar. | Check `wissen/` / `knowledge/`; wenn keine, RFC + Note hinzufügen. | + +`OUT-OF-SCOPE`-Requests (Worker will außerhalb des Bundles +refaktorieren, neues Feature hinzufügen) werden abgelehnt: Meta +schreibt `REJECTED: ` und schließt. + +--- + +## §14 Two-Protocol-Operating-Modes + +> Hinzugefügt 2026-05-18 — Design-Arbeit und Implementations-Arbeit +> haben unterschiedliche Gates und profitieren von unterschiedlichen +> Topologien. + +### §14.1 Zwei Protokolle, eine Loop-Familie + +| Protokoll | Phase | Erzeugtes Artifact | Goal-Gate-Kriterium | +|---|---|---|---| +| **Protokoll B** | Design | Specs, RFCs, Pläne, INVARIANT-Amendments, Agent-Cards | Doc-Coherence + Scope-Completeness über N Docs gemeinsam | +| **Protokoll A** | Implementation | Code, Parity-Tests, Ledger-Zeilen, PRs | Tier-1-Toolchain grün + Spec-Contract erfüllt | + +Beide Protokolle nutzen das gleiche 4-Savant-Council (PP-13/14/15/16) +und den gleichen Meta-Agent. Sie unterscheiden sich in (1) was ein +Goal-Gate-Pass ist, (2) der Topologie des Savant-Passes (sequenziell +vs. cooperative Council per §15) und (3) dem Artifact, das die +Preflight erzeugt. + +### §14.2 Protokoll B — Design-Loop + +``` +1. Draft → Human oder LLM authored N Documents auf einem Design-Branch +2. Joint-Review → Savants KOOPERIEREN auf den N Docs als coherent Set (§15) +3. Correct → Orchestrator wendet Cross-Doc-Fixes aus dem Joint-Review an +4. Re-Review → goto Step 2 bis CONVERGE (§15.5) oder Human-Override +5. Land → Docs mergen zu Main; Protokoll A darf beginnen +``` + +Goal-Gate-Kriterien (Protokoll B): + +| Check | Owner | Pass-Bedingung | +|---|---|---| +| Doc-Coherence | PP-15 baton-handoff-auditor | Kein Cross-Doc-Schema/Term-Drift (z. B. `status.json` in Spec A matched Consumer in Spec B) | +| Scope-Completeness | PP-16 preflight-drift-auditor | Jede Requirement im Source-Brief ist in mindestens einem Doc adressiert | +| Convergence-Opportunity | PP-14 convergence-architect | Kein latentes shared Konzept dupliziert über Docs ohne shared Section | +| Conformance-Checklist | PP-13 brutally-honest-tester | Jedes Doc hat eine Definition-of-Done-Section mit checkbaren Items | + +PP-13 in Protokoll B läuft NICHT die Language-Toolchain (kein Code +zum Compilen). Es validiert stattdessen, dass die Docs DIE Art Ding +sind, gegen die ein PP-13 später compilen/testen kann. + +### §14.3 Protokoll A — Implementation-Loop + +Der 6-Step-Wave-Loop von §3.1, mit einer Ergänzung: **Preflight +erzeugt ein auskommentiertes, compile-error-only Rust-Skelett** +(§14.4) vor dem Worker-Fan-out. Workers füllen Bodies in das +Skelett statt in leere Files zu schreiben. + +``` +1. Plan → Orchestrator partitioniert Arbeit in N Bundles +2. Preflight → PP-16 erzeugt SKELETON (§14.4) + Verdict +2a. Council → Savants KOOPERIEREN auf SKELETON (§15) — schnell, billig +3. Sprint → N parallele Worker-Agents füllen Bodies in Skelett +4. Council → Savants KOOPERIEREN auf FILLED Code (oder sequenziell per §15.6 bei großen Diffs) +5. Fix P0s → Orchestrator wendet Fixes an + verifiziert Tier-1-Gates +6. Commit+PR → Orchestrator (atomic Consolidation per §3.4) +7. Repeat → Orchestrator plant die nächste Wave +``` + +### §14.4 Das auskommentierte Rust-Skelett (Protokoll-A-Preflight-Artifact) + +PP-16 in Protokoll A erzeugt sowohl (a) sein Verdict (SPAWN-CLEAR / +CAUTION / BLOCKED per §4.6) ALS AUCH (b) ein lauffähig-gestubbtes +Rust-Skelett am Path deklariert in `skeleton_output_path` (ein +neues Node-Attribut auf jedem Worker, siehe §14.6). + +#### §14.4.1 Kanonisches Rust-Skelett-Format + +| Element | Skelett-Form | +|---|---| +| Funktions-Body | `todo!("SOURCE: :-")` | +| Trait-Impl | Deklariere den impl-Block mit jedem Method-Body als `todo!("SOURCE: ...")` | +| Struct | Deklariere alle Felder; `Default::default()`-Impl als `todo!("SOURCE: ...")` wenn Konstruktion nicht-trivial | +| Enum | Deklariere Variants; kein Body nötig | +| Module | `pub mod x;` mit Stub-`mod.rs` enthaltend `// SKELETON: — SOURCE: ` | +| `unsafe`-Block | `unsafe { todo!("UNSAFE-SOURCE: : — // SAFETY: ") }` — SAFETY-Rationale required weil PP-13 es später verlangen wird | +| Async-Funktion | Same wie Funktion; Body `todo!("SOURCE: ...")` | +| Macro | Deklariere mit leerem Body `() => { todo!("SOURCE: ...") }` | + +#### §14.4.2 Token-Wahl: `todo!` über `unimplemented!` + +- `todo!("SOURCE: ...")` — bevorzugt. Signalisiert Intent „das ist zu + tun", panic'ed mit Source-Location at Runtime falls hit, Compiler + akzeptiert es als beliebigen Typ. +- `unimplemented!()` — reserved für „korrekte API-Surface aber nie + implementiert in diesem Crate" (selten; kein Skelett-Placeholder). +- `unreachable!()` — reserved für „statisch unmöglicher Branch"; + kein Skelett-Primitive. + +#### §14.4.3 Skelett-Compile-Invariante + +Das Skelett MUSS mit `cargo check --workspace` grün compilen. Es +DARF NICHT `cargo test` oder `cargo run` bestehen (die `todo!()`- +Panics). Das ist die diagnostische Signatur eines well-formed +Skeletts. + +| Regel | Beschreibung | Severity | +|---|---|---| +| `WAVE-018 skeleton-compiles` | `cargo check --workspace` MUSS grün auf dem von PP-16 emittierten Skelett sein. | ERROR | +| `WAVE-019 skeleton-source-annotated` | Jedes `todo!()` MUSS ein `"SOURCE: :"`- oder `"UNSAFE-SOURCE: ..."`-Argument tragen. | ERROR | +| `WAVE-020 skeleton-no-runtime` | Das Skelett DARF NICHT `cargo test` oder `cargo run` bestehen — ein grüner Test auf einem Skelett bedeutet, dass der Test eine Tautologie ist. | ERROR | + +#### §14.4.4 Per-Language-Equivalents (für nicht-Rust-Repos) + +| Sprache | Skelett-Form | +|---|---| +| Rust | `todo!("SOURCE: ...")` (kanonisch) | +| Python | `raise NotImplementedError("SOURCE: :")` mit Docstring-Stub | +| TypeScript | `throw new Error("TODO — SOURCE: :")` | +| Go | `panic("TODO — SOURCE: :")` | + +Rust ist kanonisch, weil das `todo!()`-Macro der Sprache purpose-built +für genau diesen Use-Case ist. + +### §14.5 Protokoll A vs. Protokoll B auf der Savant-Schicht + +| Savant | Protokoll B (Design) | Protokoll A (Implementation) | +|---|---|---| +| PP-13 | Verifiziert, dass Docs DoD-Sections haben; kein Compile-Gate. | Tier-1-Toolchain + AP1..AP9 auf gefülltem Code (§4.4). | +| PP-14 | Surfacet Convergence-Opportunities über Docs. | Surfacet Convergence-Opportunities über Slices (Helper-Hoist). | +| PP-15 | Cross-Doc-Schema/Term-Drift. | Cross-Bundle-DTO-Drift auf gefülltem Code (BAP1..BAP10, §4.5). | +| PP-16 | Validiert Plan-vs-Source-Brief: jede Requirement landed in einem Doc. | Validiert Plan-vs-Main (PD1..PD10, §4.6) + EMITTIERT SKELETON (§14.4). | + +### §14.6 Mode-Switch ist explizit + +Der Orchestrator deklariert, welches Protokoll im Sprint-Header +aktiv ist: + +```yaml +sprint: + id: SPRINT-17-attractor-fold-in + protocol: B + default_fidelity: full + inputs: + docs: + - .claude/ATT/autoattended-orchestrator-spec.md + - .claude/ATT/anti-skim-agent-spec.md + - .claude/ATT/agent-coordination-mcp-spec.md + goal_gate: savant_council_converge +``` + +```yaml +sprint: + id: SPRINT-18-attractor-implementation + protocol: A + default_fidelity: compact + preflight: + skeleton_output_root: src/attractor/ + skeleton_compiles_check: cargo check --workspace + workers: + - agent_id: A1 + bundle_name: orchestrator-runner + skeleton_output_path: src/attractor/orchestrator/mod.rs + ... +``` + +| Regel | Beschreibung | Severity | +|---|---|---| +| `WAVE-021 protocol-declared` | Jedes Sprint-Header MUSS `protocol: A` oder `protocol: B` deklarieren. | ERROR | +| `WAVE-022 protocol-coherence` | Protokoll-B-Sprints DÜRFEN NICHT `workers[].owned_files` von File-Extensions außer `.md` / `.yaml` / `.dot` deklarieren. Protokoll-A-Sprints MÜSSEN `preflight.skeleton_output_root` deklarieren. | ERROR | + +--- + +## §15 Cooperative-Savant-Council + +> Die 4 Savants **kooperieren** — sie laufen nicht als unabhängige +> Fan-out-Branches, deren Verdicts bag-of-words-aggregiert werden. +> Sie lesen ein shared Scratchpad, filen Findings, cross-referen +> einander, iterieren, und emerge mit einem EINZELNEN gemeinsamen +> Verdict. + +### §15.1 Warum cooperative, nicht independent-parallel + +Independent-Parallel-Review (4 Savants → 4 Verdicts → Super-Verdict- +Aggregation) hat zwei Failure-Modes: + +1. **Lockstep-Drift.** Alle 4 Savants verpassen das gleiche + cross-cutting Issue, weil sie das Artifact jeweils durch die + eigene Achse anschauten ohne den Winkel der anderen zu sehen. +2. **Duplicate-Findings.** Jeder Savant flaggt independent das + gleiche Issue aus einem anderen Winkel; der Orchestrator + verschwendet eine Round mit Deduplikation. + +Cooperation fixt beides: Savants sehen die Findings der anderen +während sie landen und entweder (a) cross-referen („PP-15 hat das +schon geflaggt; mein Winkel ist …") oder (b) suppressen Duplicates +(„PP-13 hat das schon aus stärkerem Winkel covered — withdrawn"). + +### §15.2 Das shared Scratchpad + +``` +.claude/board/savant-council-/ +├── ROUND-0-ARTIFACT.md (Snapshot dessen was unter Review steht) +├── ROUND-1-PP-13.md (PP-13s Round-1-Findings) +├── ROUND-1-PP-14.md (PP-14s Round-1-Findings) +├── ROUND-1-PP-15.md (PP-15s Round-1-Findings) +├── ROUND-1-PP-16.md (PP-16s Round-1-Findings) +├── ROUND-2-PP-13.md (PP-13s Round 2 — sieht alles von Round 1) +├── ... +└── COUNCIL-VERDICT.md (finales gemeinsames Dokument) +``` + +Append-only per §7.1 von `agent-coordination-mcp-spec.md`. Jeder +Savant schreibt seine File am Ende seiner Round; liest ALLE anderen +Files am Beginn seiner nächsten Round. + +### §15.3 Der Cooperation-Loop + +``` +Round R+1 (per Savant): + 1. Lies jede ROUND-R-*.md (die Findings der anderen aus der vorigen Round) + 2. Lies ROUND-R-.md (deine eigenen Findings aus der vorigen Round) + 3. Für jede Finding eines anderen Savants: + a. Cross-refere wenn es deine Achse berührt („noted — meine AP3- + Finding bezieht sich darauf: ") + b. Withdraw deine eigenen Findings, die der andere Savant aus + stärkerem Winkel covered hat + c. Suppresse Duplikate mit `STATUS: superseded-by(PP-X round-R)` + 4. Append deine neuen Findings (Achsen-getagged) an ROUND-(R+1)-.md + 5. Markiere mit `ROUND-COMPLETE`-Sentinel wenn du keine neuen Findings hast +``` + +Eine Round endet wenn ALLE 4 Savants in derselben Round entweder +(a) neue Findings hinzufügten ODER (b) `ROUND-COMPLETE` emittierten +(keine neuen Findings + keine unaddressierten Cross-Refers von Peers). + +### §15.4 Convergence + Termination + +| Bedingung | Outcome | +|---|---| +| Alle 4 Savants emittieren `ROUND-COMPLETE` in derselben Round | **CONVERGE** — proceed zu §15.5 Verdict-Synthese | +| Round-Count überschreitet `max_rounds` (Default 3) | **STALL** — Orchestrator oder Human arbitred | +| Ein Savant emittiert ein unrecoverable BLOCK in irgendeiner Round (z. B. PP-16=SPAWN-BLOCKED ohne klares Remediation) | **BLOCK** — abort das Council; zurück zu Step 1 des Protokolls | + +### §15.5 Das gemeinsame Verdict (`COUNCIL-VERDICT.md`) + +Nach CONVERGE liest der Meta-Agent (oder ein designierter Chairman- +Savant — Default PP-16 in Protokoll A, PP-15 in Protokoll B) ALLE +ROUND-*.md-Files und synthetisiert eine einzelne +`COUNCIL-VERDICT.md`: + +```yaml +council_verdict: + topic: + protocol: A | B + rounds_run: N + super_verdict: CONVERGE | SPLIT | BLOCK + + per_savant_final: + PP-13: + verdict: LAND | HOLD | REJECT + findings_kept: N + findings_withdrawn: M + PP-14: { ... } + PP-15: { ... } + PP-16: { ... } + + consolidated_p0_findings: + - finding_id: F1 + raised_by: PP-13 (round 1) + cross_referred_by: [PP-15 round 1, PP-16 round 2] + summary: + remediation: + + consolidated_p1_findings: [ ... ] + + next_action: proceed | arbitrate | retry_preflight | block +``` + +Der Super-Verdict ist abgeleitet aus den Per-Savant-Finals: + +| Super-Verdict | Trigger | +|---|---| +| **CONVERGE** | Alle 4 Savants pass (PP-13=LAND ∧ PP-14∈{OPPORTUNITY-NOW,WORTH-EXPLORING,DROP} ∧ PP-15=CLEAN ∧ PP-16=SPAWN-CLEAR), UND keine P0-Findings bleiben nach Deduplikation. | +| **SPLIT** | Gemischte Verdicts, die weder all-pass noch block-on-any sind. Orchestrator oder Human arbitred. | +| **BLOCK** | Eines von: PP-13=REJECT ∨ PP-15=CATCH-CRITICAL ∨ PP-16=SPAWN-BLOCKED ∨ verbleibende P0-Findings ≥ 1. | + +### §15.6 Council-DOT-Topologie + +```dot +digraph savant_council { + rankdir=LR; + start [shape=Mdiamond]; + artifact [shape=note, label="docs (B) OR skeleton (A) OR filled-code (A)"]; + + round_R [shape=component, + label="round R: 4 savants read shared scratchpad, + append findings, cross-refer, withdraw duplicates"]; + + pp13 [shape=box]; pp14 [shape=box]; pp15 [shape=box]; pp16 [shape=box]; + + round_check [shape=diamond, + label="all 4 savants ROUND-COMPLETE?"]; + bump_round [shape=parallelogram, label="R := R+1"]; + + chairman [shape=box, label="chairman savant synthesizes COUNCIL-VERDICT.md"]; + verdict [shape=tripleoctagon, label="super-verdict: CONVERGE / SPLIT / BLOCK"]; + exit [shape=Msquare]; + + start -> artifact; + artifact -> round_R; + round_R -> pp13; + round_R -> pp14; + round_R -> pp15; + round_R -> pp16; + pp13 -> round_check; + pp14 -> round_check; + pp15 -> round_check; + pp16 -> round_check; + round_check -> bump_round [label="no: a savant has new findings"]; + bump_round -> round_R; + round_check -> chairman [label="yes: CONVERGE / STALL / BLOCK"]; + chairman -> verdict; + verdict -> exit; +} +``` + +### §15.7 Wann zurück auf sequenziell fallen (kein Council) + +Drei Daumenregeln: + +1. **Filled-Code-Review mit Diff > 500 Zeilen:** sequenziell PP-13 → + PP-15 → PP-16 (per §4-Chain). Jeder Savant sieht einen kleineren + Diff, nachdem der Orchestrator die P0-Fixes des vorigen Savants + angewendet hat. +2. **Token-Budget-constrained Run:** sequenziell. Council bezahlt + für `4 × Rounds × Artifact-Size`-Reads; sequenziell bezahlt für + `1 × Artifact + 3 × Diff-only`-Reads. +3. **Erstes Mal mit neuem Spec-Set:** sequenziell. Lass einen Savant + die offensichtlichen Issues shaken bevor die anderen es lesen. + +Sonst: Council by default. + +### §15.8 Konfiguration + +```yaml +council: + max_rounds: 3 + chairman: + protocol_A: PP-16 + protocol_B: PP-15 + scratchpad_root: .claude/board/savant-council + cooperation_protocol: cross-refer-and-withdraw # siehe §15.3 + duplicate_suppression: superseded-by-stronger-angle +``` + +### §15.9 Validierungs-Regeln + +| Regel | Beschreibung | Severity | +|---|---|---| +| `WAVE-023 council-legality` | Council-Mode ist deklariert nur wenn Artifact eines von {docs, skeleton, small-diff filled-code} ist. | ERROR | +| `WAVE-024 council-rounds-bounded` | `max_rounds` MUSS gesetzt sein; Default 3; Hard-Cap 7. | ERROR | +| `WAVE-025 scratchpad-append-only` | Das `.claude/board/savant-council-/`-Directory MUSS append-only per `agent-coordination-mcp-spec.md` §7.1 sein. | ERROR | +| `WAVE-026 cross-refer-recorded` | Wenn ein Savant die Finding eines Peers withdraws oder supersedes, MUSS die Aktion mit `STATUS: superseded-by(PP-X round-R)` aufgezeichnet sein für Traceability. | ERROR | +| `WAVE-027 chairman-declared` | Der `chairman`-Savant für den Synthese-Pass MUSS in der Sprint-Config deklariert sein; Default per §15.8. | ERROR | +| `WAVE-028 stall-arbitration` | Ein STALL-Outcome (max_rounds erreicht ohne CONVERGE) MUSS gefolgt sein von einem Arbitration-Step (Orchestrator oder Human). | ERROR | +| `WAVE-029 split-arbitration` | Ein SPLIT-Super-Verdict MUSS gefolgt sein von einem Arbitration-Step bevor Fan-out fortgesetzt. | ERROR | + +### §15.10 Beispiel: dieses Kit selbst + +Ein worked Example. Um die §14- / §15-Ergänzungen in die drei +`.claude/ATT/*.md`-Specs zu folden, würde ein Protokoll-B-Council: + +``` +Round 1: + PP-13: "Spec A §11 'Context Fidelity' hat keine DoD-Subsection" + PP-14: "Spec A §15 'cooperative council' dupliziert Spec C §3.1 'three-layer model' + — Opportunity für shared Konzept" + PP-15: "Spec A §14.4 'skeleton' referenziert todo!()-Macro; + Spec B §6 'tool-call loop detection' tut es nicht — kein Widerspruch, nur eine Achse" + PP-16: "Scope-Completeness-Pass — jede Requirement aus dem Source-Brief + (Protokoll A/B + Cooperation + Rust-Skelett) landed in Spec A; + Spec B + Spec C brauchen keine Änderungen" + +Round 2: + PP-13: ROUND-COMPLETE (keine neuen Findings; PP-14s Opportunity ist non-blocking) + PP-14: "Spec A §15 Cooperation sollte Spec C §3.2 'file blackboard' referenzieren + weil das Scratchpad dieses Primitive nutzt — Cross-Ref hinzugefügt" + PP-15: "withdrawn: meine Round-1-Finding ist gecovered durch PP-14s Round-2-Cross-Ref" + PP-16: ROUND-COMPLETE + +Round 3: + Alle 4: ROUND-COMPLETE + +CONVERGE — Chairman PP-15 synthetisiert COUNCIL-VERDICT.md +super_verdict: CONVERGE +consolidated_p0_findings: [] +consolidated_p1_findings: + - F1: "Spec A §11 add 'Definition of Done' subsection (PP-13 round 1)" + - F2: "Spec A §15 cross-reference spec C §3.2 (PP-14 round 2, PP-15 round 2)" +next_action: proceed +``` + +--- + +## §16 Model-Stylesheet + Mid-Task-Switching + +> Hinzugefügt 2026-05-18. Mapped auf `attractor-spec.md` §8 +> `model_stylesheet` (CSS-like Selektoren), ergänzt unsere Mid-Task- +> Opus↔Sonnet-Switching getriggert durch unsere Stuck-Protokoll- +> Blocker und Council-Round-Counts. + +### §16.1 Warum überhaupt ein Stylesheet + +| Phase / Rolle | Cognitive Load | Sinnvoller Default | +|---|---|---| +| Plan-Authoring | hoch (Architektur, cross-cutting) | **opus** + `reasoning=high` | +| Plan-Review (Meta-Agent) | hoch (Judgment, Taste) | **opus** + `reasoning=high` | +| PP-14 convergence-architect | hoch (Creative-Design-Exploration) | **opus** + `reasoning=high` | +| PP-16 preflight-drift-auditor | mittel (Git + Grep gegen Plan) | **sonnet** (escalate bei Drift > 100 Zeilen) | +| PP-15 baton-handoff-auditor | mittel (Interface-Diffing) | **sonnet** | +| PP-13 brutally-honest-tester | mittel (Toolchain-Runner + AP1..AP9) | **sonnet** | +| Worker (Skeleton-Fill) | mittel (mechanisches Füllen typed Surface) | **sonnet** | +| Worker (Greenfield-Code) | hoch (Design + Impl) | **opus** | +| Council-Round (pro Savant) | mittel (Review-Iteration) | **sonnet** | +| Chairman-Synthese | hoch (Cross-Finding-Konsolidierung) | **opus** | +| Inbox-Drain (Meta-Agent) | niedrig (typed-Blocker-Routing) | **sonnet** (escalate bei `BEHAVIOUR_QUESTION`) | + +Statische Per-Rolle-Defaults sind Step 1. Mid-Task-Switching (§16.3) +ist Step 2. + +### §16.2 Stylesheet-Syntax (attractor §8 kompatibel) + +```yaml +model_stylesheet: + # CSS-like Rules. Erste matchende Regel gewinnt (per attractor §8). + rules: + - selector: "node[kind=plan]" + props: { model: opus, reasoning_effort: high } + - selector: "node[kind=meta_review]" + props: { model: opus, reasoning_effort: high } + - selector: "node[kind=savant][role=PP-14]" + props: { model: opus, reasoning_effort: high } + - selector: "node[kind=savant][phase=POST-IMPL]" + props: { model: sonnet } + - selector: "node[kind=savant][phase=PRE-SPAWN]" + props: { model: sonnet } + - selector: "node[kind=council_chairman]" + props: { model: opus } + - selector: "node[kind=worker][mode=skeleton-fill]" + props: { model: sonnet } + - selector: "node[kind=worker][mode=greenfield]" + props: { model: opus } + - selector: "*" + props: { model: sonnet } # finaler Fallback +``` + +Selektoren komponieren mit `[attr=value]`-Pairs (attractor §8.2). Die +Fallback-`*`-Regel ist Pflicht; Abwesenheit ist `WAVE-030` ERROR. + +### §16.3 Mid-Task-Eskalations-Trigger + +Ein Worker (oder Savant) wechselt NICHT sein eigenes Model — er +schreibt ein typisiertes Signal in seine `status.json` und der +**Orchestrator re-spawned** mit dem requested Model. Self-Switching +würde LD-1-Sentinel-Continuity brechen. + +| Trigger-Bedingung | Aktion | Eskalieren von → zu | +|---|---|---| +| `outcome=RETRY` UND `notes contains "escalate-model:opus"` | re-spawn gleicher agent_id mit opus | sonnet → opus | +| Tool-Call-Loop detected im Council, `rounds >= 3` ohne CONVERGE | re-spawn den loopenden Savant mit opus + `reasoning=high` | sonnet → opus | +| Worker filed `MISSING_INVARIANT`-Blocker UND Meta-Agent-Antwort ist strukturell | re-spawn Worker mit opus | sonnet → opus | +| Worker filed `SPEC_SOURCE_MISMATCH` UND Meta hat RFC geschrieben | re-spawn Worker mit opus nach RFC-Merge | sonnet → opus | +| Proof-of-Read deckt > 10 Files | escalate beim nächsten Re-Spawn | sonnet → opus | +| `unsafe`-Block in Skeleton-Fill | escalate beim nächsten Re-Spawn | sonnet → opus | +| PP-16-Drift-Surface > 100 Zeilen | escalate den nächsten Preflight-Pass | sonnet → opus | +| PP-13-Anti-Pattern-Density > 3 pro 100 Zeilen Diff | escalate PP-13 für Re-Review-Pass | sonnet → opus | + +### §16.4 Mid-Task-De-Eskalations-Trigger + +Die Gegenrichtung — Orchestrator kann ein Re-Spawn von opus zu +sonnet runterdrücken, wenn die Arbeit einfacher war als das +Stylesheet-Default prediktet hat: + +| Trigger-Bedingung | Aktion | De-Eskalieren von → zu | +|---|---|---| +| Plan stellte sich als 2-Bundle-Wave heraus (nicht 12) | Default der nächsten Round | opus → sonnet | +| Council CONVERGED in Round 1 mit Zero P0 + ≤2 P1 | Chairman-Synthese | opus → sonnet | +| `outcome=SUCCESS` + Tier-1 grün + Diff < 50 Zeilen | Next-Wave-Default für dieses Bundle | opus → sonnet | +| Meta-Agents Inbox-Drain hat nur `AMBIGUITY`-Blocker in letzten 10 Einträgen beantwortet | Next Inbox-Drain | opus → sonnet | + +### §16.5 Wire-Format fürs Switching + +Das Signal fließt auf dem universellen Wire-Format +(`agent-coordination-mcp-spec.md §1.3`): + +```markdown +## 2026-05-18T14:22 — PROPOSAL[P1]: escalate-model A4 → opus (sonnet, claude/wave-12) + +**Author:** A4 +**Kind:** PROPOSAL +**Severity:** P1 +**Refs:** status.json#A4 wave-12 +**Reason:** tool-call-loop:length=2:rounds=3 auf customer.master sea-orm UPSERT + +--- + +Requested: model=opus, reasoning_effort=high. +Suggested rationale: das ist ein Stuck-Protokoll-AMBIGUITY-class-Issue +(sea-orm vs. Python idempotentes UPSERT-Semantics) — Judgment-heavy. +``` + +Orchestrator routed nach `Kind=PROPOSAL` + `Severity=P1` + Body +enthält `escalate-model:`. Re-Spawn passiert im nächsten Wave-Step. + +### §16.6 Cost-Aware-Ceiling + +Das Stylesheet MUSS ein Per-Wave-**Escalation-Budget** deklarieren: + +```yaml +model_stylesheet: + budget: + max_opus_workers_per_wave: 3 # Default 3 + max_opus_savant_rounds_per_council: 2 # Default 2 + warn_if_exceeds: 0.8 +``` + +Wenn die pending Eskalationen einer Wave das Budget überschreiten +würden, MUSS der Orchestrator entweder (a) Eskalationen über Waves +serialisieren ODER (b) den Human via `wait.human` (attractor §6) +fragen bevor escaliert wird. + +### §16.7 Validierungs-Regeln + +| Regel | Beschreibung | Severity | +|---|---|---| +| `WAVE-030 stylesheet-fallback` | `model_stylesheet.rules` MUSS mit einem `*`-Fallback enden. | ERROR | +| `WAVE-031 no-self-switching` | Workers / Savants DÜRFEN NICHT ihr eigenes Model mid-call wechseln. Nutze das `PROPOSAL`-Wire-Signal (§16.5). | ERROR | +| `WAVE-032 sentinel-on-respawn` | Re-Spawn unter Eskalation MUSS einen NEUEN Sentinel-Token ausgeben (die Identität des vorigen Workers ist geschlossen). | ERROR | +| `WAVE-033 escalation-budget` | Das Eskalations-Total der Wave DARF `model_stylesheet.budget` NICHT überschreiten ohne expliziten Human-Override. | WARNING | +| `WAVE-034 escalation-trace` | Jedes Eskalations-Re-Spawn MUSS einen `PROPOSAL`-Eintrag auf dem Wire-Format (§16.5) hinterlassen, damit das Audit-Log zeigt wann + warum. | ERROR | +| `WAVE-035 de-escalation-gate` | De-Eskalation MUSS nur durch §16.4-Bedingungen getriggert sein; arbiträre Downgrades sind verboten (Cost-Saving-Optimismus). | ERROR | + +### §16.8 Worked-Beispiel: eine Wave, die escaliert dann de-escaliert + +``` +T+0 Plan committed opus (per §16.1 Default für Plan) +T+1 PP-16 Preflight läuft sonnet (Drift < 100 Zeilen, Default) +T+1 PP-16 emittiert Skelett sonnet (immer noch PP-16) +T+2 Council-Round 1 sonnet x4 (alle Savants Default) +T+2 Council CONVERGE opus (Chairman-Synthese-Default) +T+3 Workers spawnen (12 × A1..A12) sonnet (Skeleton-Fill-Default) +T+4 A4 hits sea-orm AMBIGUITY → PROPOSAL: escalate A4 +T+4 Meta-Agent schreibt RFC opus (Meta-Default) +T+5 A4 Re-Spawn opus (escalated, neuer Sentinel) +T+6 A4 returned SUCCESS — (behielt opus durch diese Wave) +T+7 Fan-in + Tier-1 grün — +T+8 nächste Wave plant A4 wieder opus (sticky Eskalation für eine Wave) +T+9 A4 returned SUCCESS wieder — +T+10 Wave 3 plant A4 sonnet (DE-ESCALATE per §16.4: 2 Successes + Diff < 50) +``` + +--- + +*Ende der Datei autoattended-orchestrator-spec.md.* diff --git a/.claude/ATT/README.md b/.claude/ATT/README.md new file mode 100644 index 000000000..36ac86c5e --- /dev/null +++ b/.claude/ATT/README.md @@ -0,0 +1,87 @@ +# `.claude/ATT/` — Attractor-style NLSpecs of our kit + +> **Status:** DRAFT · **Version:** 0.1.0 · **Last updated:** 2026-05-17 +> +> **What this is.** Our `.claude/EN/` kit's ideas, restated in the +> [strongdm/attractor](https://github.com/strongdm/attractor) NLSpec +> format so a coding agent can implement them directly. +> [NLSpec](https://github.com/strongdm/attractor#terminology) = +> "human-readable spec intended to be directly usable by coding agents +> to implement/validate behavior." +> +> **What this is NOT.** A replacement for `.claude/EN/`. The two are +> complementary: `.claude/EN/` is the operator's cheat-sheet +> (prose, in-session use); `.claude/ATT/` is the engineering spec +> (NLSpec, build-time use). + +## The three specs + +| File | Mirrors attractor's | Adds our innovation | +|---|---|---| +| [`autoattended-orchestrator-spec.md`](./autoattended-orchestrator-spec.md) | [`attractor-spec.md`](https://github.com/strongdm/attractor/blob/main/attractor-spec.md) (DOT-graph pipeline runner) | Wave-based 12-worker fan-out; 4-savant verdict gates (PP-13/14/15/16); 6 worker iron rules; sprint-token budget (~300k/wave); multi-file board pattern with single-mutable-file invariant | +| [`anti-skim-agent-spec.md`](./anti-skim-agent-spec.md) | [`coding-agent-loop-spec.md`](https://github.com/strongdm/attractor/blob/main/coding-agent-loop-spec.md) (the per-LLM-call agent library) | Reading-Depth-Ladder (grep→read→thorough→fan-out); Lie-Detector LD-1..5 (sentinel token / proof-of-read SHA / 3-section challenge / negative-knowledge test / line-range quote); typed stuck-protocol blockers (AMBIGUITY / MISSING_INVARIANT / SPEC_SOURCE_MISMATCH / BEHAVIOUR_QUESTION / EXTERNAL_DEPENDENCY) | +| [`agent-coordination-mcp-spec.md`](./agent-coordination-mcp-spec.md) | [`unified-llm-spec.md`](https://github.com/strongdm/attractor/blob/main/unified-llm-spec.md) (provider-agnostic LLM SDK) | Three coordination layers (role-teleport / file-blackboard / branch-pub-sub) the way a native A2A MCP server should expose them; structured handover schema; decision matrix for when each layer fits | + +## What we adopted from attractor (the five wins) + +These are concrete things attractor's specs nail down that our prose +docs in `.claude/EN/` didn't have, now incorporated: + +| # | Attractor concept | Lands in our NLSpec | Adoption | +|---|---|---|---| +| 1 | Typed `status.json` schema + 5-value `StageStatus` enum (attractor Appendix C: `{outcome, preferred_label, suggested_next_ids, context_updates, notes}`) | [`autoattended-orchestrator-spec.md` §9](./autoattended-orchestrator-spec.md#9-status-file-schema) | Adopted **with `auto_status=false` mandatory** (see "Where it conflicts" below). | +| 2 | DOT graph DSL for the workflow + lint rules (attractor §2 grammar + §7 validation: `reachability`, `start_no_incoming`, `goal_gate_has_retry`, `condition_syntax`) | [`autoattended-orchestrator-spec.md` §6](./autoattended-orchestrator-spec.md#6-sprint-plan-format) (DOT + YAML mirror) + [§7](./autoattended-orchestrator-spec.md#7-validation-rules) (WAVE-001..WAVE-017 with ERROR/WARNING severity) | Adopted with three wave-specific additions: `unique-write`, `declared-shared`, `auto-status-false`. | +| 3 | Context Fidelity ladder (attractor §5.4: `full` / `truncate` / `compact` / `summary:low/medium/high` with token budgets + edge > node > graph > default precedence) | [`autoattended-orchestrator-spec.md` §11A](./autoattended-orchestrator-spec.md#11a-context-fidelity) | Adopted with one tightening: `fidelity=truncate` does NOT exempt a worker from the §3.3 Reading-Depth-Ladder of `anti-skim-agent-spec.md`. | +| 4 | In-loop tool-call loop detection (attractor coding-agent §2.10: last 10 calls scanned for length-1/2/3 repeating patterns → inject steering warning) | [`anti-skim-agent-spec.md` §6](./anti-skim-agent-spec.md#6-tool-call-loop-detection) + AP9 in [§9](./anti-skim-agent-spec.md#9-anti-pattern-catalog-ap1ap9) | Adopted verbatim; elevated to a system-level invariant. PP-13's post-hoc AP9 catches what the in-loop detector misses. | +| 5 | Definition-of-Done checklists + Cross-Provider Parity Matrix per spec (attractor §10-style conformance tables) | Each NLSpec ends with `§ Definition of Done` + `§ Cross-{Language,Provider} Parity Matrix` | Adopted as the structural template. The 26-repo rollout is now machine-checkable. | + +## Why this format + +Three properties we get from attractor's NLSpec format that our prose +docs in `.claude/EN/` don't have: + +1. **Definition of Done checklists** at the end of each spec — gives + us a conformance test for "is this implementation complete?" +2. **Cross-Provider Parity Matrix** tables — gives us a per-language / + per-runtime mapping so the same NLSpec can land in Rust, Python, + TypeScript, Go without three-way drift. +3. **Validation rules with ERROR/WARNING/INFO severity** — turns + linting into a deterministic process, not a judgment call. + +## Where it conflicts with attractor's posture (and why we keep our position) + +| Attractor's default | Our position | Why | +|---|---|---| +| `auto_status=true` (§4.5 + Appendix C: "if the handler writes no status, auto-generate SUCCESS") | `auto_status=false` is mandatory | This is exactly the silent-skim failure mode our Lie-Detector LD-1..5 exists to prevent. Missing status = FAIL, not SUCCESS. | +| Single-threaded graph traversal (§3.8: "Only one node executes at a time") | Wave fan-out is the baseline, not a special-case `parallel` node | Our token budget is per-wave (~300k for 12 workers), not per-node. Modeling waves as one giant `parallel` node is syntactically awkward. | +| Engine-level retries with exponential backoff (§3.5-3.6) | Stuck-agents file typed blockers in REQUESTS-FROM-AGENTS.md; meta-agent decides | Retries should be contextual and inspected, not silent and uniform. | +| `wait.human` default; LLM gates are test fixtures (§6.4: `AutoApproveInterviewer` "Used for automated testing") | LLM meta-agent is the production gate | Our meta-agent's plan review + P0/P1 PR review + inbox drain is a production role, not a test fixture. | +| Subagent depth = 1 default (coding-agent §7.3) | Wave fan-out routinely runs 12 workers from one orchestrator | We override depth to ≥2 — workers should be able to spawn sub-investigations. | + +## Conformance + +A repo that imports these NLSpecs is conformant if it satisfies the +"Definition of Done" checklist at the end of each spec. The lance-graph +implementation (see [`AdaWorldAPI/lance-graph` `.claude/agents/`](https://github.com/AdaWorldAPI/lance-graph/tree/main/.claude/agents)) +is the most-mature reference; the WoA + woa-rs implementations are +the wave-based reference. + +## Provenance + +- Source kit: `.claude/EN/` in this repo (see [`.claude/EN/README.md`](../EN/README.md)) +- Format inspiration: [strongdm/attractor](https://github.com/strongdm/attractor) (MIT-style NLSpecs) +- Distillation handover: [`META/HANDOVER-AGENTKIT-CONSOLIDATION-2026-05-17.md`](https://github.com/AdaWorldAPI/WoA/blob/main/META%2FHANDOVER-AGENTKIT-CONSOLIDATION-2026-05-17.md) (in `AdaWorldAPI/WoA`) +- Sister handover (Rust hardening pass): [`META/HANDOVER-WOA-RS-AGENT-HARDENING-2026-05-17.md`](https://github.com/AdaWorldAPI/WoA/blob/main/META%2FHANDOVER-WOA-RS-AGENT-HARDENING-2026-05-17.md) + +## Build + +To turn these NLSpecs into a runnable implementation, supply this +prompt to a modern coding agent (Claude Code, Codex, OpenCode, Amp, +Cursor, ...): + +``` +codeagent> Implement the Autoattended Orchestrator + Anti-Skim Agent + + Agent Coordination MCP as described by + https://github.com/AdaWorldAPI//tree/main/.claude/ATT + together with strongdm/attractor as the substrate. +``` diff --git a/.claude/ATT/agent-coordination-mcp-spec.md b/.claude/ATT/agent-coordination-mcp-spec.md new file mode 100644 index 000000000..0332e4988 --- /dev/null +++ b/.claude/ATT/agent-coordination-mcp-spec.md @@ -0,0 +1,743 @@ +# Agent Coordination MCP Specification + +> **Status:** DRAFT · **Version:** 0.1.0 · **Last updated:** 2026-05-17 +> **Format:** NLSpec (per [strongdm/attractor](https://github.com/strongdm/attractor)) +> **Substrate:** Designed as a sibling to `unified-llm-spec.md` — +> a *coordination* SDK the way attractor's spec is an *LLM* SDK. + +--- + +## §1 Overview + +### §1.1 Purpose + +Claude Code spawns each `Agent()` as an isolated subprocess. Each +subprocess gets a fresh context window, cannot call other agents' +tools, cannot read other agents' in-flight state, and returns a +single blob to its parent. This breaks three patterns that worked +in earlier Claude / Gemini setups: + +1. **Role teleportation** — switching persona in-context with zero loss. +2. **Mid-flight coordination** — agent A tells agent B what it found. +3. **Cross-session handoff** — session A's work feeds session B in real-time. + +This spec defines the **Agent Coordination MCP**: the three-layer +coordination model needed to restore these patterns, and the +file / git / MCP primitives that implement it. + +### §1.2 Two operating modes + +| Mode | Substrate | When to use | +|---|---|---| +| **Native** | A future MCP server exposing `post_entry` / `read_entries` / `subscribe` endpoints (§5). | When available — preferred for low-latency. | +| **Workaround** | `tee -a` markdown files in git + GitHub PR webhooks via `mcp__github__subscribe_pr_activity`. | Today, on every Claude Code session. Defined here as the canonical fallback. | + +Both modes implement the same three-layer model (§3) with the same +schemas (§6). The native server is a thin serde layer over the +workaround's wire format. + +### §1.3 The universal wire format: `tee -a [bug/proposal]` + +The same markdown blob serves **three purposes simultaneously**: + +| Purpose | Reader | Mutability | +|---|---|---| +| **MCP orchestration message** | the orchestrator (and any subscribed session via `subscribe_pr_activity`) | append-only | +| **A2A wire format** | sibling agents (worker → worker, worker → meta, savant → savant) | append-only | +| **Log format (audit + replay)** | any future session reading git history | immutable once committed | + +One write, three uses. This is by design: it means the same code +that posts an entry to the file-blackboard (Layer 1) ALSO emits the +log line ALSO becomes a cross-session-readable orchestration message +the moment it lands on a coordination PR's branch. + +The blob's shape is **always a typed envelope + a body**: + +``` +## YYYY-MM-DDTHH:MM — KIND[severity]: one-line headline (author, branch) + +**Author:** +**Kind:** BUG | PROPOSAL | HANDOVER | FINDING | DECISION | RFC | STATUS +**Severity:** P0 | P1 | INFO (optional; defaults to INFO) +**Refs:** | | +**Proof-of-read:** +- file= sha256=<...> lines= depth= +- file= sha256=<...> lines= depth= + +--- + + +``` + +The `tee -a` envelope is the wire; the body is the payload. Routers +(orchestrator, meta-agent, MCP server) dispatch by `Kind` and +`Severity`; readers grep by `Author` + `Refs`; auditors replay by +the immutable git-log order. + +### §1.4 Tables over prose (NLSpec discipline) + +Implementations SHOULD prefer tabular content over prose for every +catalog (anti-patterns, validation rules, verdict vocabularies, +configuration defaults, parity matrices). Rationale: + +| Property | Table | Prose | +|---|---|---| +| Machine-parseable | yes | no | +| Forces consistency (all rows have the same columns) | yes | no | +| Compressible (each row is a fact) | yes | no | +| Diffs cleanly in PRs | yes | partial | +| Resists hedging language | yes (cell width caps qualifiers) | no | +| Suitable for English narrative | no | yes | + +Use prose for: section overviews, rationale paragraphs, conflict +explanations. Use tables for: everything else. + +### §1.5 What this spec is NOT + +- Not a workflow engine. Wave / sprint structure is in + [`autoattended-orchestrator-spec.md`](./autoattended-orchestrator-spec.md). +- Not a per-agent loop. Worker behavior is in + [`anti-skim-agent-spec.md`](./anti-skim-agent-spec.md). +- Not provider-coupled. Both modes are LLM-provider-agnostic. + +--- + +## §2 Terminology + +| Term | Definition | +|---|---| +| **Layer-0 Teleportation** | The main thread loads an agent card and "wears its hat" in-context. Zero transport. | +| **Layer-1 File Blackboard** | A per-session append-only markdown file (`AGENT_LOG.md`) that workers read on entry and append to on exit. | +| **Layer-2 Branch Pub/Sub** | A draft PR's push activity feed used as a real-time cross-session message bus. | +| **Handover** | A structured markdown file (`.claude/handovers/YYYY-MM-DD-HHMM-*.md`) written at session end for the next session to read at startup. | +| **Blackboard entry** | One append to `AGENT_LOG.md`; schema in §6.1. | +| **Cross-session broadcast** | A committed-and-protected file separate from `AGENT_LOG.md`; the durable mirror of important entries. | +| **Coordination PR** | A draft PR (never merged) whose push activity is the Layer-2 transport. | + +--- + +## §3 The Three Coordination Layers + +### §3.1 Layer-0: Teleportation + +**When:** the task needs FULL conversation context (not a summary) +and the role switch is temporary. + +**How:** on the main thread (NOT via `Agent()`): + +``` +1. Read .claude/EN/agents/.md +2. Load its Tier-1 knowledge docs (per the card's §Inputs) +3. Do the work with full session context intact +4. When done, optionally switch: read another role card +5. Review the work from the other role's perspective +6. Back to the original role — nothing lost +``` + +**Cost:** zero transport, single-threaded, context budget fills as +role cards are read. No isolation: a mistake made "as role-X" is +visible to a subsequent "as role-Y" review (a feature, not a bug). + +**Not for:** mechanical grind-work (use Layer-1 + `Agent()`) or +truly independent parallel work (use `Agent()` directly). + +### §3.2 Layer-1: File Blackboard + +**Replaces:** Mid-flight coordination (partially). +**Path:** `.claude/board/AGENT_LOG.md` (or `META/AGENT_LOG.md` per +repo convention). +**Permission:** pre-allowed in `.claude/settings.json` as +`Bash(tee -a *)` and `Bash(tee -a **)`. + +**Setup (native mode):** + +A future MCP server exposes the file as a structured stream +(`post_entry`, `read_entries`, `subscribe`). Until that exists, the +fallback is the markdown file directly. + +**Agent prompt template (workaround mode):** + +``` +Before starting work, read .claude/board/AGENT_LOG.md to see what +other agents already shipped or found. + +After committing, append your entry: + +tee -a .claude/board/AGENT_LOG.md > /dev/null <<'EOF' + +## YYYY-MM-DDTHH:MM — description (model, branch) + +**Agent-id:** +**Bundle:** +**Sentinel:** +**Commit:** `abc1234` +**Tests:** N pass (M new) +**Outcome:** One-line summary. +**Proof-of-read:** +- file= sha256=<...> lines= depth= +EOF +``` + +**Limitations:** + +- Not real-time: agent B only sees what agent A *committed*, not + what A is currently working on. +- Git staging: if agent A and B append without committing, only the + last `git add` wins. Mitigation: commit immediately after append. +- Ordering: entries appear at the bottom (per `tee -a`); convention + is newest-first. The main thread reorders during board hygiene. + +### §3.3 Layer-2: Branch Pub/Sub + +**Replaces:** Cross-session handoff. +**How:** open a coordination PR. Both sessions subscribe. Push +events arrive as `` tags via +`mcp__github__subscribe_pr_activity`. + +**Setup:** + +```bash +# Session A (creates the bus): +git checkout -b claude/blackboard +echo "# Coordination Blackboard" > .claude/board/AGENT_LOG.md +git add .claude/board/AGENT_LOG.md +git commit -m "init coordination blackboard" +git push -u origin claude/blackboard + +mcp__github__create_pull_request( + owner="", repo="", + title="A2A coordination blackboard", + head="claude/blackboard", base="main", + body="Cross-session pub/sub bus. Do not merge.", + draft=true +) + +mcp__github__subscribe_pr_activity(owner="", repo="", pullNumber=NNN) + +# Session B (joins): +mcp__github__subscribe_pr_activity(owner="", repo="", pullNumber=NNN) +git fetch origin claude/blackboard +git checkout claude/blackboard +# Read AGENT_LOG.md +``` + +**Coordination loop:** + +``` +Session A: Session B: + [does work] + tee -a AGENT_LOG.md > /dev/null < + git pull origin claude/blackboard + cat AGENT_LOG.md + [builds on A's findings] + tee -a AGENT_LOG.md ... + git add && commit && push + ← + git pull + # reads B's entry, continues +``` + +**Limitations:** + +- GitHub webhook latency: seconds to low minutes. +- Rate limits: GitHub API 5000/hr authenticated. +- Requires network: doesn't work offline. +- PR MUST stay open: closing it kills the subscription. + +### §3.4 Layer-3 (handover): Structured handover files + +**Replaces:** Session-to-session context transfer. +**Path:** `.claude/handovers/YYYY-MM-DD-HHMM--to-.md`. + +The `SessionStart` hook (`.claude/hooks/session-start.sh`) cats the +latest handover file into the next session's context. + +Schema is in §6.3. + +--- + +## §4 Decision Matrix + +| Need | Workaround | Native MCP equivalent | Cost | +|---|---|---|---| +| Agent A's findings feed agent B (same session) | Layer-1 File Blackboard | `post_entry` + `read_entries` | Low: `tee -a` + `git add` | +| Session A's work feeds session B (real-time) | Layer-2 Branch Pub/Sub | `subscribe` on entries | Medium: PR + subscribe | +| Full-context role switch (no loss) | Layer-0 Teleportation | n/a (in-process) | Zero: just read the card | +| Session-to-session knowledge transfer | Handover files | `post_handover` + `read_latest_handover` | Low: write once, read at startup | +| Parallel independent grind-work | Standard `Agent()` spawns | n/a | Low: fire and forget | +| Multi-source synthesis needing judgment | Teleportation on Opus main thread | n/a | Zero | + +--- + +## §5 Native MCP Server Contract + +A future MCP server SHOULD expose the following endpoints. They are +specified here so the workaround mode's wire format is forward-compatible +with the native mode. + +### §5.1 `post_entry` + +```yaml +endpoint: post_entry +params: + board: string # e.g. ".claude/board/AGENT_LOG.md" + entry: + timestamp: string (ISO 8601) + agent_id: string + bundle: string | null + sentinel: string | null + commit: string | null # short SHA + outcome: enum (SUCCESS | PARTIAL_SUCCESS | RETRY | FAIL | SKIPPED) + summary: string + proof_of_read: list of ProofOfRead # see §6.2 +returns: + entry_id: string + position: integer +errors: + - INVALID_OUTCOME + - SENTINEL_MISMATCH + - PROOF_OF_READ_MISSING_REQUIRED +``` + +### §5.2 `read_entries` + +```yaml +endpoint: read_entries +params: + board: string + since: string (entry_id) | null + limit: integer (default 100, max 1000) + filter: + agent_id: string | null + outcome: enum | null + bundle: string | null +returns: + entries: list of BlackboardEntry + next_cursor: string | null +``` + +### §5.3 `subscribe` + +```yaml +endpoint: subscribe +params: + board: string + cursor: string | null # start position +streams: + type: server_sent_events + event_kinds: + - entry_appended + - entry_redacted + - board_archived +returns_initial: + cursor: string +errors: + - BOARD_NOT_FOUND + - SUBSCRIPTION_LIMIT_EXCEEDED +``` + +### §5.4 `post_handover` / `read_latest_handover` + +```yaml +endpoint: post_handover +params: + from_session: string + to_session: string | null # null = "next session, whoever" + handover: Handover # see §6.3 +returns: + handover_id: string + +endpoint: read_latest_handover +params: + to_session: string # current session id +returns: + handover: Handover | null +``` + +### §5.5 Authentication + +The native server SHOULD use the same auth substrate as the GitHub +MCP server (per-session OAuth or PAT). Workaround mode uses git +push permissions on the coordination PR's branch. + +--- + +## §6 Schemas + +### §6.1 BlackboardEntry + +```json +{ + "entry_id": "01HXYZ-WAVE12-A4-SUCCESS", + "timestamp": "2026-05-17T17:42:00Z", + "agent_id": "A4", + "bundle": "customer-master-data", + "sentinel": "WAVE-12-A4-7f3c", + "commit": "a1b2c3d4", + "outcome": "SUCCESS", + "summary": "customer-master ported; 7 parity tests green; no Iron Rule violations.", + "proof_of_read": [ + { "file": "META/INVARIANTS.md", "sha256": "...", "lines": 412, "depth": "thorough" } + ] +} +``` + +### §6.2 ProofOfRead + +```json +{ + "file": "path/relative/to/repo-root", + "sha256": "64-hex", + "lines": 412, + "depth": "thorough" +} +``` + +`depth` values: `grep` | `sed-partial` | `skim` | `read` | `thorough` +| `troubleshooting` | `fan-out` | `truncated:head-N` | `truncated:tail-N`. + +### §6.3 Handover + +```yaml +handover: + id: 2026-05-17-2200-wave12-to-wave13 + from_session: 2026-05-17-evening + to_session: null # any next session + topic: customer-master-port + + what_i_did: + - bullet: ported 12 bundles (A1..A12) for customer-master + commits: [a1b2c3, d4e5f6, ...] + + finding: + - bullet: BBB-Barrier compile-error happens at A5 when sea-orm 0.12 is in path + severity: P0 + source: META/INVARIANTS.md §BBB + + conjecture: + - bullet: switching to sea-orm 0.13 might break the migration path; needs probe + severity: P1 + + blockers: + - description: A5 cannot be merged until the sea-orm RFC is accepted + filed_in: META/REQUESTS-FROM-AGENTS.md#A5 + + open_questions: + - "Should A11 be a separate PR or rolled into the consolidation?" + + proof_of_read: + - file: META/INVARIANTS.md + sha256: "..." + lines: 412 + depth: thorough +``` + +### §6.4 RequestEntry (`META/REQUESTS-FROM-AGENTS.md`) + +```yaml +request: + agent_id: A5 + file: src/customer/master/sea_orm.rs + timestamp: 2026-05-17T18:14:32Z + + question: | + The reference Python uses an idempotent UPSERT but the sea-orm + builder I have does INSERT-OR-FAIL. Spec is ambiguous. + + tried: + - sea-orm `on_conflict().do_nothing()` — fails with `Error: ...` + - manual transaction wrap — works but doubles latency + + blocker: AMBIGUITY + + proof_of_read: + - file: vendor/ogit/NTO/WorkOrder/entities/customer.ttl + sha256: "..." + lines: 137 + depth: full + - file: ../WoA/woa/blueprints/customer.py + sha256: "..." + lines: 891 + depth: full +``` + +### §6.5 AnswerEntry (`META/ANSWERS-TO-AGENTS.md`) + +```yaml +answer: + agent_id: A5 + in_response_to: 2026-05-17T18:14:32Z + + decision: | + Use sea-orm transaction wrap. The latency cost is acceptable. + + propagation: + invariants_section: META/INVARIANTS.md §UPSERT-PATTERN added + rfcs: null + + signed_off_by: meta-agent (auto) + timestamp: 2026-05-17T18:42:00Z +``` + +--- + +## §7 Append-only Governance + +### §7.1 Mutability invariant + +Across all coordination files: + +| File | Mutability | +|---|---| +| `Stand.md` / `STATUS_BOARD.md` | Mutable (the only one). | +| `AGENT_LOG.md` | Append-only. | +| `REQUESTS-FROM-AGENTS.md` | Append-only. | +| `ANSWERS-TO-AGENTS.md` | Append-only. | +| `INVARIANTS.md` | Append-only by section; sections may be marked SUPERSEDED but never deleted. | +| Handover files | Immutable after write. | +| Cross-session broadcast files (`PR_ARC_INVENTORY.md`, `LATEST_STATE.md`, `EPIPHANIES.md`, `IDEAS.md`, `INTEGRATION_PLANS.md`, `ISSUES.md`, `TECH_DEBT.md`, `STATUS_BOARD.md`) | Append-only at the entry level; specific fields are mutable state. | + +### §7.2 Enforcement + +Implementations SHOULD enforce append-only governance at the +permissions layer. The lance-graph reference (see +[`AdaWorldAPI/lance-graph` `.claude/settings.json`](https://github.com/AdaWorldAPI/lance-graph/blob/main/.claude/settings.json)) +denies `Edit` and `Write` on the 8 bookkeeping files and allows +only `Bash(tee -a *)`. This is the recommended pattern. + +--- + +## §8 Relation to Runtime A2A (Layer 1, in-process) + +When a project also runs an in-process Blackboard in its own runtime +(e.g. `lance_graph_contract::a2a_blackboard::Blackboard`), the +session-level workarounds are structurally isomorphic to it: + +| Runtime (in-process) | Session (this spec) | +|---|---| +| `Blackboard.entries` | `AGENT_LOG.md` entries | +| `BlackboardEntry.expert_id` | Agent description + model | +| `BlackboardEntry.capability` | Bundle / D-ids | +| `BlackboardEntry.result` | Commit hash + outcome | +| `BlackboardEntry.confidence` | Tier-1 gate pass count | +| `Blackboard.round` | Git commit sequence | +| Experts read prior rounds | Agents read prior log entries | + +The isomorphism is intentional: the same coordination pattern works +on both layers because the problem is the same — independent experts +composing results on a shared substrate. + +--- + +## §9 Definition of Done + +An implementation is conformant if it satisfies ALL of: + +- [ ] Three layers (Teleport / Blackboard / Branch Pub/Sub) are + implementable with the existing primitives (file + git + MCP + `subscribe_pr_activity`). +- [ ] Native MCP endpoints §5.1–§5.4 exist OR the workaround mode + is documented as the explicit fallback. +- [ ] `BlackboardEntry`, `ProofOfRead`, `Handover`, `RequestEntry`, + `AnswerEntry` schemas are implemented and validated. +- [ ] Append-only governance (§7) is enforced at the + `.claude/settings.json` layer for the 8 bookkeeping files. +- [ ] The single-mutable-file invariant is enforced: `Stand.md` / + `STATUS_BOARD.md` is the ONLY file workers may overwrite. +- [ ] Decision matrix (§4) is followed: workers use the right + transport for the right kind of message. +- [ ] Coordination PRs are draft, named `claude/`, and + explicitly marked `Do not merge` in the body. +- [ ] Handover files use the §6.3 schema with required sections: + what-I-did / FINDING / CONJECTURE / blockers / open-questions + / proof-of-read. + +--- + +## §10 Cross-Provider Parity Matrix + +| Capability | Claude Code | OpenAI Codex / codex-rs | Gemini CLI | Notes | +|---|---|---|---|---| +| Layer-0 Teleportation | Read agent card on main thread | Same | Same | Provider-agnostic; depends only on file read. | +| Layer-1 File Blackboard | `Bash(tee -a)` + `git add` | Same | Same | POSIX-only; provider-agnostic. | +| Layer-2 Branch Pub/Sub | `mcp__github__subscribe_pr_activity` | `gh pr` polling | `gh pr` polling | Claude Code has native MCP; others poll. | +| Native MCP server (§5) | TBD (this spec) | TBD | TBD | All three providers can speak MCP. | +| Append-only governance | `.claude/settings.json` deny list | provider-specific permission file | provider-specific | Pattern transfers; allowed-list syntax differs. | +| Handover files | `.claude/hooks/session-start.sh` cats latest | Equivalent shell hook | Equivalent shell hook | Hook script is bash; provider-agnostic. | + +--- + +## §11 Appendix A — Sample `AGENT_LOG.md` entry (verbatim) + +```markdown +## 2026-05-17T17:42 — customer-master ported; 7 parity tests green (sonnet, claude/wave-12-customer-master) + +**Agent-id:** A4 +**Bundle:** customer-master-data +**Sentinel:** WAVE-12-A4-7f3c +**Commit:** `a1b2c3d4` +**Tests:** 7 pass (3 new) +**Outcome:** SUCCESS — all Tier-1 gates green; no Iron Rule violations. +**Proof-of-read:** +- file=META/INVARIANTS.md sha256=fa39a3... lines=412 depth=thorough +- file=../WoA/woa/blueprints/customer.py sha256=8e1a45... lines=891 depth=full +- file=vendor/ogit/NTO/WorkOrder/entities/customer.ttl sha256=4c0b... lines=137 depth=full +``` + +--- + +## §12 Appendix B — When NOT to use coordination + +If the task is... + +- truly independent and parallel → use standard `Agent()` spawns; no coordination layer needed. +- a single one-shot question → use `Agent()` with sub-agent_type=Explore; no `AGENT_LOG.md` write. +- a security-sensitive review → use Layer-0 Teleportation on the main thread; do NOT spawn a separate Agent() that might be compromised by an untrusted source it reads. + +--- + +## §13 Cooperative-Savant Scratchpad Bus + +> Added 2026-05-18. The transport layer for the Cooperative Savant +> Council defined in `autoattended-orchestrator-spec.md` §15. + +### §13.1 What the scratchpad bus is + +A purpose-shaped extension of the Layer-1 File Blackboard (§3.2) +used specifically for the savant council's iterative cooperation. +Same wire format (`tee -a` markdown), same append-only governance +(§7), one new directory convention: + +``` +.claude/board/savant-council-/ +├── ROUND-0-ARTIFACT.md snapshot of artifact under review +├── ROUND--.md one file per (round, savant) +└── COUNCIL-VERDICT.md chairman's synthesis after CONVERGE +``` + +Topic naming: `savant-council-` (e.g. +`savant-council-SPRINT-17-attractor-fold-in/`). + +### §13.2 Per-savant file schema + +```markdown +# ROUND-{N} {savant_id} — {topic} + +**Round:** N +**Savant:** PP-13 | PP-14 | PP-15 | PP-16 +**Read at round start:** [list of peer files read this round] +**Status:** IN-PROGRESS | ROUND-COMPLETE + +## New findings (this round) + +### F{round}-{savant}-{N}: {one-line headline} +**Axis:** AP1..AP9 | BAP1..BAP10 | PD1..PD10 | EP1..EP8 +**Severity:** P0 | P1 +**File:** : +**Detail:** +**Remediation:** + +## Cross-references to peers' findings + +- F{R}-PP-X-N: NOTED — my angle: +- F{R}-PP-Y-N: SUPERSEDED-BY my F{R+1}-{self}-M + +## Withdrawals (my prior findings I am retracting) + +- F{R-1}-{self}-N: WITHDRAWN — covered by PP-X round R from a stronger angle +``` + +### §13.3 Reading-and-writing protocol + +Each savant in each round: + +1. **Read** ALL `ROUND-(R-1)-*.md` files (peer findings from previous + round) plus its own `ROUND-(R-1)-.md` if any. +2. **Decide** cross-refs, withdrawals, new findings. +3. **Write** `ROUND-R-.md` in one `tee -a` call (no + partial writes — savants share a directory and partial + writes confuse peers' next round). +4. **Emit** `Status: ROUND-COMPLETE` if no new findings AND no + un-addressed cross-refers from peers. + +### §13.4 Chairman synthesis + +After CONVERGE (all four savants `ROUND-COMPLETE` in the same +round) the chairman savant (declared in sprint config; default +PP-16 for Protocol A, PP-15 for Protocol B) reads ALL ROUND-*.md +files in lexical order and writes a single `COUNCIL-VERDICT.md` +matching the schema in `autoattended-orchestrator-spec.md` §15.5. + +The chairman: +- MUST cite every kept finding with its raised-by + cross-referrals. +- MUST consolidate duplicates that survived the cooperation rounds + (rare — most should withdraw themselves, but races can leave a + pair that needs one merged into the other). +- MUST NOT add findings of its own that did not appear in any + `ROUND-*.md` (the chairman is a synthesizer, not a fifth voice). +- MUST set `super_verdict` per §15.5 rules. + +### §13.5 Concurrency contract + +Savants may run on separate sessions; the scratchpad bus is the +synchronization point. + +- **Round boundary** is implicit: a savant starts round R only after + it has read all four `ROUND-(R-1)-*.md` files (including its own). +- **Last-writer-wins** is acceptable for the per-savant per-round + file since each (savant, round) pair has exactly one writer by + construction. If a savant writes twice in the same round (e.g. a + retry after a tool-call loop), the second write replaces the first. +- **Round skipping** is forbidden: a savant MUST NOT write + `ROUND-(R+2)` until `ROUND-(R+1)` exists for it. + +### §13.6 Decision matrix update + +Extends §4 with one new row: + +| Need | Workaround | Native MCP equivalent | Cost | +|---|---|---|---| +| Cooperative multi-agent review with iterative cross-refer + withdraw | Layer-1 File Blackboard scoped to `savant-council-/` directory (§13) | `post_council_finding` + `read_council_round` + `subscribe_council_round` | Medium: `tee -a` per round + git commit per round | + +### §13.7 Native MCP endpoints (sketch) + +```yaml +endpoint: post_council_finding +params: + topic: string # e.g. "SPRINT-17-attractor-fold-in" + round: integer + savant: enum (PP-13 | PP-14 | PP-15 | PP-16) + payload: FindingsFile # matches §13.2 schema +returns: + file_id: string + +endpoint: read_council_round +params: + topic: string + round: integer +returns: + findings_by_savant: map[savant -> FindingsFile] + complete_savants: list[savant] # those that emitted ROUND-COMPLETE + +endpoint: subscribe_council_round +params: + topic: string +streams: + event_kinds: [ findings_appended, savant_round_complete, council_converged, council_stalled, council_blocked ] +``` + +### §13.8 Validation rules + +| Rule | Description | Severity | +|---|---|---| +| `COORD-001 directory-naming` | Council scratchpad MUST live at `.claude/board/savant-council-/`. | ERROR | +| `COORD-002 file-naming` | Per-savant files MUST be named `ROUND--PP-.md`. | ERROR | +| `COORD-003 append-only` | The scratchpad directory inherits the append-only governance of §7. | ERROR | +| `COORD-004 chairman-no-new-findings` | The chairman's `COUNCIL-VERDICT.md` MUST NOT introduce findings absent from any `ROUND-*.md`. | ERROR | +| `COORD-005 round-monotonic` | Each savant MUST write `ROUND-(R+1)` only after `ROUND-R-.md` exists. | ERROR | + +--- + +*End of `agent-coordination-mcp-spec.md`.* diff --git a/.claude/ATT/anti-skim-agent-spec.md b/.claude/ATT/anti-skim-agent-spec.md new file mode 100644 index 000000000..62a2fbeb7 --- /dev/null +++ b/.claude/ATT/anti-skim-agent-spec.md @@ -0,0 +1,1077 @@ +# Anti-Skim Agent Specification + +> **Status:** DRAFT · **Version:** 0.1.0 · **Last updated:** 2026-05-17 +> **Format:** NLSpec (per [strongdm/attractor](https://github.com/strongdm/attractor)) +> **Substrate:** Designed to compose on top of `coding-agent-loop-spec.md`; +> adds the verification + escalation layer attractor's spec omits. + +--- + +## §1 Overview + +### §1.1 Purpose + +The Anti-Skim Agent is a per-worker LLM loop that is verifiably +read-before-acting. It treats agent **overconfidence** as the +primary failure mode (cf. Kahneman / Tversky System-1 easy-path, +Dunning-Kruger) and shifts the burden of proof onto the agent: + +- Every claim about a file's content MUST be backed by a SHA-256 + + line-count + reading-depth declaration. +- Every brief contains a sentinel token the agent MUST replay verbatim. +- A spot-check passes one of five lie-detector tests per supervisor pass. + +### §1.2 Relation to `coding-agent-loop-spec.md` + +The Anti-Skim Agent is implementable as a coding-agent-loop session +with the additions in §3–§6. Specifically: + +- The `Session.run()` loop (coding-agent §2.5) is wrapped with a + proof-of-read precondition (§7). +- The `steering_queue` (coding-agent §2.6) is extended with the + typed stuck-protocol blockers in §5. +- The tool-call loop detector in coding-agent §2.10 is adopted + verbatim and elevated to a system-level invariant (§6). +- Tool-output truncation (coding-agent §5) is adopted with one + addition: truncated reads MUST appear in the proof-of-read entry + with `depth=truncated`, not `depth=full`. + +### §1.3 What this spec is NOT + +- Not an orchestrator. Wave-level coordination is in + [`autoattended-orchestrator-spec.md`](./autoattended-orchestrator-spec.md). +- Not a transport. Cross-agent messages flow through the file + blackboard + handover files in + [`agent-coordination-mcp-spec.md`](./agent-coordination-mcp-spec.md). + +--- + +## §2 Terminology + +| Term | Definition | +|---|---| +| **Sentinel token** | A unique opaque string in the worker's brief that the worker MUST replay verbatim in its first reply. | +| **Proof-of-read** | A typed entry `{ file, sha256, lines, depth }` declared by the worker for every file it consumed. | +| **Reading depth** | One of seven escalating levels: `grep` (anti) / `sed-partial` (anti) / `skim` / `read` / `thorough` / `troubleshooting` / `fan-out`. | +| **Lie-Detector test** | One of five tests (LD-1..5) the meta-agent / orchestrator spot-checks against a worker's output. | +| **Drift signal** | A passive indicator of skim or overconfidence (§4.3). | +| **Stuck-protocol blocker** | A typed entry in `META/REQUESTS-FROM-AGENTS.md` (one of five types) signaling "I cannot proceed". | +| **Tool-call loop** | A repeating pattern of length 1, 2, or 3 in the worker's last 10 tool calls. | + +--- + +## §3 The Reading-Depth Ladder + +### §3.1 Seven depths, two anti-depths + +| Depth | Appropriate use | Proof | +|---|---|---| +| `grep` (anti) | Symbol locator AFTER or PARALLEL to a real read. | Worker declares `depth=grep`; NEVER `depth=full`. | +| `sed-partial` / `head-only` (anti) | Snapshotting a few lines for orientation. | Worker declares `depth=sed-partial`; NEVER `depth=full`. | +| `skim` | Huge file; need ONE section located, then read in full. | Worker outputs claims ONLY about the read section. | +| `read` | File < ~500 lines; standard full read. | Top to bottom, no skip; for larger files, offset/limit chunks but actually read every chunk. | +| `thorough` | Iron Rules, INVARIANTS, RFCs, schema migrations. | Read twice: once for comprehension, once for verification. Worker can name 3 sections. | +| `troubleshooting` | Known bug + error message. | Error → grep symbol → READ function in full → READ caller(s). | +| `fan-out` | Cross-file pattern, refactor planning, audit across > 5 files. | Inventory file as output; spawn Explore subagent. | + +### §3.2 Escalation default + +**Default bias is to read too deep, not too shallow.** If in doubt: +upgrade the depth one rung; never downgrade. + +### §3.3 When → minimum depth + +| If the worker is about to ... | ... then at minimum | +|---|---| +| Open `INVARIANTS.md`, `CLAUDE.md`, `BOOT.md` | `thorough` | +| Open a memory file (`CONTEXT.md`, `JOURNAL.md`, `TODO.md`) | `thorough` | +| Touch a schema or migration file | `thorough` + check downstream drift detectors | +| Open an unknown file for the first time | at least `read`, preferably `thorough` | +| Pure symbol lookup ("where is `foo` defined?") | `grep` OK but then read the definition in full | +| Triage a bug report | `troubleshooting` (error → grep → read function + caller) | +| Plan a refactor / wave / audit | `fan-out` (inventory file mandatory) | +| Is unsure which depth | upgrade one rung | + +### §3.4 Truncation interaction + +When `coding-agent-loop-spec` truncates a tool output (per +coding-agent §5.2), the worker's proof-of-read entry for that file +MUST declare `depth=truncated:head-N` or `depth=truncated:tail-N` — +NEVER `depth=full`. + +--- + +## §4 The Lie-Detector + +### §4.1 Five tests + +Cheap to expensive: + +| # | Test | How | Honest agent | Shallow agent | +|---|---|---|---|---| +| LD-1 | **Sentinel-Token** | Brief ends with: "If you have read this fully, begin your first reply with ``" | replays token verbatim | token missing / wrong / paraphrased | +| LD-2 | **Proof-of-Read with SHA** | Output must contain `{ file, sha256, lines, depth }` per file consumed | SHA + line count match the actual file | SHA missing, wrong, or `` placeholder | +| LD-3 | **3-Sections Name Challenge** | "Name 3 sections from file X (heading + approx. line span)" | 3 concrete headings, plausible spans | vague theme labels; no real headings | +| LD-4 | **Negative-Knowledge Test** | "Does file X say anything about topic Y?" — where Y is NOT in the file | "no, not contained" | hallucinates plausible-sounding content about Y | +| LD-5 | **Line-Range Quote** | "Quote lines N–M from file X verbatim" | exact quote OR "range does not exist (file only K lines)" | paraphrases, deviates, or refuses without reason | + +> **Adoption note.** LD-3 / LD-4 / LD-5 are SHOULD-USE on savants +> every wave, MAY-USE on workers selectively — typically when +> `phase_reached=internalize` is claimed or the output looks +> overconfident. Per-worker-per-wave rotation is overkill for +> routine 200-LoC bundles. See §16 Adoption Tiers. + +### §4.2 Trigger heuristic + +| Worker answer pattern | Lie-Detector | +|---|---| +| Vague ("not sure", "about 60", "around 5 sections") | NO trigger — honest uncertainty. | +| Confident **false** | FIRES — overconfidence + drift. | +| Confident **correct** without proof-of-read | FIRES — luck and hallucination are indistinguishable without LD-1..5. | + +### §4.3 Drift signals (passive detection, meta-agent duty) + +The meta-agent scans EVERY worker status before goal-gate verdict. If +any signal triggers, the worker MUST be re-dispatched OR a Lie-Detector +test MUST be applied: + +| Signal | Action | +|---|---| +| `depth=grep` declared on a semantic task | Re-dispatch with `depth=full` enforced. | +| `depth=sed-partial` declared on a semantic task | Re-dispatch; require SHA-256 over the whole file. | +| `depth=full` declared without `sha256` in proof-of-read | Stop; worker MUST back-fill SHA. | +| Status `notes` cites a non-existent section of a file | LD-3 equivalent failed post-facto → P0 re-dispatch. | +| Status `notes` is word-identical to a sibling agent's without cross-read note | Lockstep drift; spot-check LD-5 on one of the two. | +| Opening output enumerates a specific count ("62 lessons") WITHOUT proof-of-read on the source | Overconfidence trigger; agent MUST back-fill SHA + 3 entries by name. | +| Status touches an INVARIANT but its `proof_of_read` does not include `INVARIANTS.md` | Mandatory `thorough` re-read. | + +### §4.4 Burden-of-proof rule + +On suspicion: the worker MUST upgrade. Never "explain away" the +suspicion — either produce the proof, or honestly downgrade +(`depth=skim`/`grep` with a note). + +--- + +## §5 Stuck Protocol + +### §5.1 Five typed blockers + +| Type | Meaning | +|---|---| +| `AMBIGUITY` | Spec is mehrdeutig. More than one sensible interpretation. | +| `MISSING_INVARIANT` | An Iron Rule should cover this case but does not; the convention is missing. | +| `SPEC_SOURCE_MISMATCH` | The authoritative spec says X; the reference source does Y. | +| `BEHAVIOUR_QUESTION` | Possible bug in the reference source; behavioral divergence requires RFC. | +| `EXTERNAL_DEPENDENCY` | Third-party system zickt; workaround unclear. | + +### §5.2 The protocol + +When stuck, the worker MUST: + +1. STOP writing code. +2. Append ONE entry to `META/REQUESTS-FROM-AGENTS.md` with the + §5.3 schema. +3. Set its `status.json` to `outcome=RETRY` and `notes=stuck:`. +4. Idle until the meta-agent writes to `META/ANSWERS-TO-AGENTS.md` + OR updates `META/INVARIANTS.md`. + +### §5.3 Request schema + +```markdown +## Agent {{agent_id}}, file , timestamp + +### Question + + +### Tried + + +### Blocker + + +### Proof-of-read attached +- file= sha256=<...> lines=<...> depth=<...> +- file= sha256=<...> lines=<...> depth=<...> +``` + +The proof-of-read MUST cover EVERY file the worker references in the +question. Stuck requests without proof-of-read are rejected at +intake (§7.5 in `autoattended-orchestrator-spec.md`). + +### §5.4 Forbidden alternatives + +The worker MUST NOT: + +- Guess. +- Write a `TODO:` comment in code and proceed. +- Refactor outside the bundle "while waiting". +- Refile the same request twice without new information. + +--- + +## §6 Tool-Call Loop Detection + +### §6.1 Adopt attractor coding-agent §2.10 + +A worker MUST scan its own last `N=10` tool calls (signature = name + +arguments hash) for repeating patterns of length 1, 2, or 3. + +``` +Pattern length 1: [A][A][A] — same tool, same args, 3+ times +Pattern length 2: [A][B][A][B] — alternating, 2+ cycles +Pattern length 3: [A][B][C][A][B][C] — 3-cycle, 2+ cycles +``` + +### §6.2 Action on detection + +When detected: + +1. The worker MUST NOT issue the next predicted call in the pattern. +2. The worker MUST emit a typed RETRY-WITH-STEER status: + `outcome=RETRY`, `notes=tool-call-loop:length=:pattern=`. +3. The worker MAY file a `META/REQUESTS-FROM-AGENTS.md` entry under + the `AMBIGUITY` blocker type (§5.1) if the loop has no obvious + external resolution. + +### §6.3 Anti-pattern AP9 + +This rule is also enforced by PP-13 brutally-honest-tester as +anti-pattern AP9 (tool-call-loop). PP-13's post-hoc detection +applies if the in-loop detector failed. + +> **Implementation note (honest caveat).** The current Claude Code +> `Agent()` tool does NOT expose a self-interrupt API. The §6.1 +> detector lives only as a prompt-level instruction; workers cannot +> actually terminate themselves via the tool API — they can only +> emit `outcome=RETRY` after they notice the loop. This catches +> in-LLM oscillation; it does NOT catch OS-level hangs (e.g. +> `cargo build` stuck on a network resolver). For OS-level hangs, +> the orchestrator MUST wrap each spawn in a wall-clock timeout. +> See §16.4. + +--- + +## §7 Proof-of-Read Schema + +### §7.1 Per-file entry + +```json +{ + "file": "path/relative/to/repo-root.md", + "sha256": "abc...64-hex...def", + "lines": 412, + "depth": "thorough", + "comment": "two-pass read; INVARIANTS §3.1-3.4 cited in worker output" +} +``` + +### §7.2 Allowed depth values + +``` +grep sed-partial skim +read thorough troubleshooting +fan-out truncated:head-N truncated:tail-N +``` + +`grep`, `sed-partial`, `truncated:*` MUST NOT be combined with claims +that imply full knowledge of the file (LD-3 / LD-4 / LD-5). + +### §7.3 Multiple-file entries + +Workers MUST emit one entry per file consumed. The orchestrator's +goal-gate (PP-13) MAY spot-check up to three entries per worker per +wave via LD-2 (recompute the SHA, compare line count). + +### §7.4 Storage + +Proof-of-read entries live inside the worker's `status.json` +(per `autoattended-orchestrator-spec.md` §9.1). They are also +mirrored to `META/AGENT_LOG.md` as a one-line summary after each +chunk landed: + +``` +## YYYY-MM-DDTHH:MM — A chunk N/M +- chunk N landed (sha ) +- typecheck: green | +- proof-of-read: sha= lines= depth= +``` + +### §7.5 Sentinel-token storage + +The sentinel token is mirrored from the worker's first-reply line +into the `status.json` `sentinel_token` field. Mismatch = FAIL. + +--- + +## §8 Toolchain Tiers + +### §8.1 Tier 1 (every PR — mandatory) + +Owned by PP-13 brutally-honest-tester. Per-language adapter: + +> **Adoption note.** By default, Tier-1 is **coordinator-side** — +> PP-13 runs the full toolchain once on the consolidated diff. Per- +> worker Tier-1 is expensive at 12-agent fan-out (e.g. ~1 GB Rust +> `target/` per worker). Projects MAY push Tier-1 to per-worker +> (smaller workspaces, faster feedback) by setting +> `tier_1_runner: per-worker` in `INVARIANTS.md`. See §16.3. + +| Purpose | Rust | Python | TypeScript | Go | +|---|---|---|---|---| +| Lint, no warnings | `cargo clippy --all-targets --all-features -- -D warnings` | `ruff check` | `eslint --max-warnings 0` | `golangci-lint run` | +| Formatter check | `cargo fmt --check` | `ruff format --check` | `prettier --check` | `gofmt -l` | +| Advisory scan | `cargo audit` | `pip-audit` | `npm audit --omit=dev` | `govulncheck ./...` | +| Dep policy / vet | `cargo deny check` | `deptry .` | (project-defined) | `go vet -all` | +| Typecheck | (clippy implies) | `mypy --strict` | `tsc --noEmit --strict` | (compiler implies) | +| Tests | `cargo test --all-features` | `pytest` | `vitest run` | `go test ./...` | + +### §8.2 Tier 2 (quality / maintenance — opt-in) + +| Purpose | Rust | Python | TypeScript | +|---|---|---|---| +| Unused-dep detector | `cargo machete` | `deptry .` | `depcheck` | +| Unsafe scan | `cargo geiger` | `bandit` | (n/a) | +| Public-API SemVer compat | `cargo semver-checks check-release` | `griffe check` | `api-extractor` | +| Spellcheck | `cargo spellcheck` | CSpell | CSpell | + +### §8.3 Tier 3 (heavier — opt-in, all stable) + +| Purpose | Rust | Python | +|---|---|---| +| Bounded model checker | `kani` | (none standard) | +| Concurrency model checker | `loom` (lib) | (none standard) | +| Mutation testing | `cargo mutants` | `mutmut` | +| Coverage | `cargo tarpaulin` | `pytest --cov` | + +### §8.4 Tier-1 invariant + +For every PR, every language: the worker proves it satisfies a +no-warning gate BEFORE the orchestrator opens the PR. Tier-1 failure +maps directly to `outcome=FAIL` in the status file (§9.2 of +`autoattended-orchestrator-spec.md`). + +--- + +## §9 Anti-Pattern Catalog (AP1..AP9) + +PP-13 brutally-honest-tester actively hunts these: + +| # | Anti-pattern | Detection | Finding | +|---|---|---|---| +| AP1 | Silent fallback that swallows errors (`unwrap_or_default()`, bare `try { ... } catch {}`, `result, _ := f()`) | grep PR diff for these idioms | P0 if in non-test code path | +| AP2 | Hardcoded secret / token / URL in source | grep for plausible secret regex | P0 always | +| AP3 | Compile-time guard dropped (e.g. `#[cfg(test)]` block removed in non-test context) | diff inspection | P0 if guard was load-bearing | +| AP4 | Test passes by tautology (asserts `true`, `assert x == x`) | read every new test body | P1 unless it's the ONLY test for the function (then P0) | +| AP5 | Behavior divergence from spec without merged RFC | spec vs implementation diff | P0 always | +| AP6 | Missing parity-test for a ported handler | check `tests/parity_/` | P0 always | +| AP7 | New workspace dependency not declared in RFC | metadata diff vs `git log --oneline rfcs/` | P0 always | +| AP8 | `#[allow(clippy::*)]` / `# noqa` / `// eslint-disable` without rationale | grep for these directives, check commit body | P1 unless rationale is missing (then P0) | +| **AP9** | **Tool-call loop (length 1/2/3 over last 10 calls; see §6)** | **in-loop detector OR post-hoc replay of tool-call history** | **P1; re-dispatch with tighter scope** | + +--- + +## §10 Definition of Done + +An implementation is conformant if it satisfies ALL of: + +- [ ] Every worker brief contains a unique `sentinel_token`. +- [ ] Every worker first-reply MUST begin with the sentinel verbatim. +- [ ] Every worker emits a `status.json` per + `autoattended-orchestrator-spec.md` §9.1 with one + proof-of-read entry per file consumed. +- [ ] Proof-of-read entries declare `sha256` + `lines` + a depth + from §7.2's allowed list. +- [ ] Workers run the §6.1 tool-call loop detector after EVERY + tool call, with `N=10`. +- [ ] On loop detection, the worker emits `outcome=RETRY` with + `notes=tool-call-loop:...`. +- [ ] On stuck, the worker uses one of the five §5.1 blocker types + and attaches proof-of-read for every referenced file. +- [ ] The meta-agent / supervisor spot-checks ONE of LD-1..LD-5 + on every **savant** per wave (rotating, so the test cannot + be gamed). On routine **workers**, LD-1 (sentinel) is + mandatory; LD-3 / LD-4 / LD-5 are conditional — applied when + `phase_reached=internalize` is claimed OR the output looks + overconfident. See §16. +- [ ] Drift signals (§4.3) are scanned for every worker before the + goal-gate verdict. +- [ ] PP-13 runs the §8.1 Tier-1 toolchain for the worker's + language; Tier-1 failure → `outcome=FAIL`. +- [ ] PP-13's anti-pattern scan covers AP1..AP9. +- [ ] Tool-output truncation (per `coding-agent-loop-spec.md` §5) + surfaces in proof-of-read as `depth=truncated:head-N` or + `depth=truncated:tail-N`; NEVER `depth=full`. +- [ ] `auto_status=false` is mandatory; missing `status.json` = FAIL. + +--- + +## §11 Cross-Provider Parity Matrix + +| Capability | Claude Code | OpenAI Codex / codex-rs | Gemini CLI | Notes | +|---|---|---|---|---| +| Sentinel-token replay (LD-1) | Available via system prompt addendum | Same | Same | Provider-agnostic; uses standard chat completion. | +| Proof-of-read schema (LD-2) | Worker writes status.json | Same | Same | File-based; provider-agnostic. | +| 3-sections challenge (LD-3) | Supervisor prompt | Same | Same | Provider-agnostic. | +| Negative-knowledge test (LD-4) | Supervisor prompt | Same | Same | Provider-agnostic. | +| Line-range quote (LD-5) | Supervisor prompt + file re-read by supervisor | Same | Same | Provider-agnostic. | +| Tool-call loop detection (§6) | Implementable in `Session.run()` loop wrapper | Same | Same | Loop-detector code is provider-independent (operates on local tool-call history). | +| Toolchain tiers (§8) | Bash tools | Bash tools | Bash tools | Per-language commands identical. | +| Truncation → `depth=truncated:*` | Wrapper around tool-output | Wrapper | Wrapper | Provider-specific in WHAT it truncates (different default tool sets), uniform in HOW it's recorded. | + +--- + +## §12 Appendix A — Worker brief template + +```markdown +You are agent {{agent_id}} in wave {{wave_id}} of sprint {{sprint_id}}. + +You own bundle: {{bundle_name}} +Owned files (read-write): +{{owned_files_table}} + +Read-only files: +{{read_only_files_table}} + +Spec files (authoritative): +{{spec_files_table}} + +INVARIANTS (read these first, depth=thorough): +- META/INVARIANTS.md sha256={{invariants_sha}} lines={{invariants_lines}} + +Reading depth required (per anti-skim-agent-spec.md §3.3): +- INVARIANTS.md → thorough +- spec files → full +- reference source files → full +- skeleton files → read +- everything else → at least read + +Status file: write to {{status_file_path}} matching the schema in +autoattended-orchestrator-spec.md §9.1. + +When stuck: file ONE entry in META/REQUESTS-FROM-AGENTS.md per +anti-skim-agent-spec.md §5; set status to outcome=RETRY; idle. + +Done criteria: per autoattended-orchestrator-spec.md §10 + this +spec's §10. + +Tool-call loop detector: run after every tool call per §6. + +SENTINEL TOKEN: {{sentinel_token}} + +Begin your first reply with the sentinel token verbatim. Then state, +in one paragraph, what you understand the bundle to be. Then begin +work. +``` + +--- + +## §13 Skeleton-Fill Contract (Protocol A) + +> Added 2026-05-18. Applies to workers operating in +> `autoattended-orchestrator-spec.md` Protocol A (implementation), +> where PP-16's preflight has produced a commented-out Rust +> skeleton (per §14.4 of the orchestrator spec). + +### §13.1 What the worker receives + +Three inputs: + +1. The skeleton file(s) at `skeleton_output_path` containing + `todo!("SOURCE: :")` macros at every body site. +2. The original spec / reference-source files referenced in each + `SOURCE:` annotation. +3. A SHA-256 of both the skeleton AND each referenced source file, + pinned by PP-16 at preflight time. + +### §13.2 Worker's obligations + +For every `todo!("SOURCE: :")` the worker fills: + +1. **Read the source range** at the declared depth (§3.3); default + for ports is `full`. +2. **Record proof-of-read** for the source file at the declared + line range (§7.1). +3. **Replace `todo!(...)` with the body**, preserving the surrounding + signature exactly. The signature came from PP-16; the worker + does not change it without an Iron-Rule-amending RFC. +4. **Quote the source line range in the commit message body** (per + `autoattended-orchestrator-spec.md` §5.6). +5. **Confirm the skeleton's SHA-256 against the pinned value** at + start of work. If the skeleton has drifted (e.g. a sibling worker + touched it), the worker MUST STOP and file an `EXTERNAL_DEPENDENCY` + blocker in `META/REQUESTS-FROM-AGENTS.md`. + +### §13.3 Forbidden in skeleton-fill mode + +- Changing a signature provided by the skeleton (RFC required). +- Adding a `todo!()` that did NOT come from the skeleton (would + bypass PP-16's source-annotation discipline). +- Removing a `// SAFETY:` comment from an `unsafe` block (PP-13 + will reject; PP-16 wrote it for a reason). +- Filling bodies in a file outside `skeleton_output_path` (§5.1 + unique-file write discipline). + +### §13.4 Reading depth required + +| Source kind | Minimum depth | +|---|---| +| `SOURCE: :` (the function being ported) | `full` for the named line range | +| `UNSAFE-SOURCE: :` | `thorough` for the named range AND the function's callers | +| The skeleton file itself | `read` (to confirm the surrounding signature you're filling into) | +| `META/INVARIANTS.md` | `thorough` (per §3.3) | + +### §13.5 Validation rules + +| Rule | Description | Severity | +|---|---|---| +| `FILL-001 source-range-read` | Every `todo!("SOURCE: P:L-M")` the worker fills MUST appear in the worker's proof-of-read with `file=P, lines covering L-M, depth=full`. | ERROR | +| `FILL-002 skeleton-sha-pin` | Worker MUST verify the skeleton's SHA-256 against the value PP-16 pinned, at start of work. Drift → STOP + `EXTERNAL_DEPENDENCY`. | ERROR | +| `FILL-003 signature-preserved` | Worker MUST NOT change a signature provided by the skeleton without a merged RFC. Diff inspection by PP-15 enforces. | ERROR | +| `FILL-004 unsafe-safety-preserved` | `// SAFETY:` comments on `unsafe` blocks from the skeleton MUST survive into the filled body. PP-13 enforces. | ERROR | +| `FILL-005 no-new-todo` | Worker MUST NOT introduce new `todo!()` calls; every `todo!()` in the filled file MUST trace back to a skeleton entry. | ERROR | + +### §13.6 Definition of Done (skeleton-fill) + +- [ ] Every `todo!()` in the assigned skeleton file(s) is replaced. +- [ ] No new `todo!()` introduced (FILL-005). +- [ ] Skeleton SHA matched at start; final SHA different (FILL-002). +- [ ] Proof-of-read covers every `SOURCE:` annotation (FILL-001). +- [ ] All signatures preserved (FILL-003). +- [ ] All `// SAFETY:` comments preserved (FILL-004). +- [ ] Tier-1 toolchain green on filled file (§8.1). +- [ ] Status file written per `autoattended-orchestrator-spec.md` §9.1. + +--- + +## §14 Reading Phases (orthogonal to depth) + +> The Reading-Depth Ladder in §3 says **how much** of a file you cover. +> The Reading Phases in this section say **what you do** with what you +> covered. Both are required for a read to count as complete. + +### §14.1 The four phases + +| # | Phase | Question it answers | Output the worker MUST be able to produce | +|---|---|---|---| +| 1 | **Survey** | "What is in this file? What is its shape?" | Section list with line numbers; file shape (N sections, K loc, language); top-level headline. | +| 2 | **Evaluation** | "What of this matters for my task?" | A relevance map: which sections / line ranges are relevant to the current bundle, prioritized P0 / P1 / unused. | +| 3 | **Critical findings** | "What is wrong, missing, contradictory, drifted?" | A typed finding list (severity P0 / P1) — Iron-Rule violations, spec-vs-source drift, missing sections, anchors that no longer resolve, dead references. | +| 4 | **Internalize** | "Can I act on this without re-reading?" | Pass LD-3 (3-section name challenge), LD-4 (negative-knowledge), LD-5 (line-range quote). Can paraphrase faithfully; can answer "what is NOT in this file?". | + +Phase ordering is typically **Survey → Evaluation → Critical findings → +Internalize**, but findings often surface DURING internalize (the act of +internalizing exposes contradictions). A complete reading reaches all +four; a partial reading stops earlier and MUST declare so. + +### §14.2 Phase × depth matrix + +| Depth | Survey | Evaluation | Critical findings | Internalize | +|---|:-:|:-:|:-:|:-:| +| `grep` (anti) | partial | no | no | no | +| `sed-partial` / `head-only` (anti) | partial | partial | no | no | +| `skim` | yes | partial | partial (per-section only) | no | +| `read` | yes | yes | partial | partial | +| `thorough` | yes | yes | **yes** | **yes** | +| `troubleshooting` | yes | yes | yes (focused on the bug) | yes (focused) | +| `fan-out` | yes (per-file shallow) | yes | yes | partial (per file) | +| `truncated:head-N` / `truncated:tail-N` | partial | partial | no | no | + +Only `thorough` and `troubleshooting` (within its focused scope) achieve +the full ladder. `fan-out` achieves internalize *per-file* but the +inventory output is the synthesis — the worker MUST treat each file in +the inventory as needing its own `thorough` pass before acting on it. + +### §14.3 Phase outputs in the worker's status.json + +The `proof_of_read` schema (§7.1) is extended with a `phase_reached` +field naming the highest phase completed for each file: + +```json +{ + "file": "META/INVARIANTS.md", + "sha256": "fa39a3...", + "lines": 412, + "depth": "thorough", + "phase_reached": "internalize", + "phases_evidence": { + "survey": "9 sections; INVARIANTS canonical structure recognized", + "evaluation": "§BBB + §UPSERT-PATTERN are load-bearing for this bundle", + "critical_findings": "§UPSERT-PATTERN line 187 contradicts the customer.ttl ogit:CustomerWriter mandatory-attributes (filed REQUESTS-FROM-AGENTS.md#A4-2026-05-18T14:22)", + "internalize": "can answer LD-3/4/5 verbatim" + } +} +``` + +The `phases_evidence` map is OPTIONAL when `phase_reached=survey` +(no evidence beyond the section list is required) but BECOMES required +at `phase_reached >= evaluation` because that phase claims judgment. + +### §14.4 Mapping Lie-Detector tests to phases + +Each LD-1..LD-5 test (§4.1) probes a specific phase. The meta-agent +SHOULD rotate the spot-check across the four phases so workers cannot +game which phase to fake. + +| Test | Probes phase | What a passing answer proves | +|---|---|---| +| LD-1 Sentinel-Token | **Survey** of the brief | The worker actually loaded the brief into context. | +| LD-2 Proof-of-Read with SHA | **Survey** of the file | The worker accessed the file at the declared content. | +| LD-3 3-Sections Name Challenge | **Survey + Evaluation** | The worker can locate structure AND chose which sections to attend to. | +| LD-4 Negative-Knowledge Test | **Internalize** | The worker built a faithful mental model — can answer "what is NOT in this file" without hallucinating. | +| LD-5 Line-Range Quote | **Internalize + Critical findings** | The worker can recall verbatim AND detect drift between recall and source. | + +A worker declaring `phase_reached=internalize` MUST be able to pass +LD-3, LD-4, **and** LD-5. Spot-check failure at a claimed phase ⇒ +phase claim is rejected and the proof-of-read is auto-downgraded to +the highest demonstrably-passed phase. + +### §14.5 Per-file required phase by file kind + +Different file kinds REQUIRE different minimum phases. The worker +brief MUST declare per-file phase requirements alongside depth +requirements: + +| File kind | Minimum depth | Minimum phase | +|---|---|---| +| `META/INVARIANTS.md` | `thorough` | **internalize** | +| `CLAUDE.md` / `BOOT.md` / RFCs | `thorough` | **internalize** | +| Memory files (`CONTEXT.md` / `JOURNAL.md` / `TODO.md`) | `thorough` | **internalize** | +| Spec files for the bundle (e.g. TTL, OpenAPI, JSON-schema) | `full` (read) | **internalize** | +| Reference-source for ports | `full` | **internalize** | +| Skeleton files the worker fills | `read` | **evaluation** | +| Sibling-bundle files (read-only context) | `skim` | **evaluation** | +| Files referenced for general orientation | `skim` | **survey** | +| Files referenced for symbol lookup only | `grep` | **survey** | + +When a worker stops at a phase lower than required, the read DOES +NOT count as complete — even if the depth was sufficient. Both axes +must clear the bar. + +### §14.6 Critical findings escalation + +Findings produced in phase 3 (Critical findings) are routed by +severity: + +| Finding severity | Filed where | Worker action | +|---|---|---| +| P0 — Iron-Rule violation in input, spec-vs-source contradiction, broken anchor that affects the bundle | `META/REQUESTS-FROM-AGENTS.md` with blocker type from §5.1; worker idles | STOP work; do not proceed to commit | +| P1 — minor inconsistency, dead reference outside bundle scope, typo, stale comment | `Altlasten.md` / `TECH_DEBT.md` row with the worker's bundle id | Continue work; the orchestrator triages later | +| INFO — observation that does not affect the bundle | Notes field in `status.json`; not filed elsewhere | Continue work | + +A worker that internalizes but does NOT escalate a P0 finding is in +violation: missing-escalation is itself a P0 finding that PP-13 +will catch (anti-pattern AP1 — "silent fallback that swallows +errors" — generalizes here as "silent skim that swallows findings"). + +### §14.7 Validation rules + +| Rule | Description | Severity | +|---|---|---| +| `PHASE-001 phase-declared` | Every `proof_of_read` entry MUST include a `phase_reached` field. Absent ⇒ treated as `phase_reached=survey` (the weakest claim). | ERROR | +| `PHASE-002 phase-monotonic-with-depth` | A `phase_reached` claim MUST be consistent with the §14.2 matrix. E.g. `depth=grep` + `phase_reached=internalize` is invalid. | ERROR | +| `PHASE-003 phase-evidence-required` | When `phase_reached >= evaluation`, the `phases_evidence` map MUST be present with non-empty entries for each phase claimed. | ERROR | +| `PHASE-004 file-kind-phase-bar` | When the worker brief declares a minimum phase per §14.5 for a file, the worker's `phase_reached` for that file MUST be ≥ the declared minimum. | ERROR | +| `PHASE-005 critical-findings-routed` | P0 findings produced during phase 3 MUST be filed to `META/REQUESTS-FROM-AGENTS.md` BEFORE the worker commits any code that depends on the affected input. | ERROR | +| `PHASE-006 internalize-passes-LD-3-4-5` | A claim of `phase_reached=internalize` MUST survive spot-checks of LD-3, LD-4, and LD-5 on rotation. Failure ⇒ auto-downgrade to highest-passed phase. | ERROR | + +### §14.8 Definition of Done (per-file read) + +A read of a single file is complete when ALL of: + +- [ ] Depth from §3 is at the declared level. +- [ ] Phase from §14.1 reaches the required minimum per §14.5. +- [ ] `proof_of_read` entry includes `sha256`, `lines`, `depth`, + `phase_reached`, and `phases_evidence` for `evaluation+`. +- [ ] Any P0 critical finding is filed before the worker commits. +- [ ] LD-3 / LD-4 / LD-5 spot-checks pass if `phase_reached=internalize` + is claimed. + +--- + +## §15 Cognitive Anti-Patterns (CA1..CA4) + +> Where AP1..AP9 (§9) catch **output** problems — the code itself +> looks wrong — CA1..CA4 catch **cognition** problems — the way the +> worker arrived at the output is wrong. CA findings often surface +> at the same time as AP findings; the distinction is that CA fixes +> require process change (re-read, re-think, re-spawn) while AP +> fixes can sometimes be edited in place. +> +> The cognitive anti-patterns are jointly owned: the meta-agent +> spots them during PR review via the Lie-Detector (§4); PP-13 +> spots them during code review by correlating commit timestamps +> with proof-of-read timestamps. + +### §15.1 The four cognitive anti-patterns + +| # | Name | What it looks like | Detection signature | Counter-pattern | Severity | +|---|---|---|---|---|---| +| **CA1** | **Cognitive dissonance** | Worker sees a contradiction between two authoritative sources (spec vs reference source, INVARIANT vs comment, TTL vs code) and resolves by hand-waving or picking one without investigation. The dissonance gets papered over instead of escalated. | Output contains phrases like "I went with", "I chose", "I preferred Y because it feels right / is already there / compiles", with no corresponding `SPEC_SOURCE_MISMATCH` entry in `META/REQUESTS-FROM-AGENTS.md`. | File `SPEC_SOURCE_MISMATCH` (§5.1) and idle until the meta-agent writes an RFC. Never resolve dissonance unilaterally. | **P0** | +| **CA2** | **Dunning-Kruger overconfidence** | Worker confidently claims knowledge in an area where its actual depth is shallow. The agent doesn't know what it doesn't know, so its sense of certainty is un-calibrated. The output reads as definite where the read was thin. | A `phase_reached=internalize` claim (§14) that fails LD-3 / LD-4 / LD-5 spot-checks. A specific numerical claim ("62 lessons", "the signature has 3 arguments") with no corresponding `proof_of_read` SHA. Confident paraphrase where the source actually says something else. | Auto-downgrade the phase claim to the highest demonstrably-passed phase (per `PHASE-006`). Re-read at the proper depth + phase. If the worker keeps overshooting, route them to a smaller bundle. | **P0** | +| **CA3** | **Kahneman/Tversky easy-path (System-1 short-circuit)** | Worker pattern-matches surface features of the input — "file looks like a CRUD handler, so it must be a CRUD handler" — without running the System-2 check (read the actual function body, compare against the spec). Easy-path is fastest when surface matches reality, but devastating when it doesn't. | The first reply is plausibly-correct-sounding but the proof-of-read is `depth=grep` or `depth=sed-partial`. Output describes structure in generic terms ("standard route handler", "typical migration") rather than specific terms ("the function on lines 47-91 dispatches on req.path"). | Force System-2: require LD-2 (SHA + line count) and LD-5 (line-range quote) before accepting any structural claim. Reading depth MUST be at least `read`; phase MUST be at least `evaluation` before any output that makes a structural claim. | **P0** | +| **CA4** | **Eager amok** | Worker starts writing code (or commits, or pushes) before completing the required reading + planning phases. Enthusiasm runs ahead of discipline. The work *looks* productive — there's a diff — but it's built on incomplete understanding. | First code-write timestamp predates the `proof_of_read` SHA-pin timestamps for one or more required files (§14.5). `status.json` shows commits landing while `phase_reached` is still `survey` or `evaluation` on files that should be at `internalize`. Worker's narrative jumps from brief-read to first-commit with no visible thinking step. | STOP and require complete proof-of-read for ALL files at their required §14.5 minimum phase BEFORE any commit. The Iron Rule applies regardless of how "obvious" the implementation seems. | **P0** | + +### §15.2 Why all four are P0 + +Each of CA1..CA4 produces output that *looks* right. AP1..AP9 produce +output that looks wrong (a `unwrap_or_default()` is visible; a missing +parity test is visible). Cognitive anti-patterns produce output whose +correctness depends entirely on the unverifiable claim that the +worker read + understood + thought before writing. They are P0 +because they break the trust contract the meta-agent depends on when +reviewing diffs without re-doing the worker's read. + +### §15.3 Joint ownership: who catches what + +| Anti-pattern | Catch site | Detection method | +|---|---|---| +| CA1 cognitive dissonance | Meta-agent (PR review) + PP-15 (cross-source diff) | Grep PR commit messages for "I went with" / "I chose" / "preferred" against spec-vs-source mismatch; check `REQUESTS-FROM-AGENTS.md` for absence of corresponding blocker. | +| CA2 Dunning-Kruger overconfidence | Meta-agent (Lie-Detector spot-check) | Rotate LD-3 / LD-4 / LD-5 on one worker per wave; cross-check `phase_reached` claims against actual passing. | +| CA3 Kahneman/Tversky easy-path | Meta-agent (proof-of-read inspection) + PP-13 (output-vs-source diff) | Worker output reads as paraphrase rather than quote; SHA missing; reading depth declared inconsistent with output claims. | +| CA4 eager amok | PP-13 (commit-timestamp audit) + Meta-agent (status.json ordering check) | Commit timestamps predate the `proof_of_read` SHA-pin timestamps; `phase_reached` was below the required minimum at first commit. | + +### §15.4 Counter-patterns: how a healthy worker behaves + +| Anti-pattern | Healthy alternative | +|---|---| +| CA1 | "I noticed the spec says X but the existing code does Y. Filing `SPEC_SOURCE_MISMATCH`. Idling." | +| CA2 | "I am confident about §3 of INVARIANTS.md (depth=thorough, phase=internalize). I am uncertain about §6 (depth=skim, phase=survey). I will deepen §6 before claiming anything about it." | +| CA3 | "Before describing this file's structure, here is `proof_of_read: { file=X, sha256=..., depth=read, phase_reached=evaluation }`. The structure is: [specific section names with line numbers]." | +| CA4 | "Reading phase complete on all 4 required files. Filing critical findings (zero P0). Status: `phase_reached=internalize` on all files. NOW beginning the first commit." | + +### §15.5 Validation rules + +| Rule | Description | Severity | +|---|---|---| +| `CA-001 dissonance-escalation` | When a worker's output mentions spec-vs-source divergence, `META/REQUESTS-FROM-AGENTS.md` MUST contain a corresponding `SPEC_SOURCE_MISMATCH` blocker entry. Absence ⇒ CA1 P0 finding. | ERROR | +| `CA-002 confidence-calibration` | A `phase_reached=internalize` claim that fails LD-3 / LD-4 / LD-5 spot-check ⇒ CA2 P0; phase claim auto-downgraded. | ERROR | +| `CA-003 system-2-required-before-structural-claim` | Any structural claim about a file's content (function count, section names, signature shapes) MUST be preceded by a `proof_of_read` entry with `depth >= read` AND `phase_reached >= evaluation`. Otherwise CA3 P0. | ERROR | +| `CA-004 read-before-write-ordering` | `status.json` MUST show all required-minimum `proof_of_read` entries timestamped BEFORE the first code-commit timestamp for files at the §14.5-required minimum phase. Otherwise CA4 P0. | ERROR | + +### §15.6 Mindset-level relation to the four savants + +The four savants in `autoattended-orchestrator-spec.md` §4.0 each +have a *cognitive* posture that resists a specific CA: + +| Savant | Mindset | Primarily resists | +|---|---|---| +| PP-13 brutally-honest-tester | "what would break in production at 3 a.m. that the author talked themselves out of seeing?" | CA1 (talking-yourself-out-of-seeing IS cognitive dissonance) + CA4 (production doesn't break because of enthusiasm) | +| PP-14 convergence-architect | "what could this become that we aren't seeing?" | CA3 (easy-path closes possibilities prematurely) | +| PP-15 baton-handoff-auditor | "do these contracts actually line up at the seams?" | CA1 (dissonance often hides at handoffs) | +| PP-16 preflight-drift-auditor | "does the plan still match the system as it actually is?" | CA2 (overconfidence in a plan that has drifted from reality) | + +The full 4-savant pass is jointly an antibody against all four +cognitive anti-patterns. A wave that runs only one savant catches +only the CAs that savant's mindset resists; a wave that runs the +cooperative council (orchestrator spec §15) catches all four. + +### §15.7 Definition of Done (cognitive-hygiene) + +A worker passes the cognitive-hygiene gate when ALL of: + +- [ ] `CA-001` clean: every spec-vs-source mention is matched by a filed `SPEC_SOURCE_MISMATCH` blocker. +- [ ] `CA-002` clean: every `phase_reached=internalize` claim survives LD-3/4/5 spot-checks. +- [ ] `CA-003` clean: every structural claim is backed by a sufficient `proof_of_read`. +- [ ] `CA-004` clean: read timestamps precede commit timestamps for all required-minimum files. +- [ ] Worker did not output `I went with` / `I chose` / `I preferred` without an associated blocker filing. + +--- + +## §16 Adoption Tiers (project-specific) + +> Specs ship a maximalist surface so every reasonable use-case is +> covered. Real projects adopt subsets. This section names what a +> project SHOULD adopt on day one (Tier-A), what's worth the cost +> only at high stakes (Tier-B), what's project-overrideable +> (Tier-C), and what has honest known limits (Tier-D). +> +> **Origin:** field-test feedback from a 12-agent Rust fan-out +> (sprints PR-X4 cascade / PR-X10..13 consolidation / PR-X12 codec) +> where ~1 GB per-worker `target/` dirs made universal per-worker +> Tier-1 toolchain prohibitively expensive, and where the +> `Agent()` API's missing self-interrupt forced the §6.1 detector +> to be prompt-level only. + +### §16.1 Tier-A — adopt on day one (minimum viable) + +The minimal surface delivering ≥80% of the framework's value at +≤20% of the ceremony. + +| § | What | Why mandatory | +|---|---|---| +| §3 | Reading-Depth Ladder per file | Single most important anti-skim primitive. | +| §5 | 5 typed stuck blockers (`AMBIGUITY` / `MISSING_INVARIANT` / `SPEC_SOURCE_MISMATCH` / `BEHAVIOUR_QUESTION` / `EXTERNAL_DEPENDENCY`) | Replaces vague "report under 200 words" with crisp typed routing. | +| §7 | `proof_of_read` schema in `status.json` | `{file, sha256, lines, depth, phase_reached}`. Trivial overhead; big audit win. | +| §14 | Reading Phases per file + §14.5 per-file-kind minimum | Catches "agent confidently asserts file content without reading" — the most common silent-skim failure. | +| §15 | CA1..CA4 cognitive anti-pattern framing | The lens a savant audit already uses; cheap to adopt. | +| §15.6 | 4-savant council for P0 review on consolidation sprints | High-leverage audit; runs on Opus, once per sprint. | +| §4.1 LD-1 | Sentinel tokens | ~50 LoC ceremony per brief; catches the trivial "agent didn't read the brief" case. | +| §6 | Prompt-level tool-call-loop instruction (best-effort, see §16.4) | Catches in-LLM oscillation when the worker honors the instruction. | +| §17 | PR-Lifecycle + Auto-Resolve (worker creates PR, subscribes to CI/review events, classifies each event silent-fix / ask-user / skip) | A worker's "done" is PR merged or PR closed, not branch pushed. Without §17 the framework stops at push and the human owns the CI loop. | + +### §16.2 Tier-B — adopt for savants / high-stakes only + +Reserve for review agents (PP-13/14/15/16) and high-stakes worker +spawns. Skip for routine 200-LoC skeleton-fills. + +| § | What | When to adopt | +|---|---|---| +| §4.1 LD-3 / LD-4 / LD-5 | 3-section challenge / negative-knowledge / line-range quote | On savants **every wave**. On routine workers **only when** `phase_reached=internalize` is claimed OR the output looks overconfident. Not as routine per-worker per-wave rotation. | +| §13 Skeleton-Fill (Protocol A) | `todo!("SOURCE:")` markers force read-before-fill | High-stakes ports (Python→Rust transcode, x265→Rust codec) where source fidelity matters. Skip for greenfield prose features. | +| Full §10 / §13.6 / §14.8 / §15.7 DoD checklists | Per-PR DoD verification | Per-sprint, not per-PR, until v0.2 prune. See §16.6. | + +### §16.3 Tier-C — project-overrideable defaults + +Defaults this spec recommends but which real projects often override. +The override SHOULD be documented in the project's `INVARIANTS.md`. + +| § | Default | Override scenario | Project's typical choice | +|---|---|---|---| +| §8.1 Tier-1 toolchain | Coordinator-side (PP-13 runs once on consolidated diff) | Small workspace where per-worker compile is fast | `tier_1_runner: per-worker` | +| §4.1 LD-3/4/5 rotation | Spot-check only on savants + overconfident workers | Project wants per-worker per-wave rotation | `lie_detector_rotation: per-worker-per-wave` | +| §13 Skeleton-Fill | Opt-in per sprint via `preflight.skeleton: enabled` | Greenfield code with no SOURCE to reference | `preflight.skeleton: disabled` (default for greenfield) | +| §14.5 per-file-kind minimum phase | INVARIANTS.md / spec / reference = internalize | Project's INVARIANTS lives elsewhere or doesn't exist | Project-defined `file_kind_phase_map` in `INVARIANTS.md` | + +### §16.4 Tier-D — known-limited (honest caveats) + +| § | Caveat | +|---|---| +| §6.1 in-loop tool-call detection | The current Claude Code `Agent()` tool does NOT expose an interrupt API. The detector lives only as a prompt-level instruction. Catches in-LLM oscillation; does NOT catch OS-level hangs. Wrap each spawn in a wall-clock timeout at the orchestrator layer for OS hangs. | +| §8.1 per-worker Tier-1 | On Rust workspaces with ~1 GB per-worker `target/` dirs, per-worker Tier-1 at 12-agent fan-out is disk-prohibitive. Use the §16.3 coordinator-side override. | +| §4.1 LD-1 sentinel tokens | Slight per-brief ceremony (~50 LoC). Project MAY template the token at orchestrator level rather than per-worker brief to amortize the cost. | +| Spec line-count at v0.1.0 DRAFT | This spec is intentionally maximalist for the first revision. Plan a v0.2 prune of the four DoD checklists (§10 / §13.6 / §14.8 / §15.7) once one real sprint has run with the framework — keep only items that caught field bugs. | + +### §16.5 Sprint-by-sprint adoption worked example + +A 12-agent Rust fan-out doing cascade + codec + consolidation: + +| Sprint | Tier-A adopted | Tier-B adopted | Tier-C overrides | +|---|---|---|---| +| PR-X4 splat cascade (12 workers, internal refactor) | full | LD-1 sentinel only; skip LD-3/4/5 on routine workers | `tier_1_runner: coordinator` | +| PR-X12 codec (Rust port of x265 reference) | full | full §13 Skeleton-Fill (high-stakes source-fidelity port); LD-3/4/5 on consolidation worker | `tier_1_runner: coordinator` | +| PR-X10+11+13 consolidation review (savant pass) | n/a (review pass) | full §15.6 four-savant council on Opus | n/a | + +### §16.6 v0.2 prune targets (slim once field-tested) + +After one full sprint with this spec, slim the following sections to +items that produced field-tested catches: + +| Section | Current items | Slim target | +|---|---:|---| +| §10 Definition of Done | 13 | keep ~5 that catch real bugs | +| §13.6 Skeleton-Fill DoD | 7 | keep ~3 | +| §14.8 per-file-read DoD | 5 | keep ~3 | +| §15.7 cognitive-hygiene DoD | 5 | keep ~3 | +| §8.1 / §8.2 / §8.3 Tier tables | full per-language matrix | slim to entries actually run in the field | + +Goal: spec line-count drops 30-50% by v0.2 while preserving the +patterns that caught real bugs. + +--- + +## §17 PR-Lifecycle + Auto-Resolve + +> Workers do not stop at "branch pushed." A worker's done condition +> is **PR merged** OR **PR closed by orchestrator/human as FAIL** — +> the lifecycle extends through CI iteration and review-comment +> resolution. This section specifies what happens between the +> worker's first push and one of those terminal states. +> +> **Tier:** Tier-A per §16.1 for any sprint that opens PRs. +> **Transport:** `mcp__github__create_pull_request` + +> `mcp__github__subscribe_pr_activity` + `git push` for fixes; events +> arrive as `` envelopes (see +> `agent-coordination-mcp-spec.md` §3.3). + +### §17.1 The extended worker lifecycle + +``` +READ → WRITE → TEST → COMMIT → PR → SUBSCRIBE → [AUTO-RESOLVE LOOP] → MERGE | FAIL + ↑ ↓ + │ event arrival + │ classify (§17.4) + │ silent-fix | ask-user | skip + └ if silent-fix: push commit +``` + +Steps 1-4 are the existing §13.2 work pattern. Steps 5-7 are new. +MERGE / FAIL are terminal — worker writes its final `status.json` +and calls `mcp__github__unsubscribe_pr_activity`. + +### §17.2 PR creation (step 5) + +After first push, the worker calls: + +``` +mcp__github__create_pull_request( + owner=, + repo=, + head=, # e.g. claude/wave-12-A4 + base=, # from sprint header + title=": (WT-NN)", + body="""\ +## Bundle ownership +{{ownership_table}} + +## Status +{{status_json_excerpt}} + +## Proof-of-read +{{proof_of_read_summary}} + +## Sentinel +{{sentinel_token}} +""", + draft=, # per sprint header + labels=["sprint-", "bundle-"] +) +``` + +The PR body MUST contain the sentinel token verbatim. The +orchestrator can grep open PRs for sentinel presence as a fast LD-1 +check (per `PR-007`). + +### §17.3 Subscription (step 6) + +Within 60 seconds of PR creation, the worker MUST call: + +``` +mcp__github__subscribe_pr_activity(owner, repo, pullNumber) +``` + +The worker then enters an event-driven idle state. Events arrive +as `` envelopes containing CI run +completions, review comments, PR state changes (merged/closed), +and label changes. + +### §17.4 The three-option event-handling decision tree + +For each event, the worker MUST classify into one of three options +(this matches the CCA2A handling protocol from the governing prompt +template): + +| Option | When | Action | +|---|---|---| +| **1. Silent fix** | Confidence high; fix in-scope of worker's bundle; fix does not contradict spec / INVARIANTS | Read failing CI logs / review comment fully (§3 depth ladder, §14.5 minimum phase for log files: `read` + `phase=evaluation`); make the fix; push commit; update `status.json`; continue idle for next event. Reply on PR ONLY if the fix resolves a specific review question. | +| **2. Ask user (file PROPOSAL)** | Ambiguity (CA1 / CA3 trigger); cross-bundle implications; spec-vs-comment contradiction; reviewer asks "should X be Y or Z?" | Append `Kind=PROPOSAL` entry to `AGENT_LOG.md` (`agent-coordination-mcp-spec.md` §1.3) with the question; idle until orchestrator/user answers via `ANSWERS-TO-AGENTS.md`. Do NOT push speculative fixes. | +| **3. Skip silently** | Duplicate event; stale CI; "LGTM" / approval; bot comment (Dependabot et al); event addressed in a prior iteration | Record the classification on `AGENT_LOG.md` (`Kind=DECISION`, body: `skip-silent: `); continue idle. Do NOT reply on the PR. | + +### §17.5 Event taxonomy + default classification + +| Event class | Specific signal | Default option | Confidence required | +|---|---|---|---| +| CI lint failure | rustfmt / clippy single-line | silent fix | high | +| CI typecheck failure | single error, in-bundle | silent fix | high | +| CI typecheck failure | error in shared zone | ask-user (cross-bundle) | n/a | +| CI test failure | regression in own bundle; root cause identifiable from log | silent fix | medium | +| CI test failure | regression elsewhere | ask-user | n/a | +| CI build-time-out | first occurrence | skip-silent (re-CI); if recurring → ask-user | n/a | +| CI dependency-resolve failure | new transitive dep, missing crate, version conflict | ask-user (`EXTERNAL_DEPENDENCY` blocker) | n/a | +| CI OOM | first occurrence | ask-user (orchestrator allocates memory) | n/a | +| Review comment "could you also X" | X is in-bundle | silent fix | medium | +| Review comment "should this be X or Y?" | ambiguity | ask-user (`AMBIGUITY` blocker) | n/a | +| Review comment "blocking — need RFC" | spec-vs-impl mismatch | ask-user (`SPEC_SOURCE_MISMATCH` blocker) | n/a | +| Review comment "LGTM" / approval | terminal-success-adjacent | skip-silent | n/a | +| Bot comment (Dependabot, codecov, sonarcloud, …) | informational | skip-silent | n/a | +| @-mention to specific human user | belongs to a human | skip-silent (do not reply) | n/a | +| PR merged | terminal | write `outcome=SUCCESS`, unsubscribe, exit | n/a | +| PR closed without merge | terminal (orchestrator/human FAIL'd it) | write `outcome=FAIL`, unsubscribe, exit | n/a | + +### §17.6 Budget + termination + +| Limit | Default | When breached | +|---|---|---| +| Max auto-fix iterations per PR | 5 | Worker emits `outcome=FAIL`, body: `auto-resolve-budget-exhausted`; orchestrator decides next | +| Max wall-clock per PR | 24 h (project-configurable) | Same as above | +| Per-iteration token cost cap | per §16 model-stylesheet | Escalate to Opus only if stylesheet allows | +| Consecutive `skip-silent` events | 20 | Worker writes a `STATUS` entry noting the silence and re-subscribes (the PR is in a quiet state) | + +### §17.7 Cognitive anti-patterns extend to auto-resolve + +Every CA1..CA4 from §15 applies to each auto-resolve iteration, not +just the initial implementation. Validation rules CA-001..CA-004 +apply unchanged. PR-005 below extends the cross-bundle rule. + +| Anti-pattern | Auto-resolve-specific shape | +|---|---| +| CA1 cognitive dissonance | Worker reads a review comment that contradicts INVARIANTS and "just fixes per the comment" without filing `SPEC_SOURCE_MISMATCH`. | +| CA2 Dunning-Kruger overconfidence | Worker pushes an auto-fix without `proof_of_read` on the failing log; claims `internalize` of the failure without LD evidence. | +| CA3 Kahneman/Tversky easy-path | Worker pattern-matches "CI red → push the same fix as last time" without reading the actual failure. | +| CA4 eager amok | Worker pushes a fix before reading the full CI log; commits before completing §17.4 classification. | + +### §17.8 Wire-format integration + +Every auto-resolve action emits an entry on `AGENT_LOG.md` per +`agent-coordination-mcp-spec.md` §1.3: + +```markdown +## 2026-05-19T08:14 — DECISION[INFO]: A4 silent-fix clippy::redundant_clone (sonnet, claude/wave-12-A4) + +**Author:** A4 +**Kind:** DECISION +**Severity:** INFO +**Refs:** PR-#427 commit-fa00b1c +**Proof-of-read:** +- file=ci/clippy-log.txt sha256=8e1a... lines=47 depth=full +- file=src/customer/master.rs sha256=4c0b... lines=312 depth=read + +--- + +Clippy flagged a `Vec.clone()` on line 187. Reviewed the call site; +the clone was leftover from a prior refactor. Replaced with `&borrow`. +Commit fa00b1c pushed. Awaiting re-CI. +``` + +Auto-resolve actions are first-class on the wire format — the +orchestrator and any subscribed sibling session see them in real +time. + +### §17.9 Validation rules + +| Rule | Description | Severity | +|---|---|---| +| `PR-001 worker-created-PR` | Within 30 minutes of first push, the worker MUST have created a PR via `mcp__github__create_pull_request`. | ERROR | +| `PR-002 subscription-active` | Within 60 seconds of PR creation, the worker MUST have called `mcp__github__subscribe_pr_activity`. | ERROR | +| `PR-003 max-iterations` | Auto-resolve MUST NOT exceed §17.6 budget without escalation. Budget exhaustion ⇒ `outcome=FAIL`, reason `auto-resolve-budget-exhausted`. | ERROR | +| `PR-004 cognitive-hygiene-extends` | CA-001..CA-004 (§15.5) apply unchanged to every auto-resolve iteration, not just initial implementation. | ERROR | +| `PR-005 cross-bundle-fix-forbidden` | A worker MUST NOT push commits that touch files outside its bundle, even during auto-resolve. Cross-bundle failures escalate via `AGENT_LOG.md` `Kind=PROPOSAL`. | ERROR | +| `PR-006 event-classification-recorded` | Each event the worker receives MUST be classified per §17.4 and the classification appended to `AGENT_LOG.md` (`Kind=DECISION`). | ERROR | +| `PR-007 sentinel-in-pr-body` | The PR body MUST contain the worker's sentinel token verbatim. | ERROR | +| `PR-008 unsubscribe-on-terminal` | On PR merge or close, the worker MUST call `mcp__github__unsubscribe_pr_activity` before writing its terminal `status.json`. | ERROR | +| `PR-009 no-reply-on-skip` | A `skip-silent` classification MUST NOT produce a reply on the PR (avoid PR-noise pollution from agents). | WARNING | + +### §17.10 Definition of Done (auto-resolve) + +A worker passes the auto-resolve gate when ALL of: + +- [ ] Created a PR (`PR-001`). +- [ ] Subscribed within 60s (`PR-002`). +- [ ] Each event classified per §17.4 and recorded on `AGENT_LOG.md` (`PR-006`). +- [ ] No cross-bundle fix commits (`PR-005`). +- [ ] CA-001..CA-004 clean on every iteration (`PR-004`). +- [ ] Sentinel token in PR body (`PR-007`). +- [ ] Auto-resolve budget not exceeded without escalation (`PR-003`). +- [ ] Unsubscribed and wrote terminal `status.json` (`PR-008`). +- [ ] Terminal outcome is `SUCCESS` (PR merged) OR `FAIL` (PR closed without merge OR budget exhausted) OR `RETRY` (worker filed a blocker and is waiting for orchestrator answer). + +### §17.11 Adoption-tier placement + overrides + +This section is **Tier-A** (mandatory) per §16.1 for any sprint +that opens PRs. Two project overrides are possible (Tier-C): + +| Setting | Default | Override scenario | Override value | +|---|---|---|---| +| Per-worker PR creation (§17.2) | Each worker opens its own PR | Project prefers a single orchestrator-consolidation PR per wave (per `autoattended-orchestrator-spec.md` §3.4) | `pr_ownership: orchestrator-consolidation` in `INVARIANTS.md` | +| Subscription transport (§17.3) | `mcp__github__subscribe_pr_activity` native MCP | Environment without GitHub MCP (offline, rate-limited, non-GitHub host) | `pr_event_transport: polling` (60 s interval via `mcp__github__pull_request_read`) | + +Tier-D honest caveat: `subscribe_pr_activity` requires network + +GitHub API rate budget (5000 req/h authenticated). For 12-agent +fan-outs running long auto-resolve loops, monitor rate-limit +consumption; the orchestrator MAY consolidate subscriptions onto +itself (one subscription per PR with the orchestrator re-broadcasting +events to interested workers) to amortize the API budget. + +--- + +*End of `anti-skim-agent-spec.md`.* diff --git a/.claude/ATT/autoattended-orchestrator-spec.md b/.claude/ATT/autoattended-orchestrator-spec.md new file mode 100644 index 000000000..4f6b8fbf5 --- /dev/null +++ b/.claude/ATT/autoattended-orchestrator-spec.md @@ -0,0 +1,1231 @@ +# Autoattended Orchestrator Specification + +> **Status:** DRAFT · **Version:** 0.1.0 · **Last updated:** 2026-05-17 +> **Format:** NLSpec (per [strongdm/attractor](https://github.com/strongdm/attractor)) +> **Substrate:** Designed to compose on top of `attractor-spec.md`; runs +> as the `house`-shaped `manager_loop` node of an attractor pipeline. + +--- + +## §1 Overview + +### §1.1 Purpose + +The Autoattended Orchestrator runs wave-based, fan-out / fan-in sprints +of LLM worker agents against a codebase, with four specialized review +gates (the "4 savants") at fixed lifecycle positions. It is the +project-agnostic distillation of the pattern described in +[`AdaWorldAPI/WoA/.claude/v0.1/CLAUDE-CONTEXT.md`](https://github.com/AdaWorldAPI/WoA/blob/main/.claude/v0.1/CLAUDE-CONTEXT.md), +hardened across 26 repositories on 2026-05-17. + +### §1.2 Central abstractions + +- **Wave**: one parallel fan-out of N worker agents (typical N = 12), + ending in a single consolidation commit by the orchestrator. A + sprint is a sequence of waves. +- **Worker**: one LLM-agent process owning one **bundle** of files. + Workers run isolated (`isolation: "worktree"`), do not read other + workers' in-flight state, coordinate only through the orchestrator + and the file-blackboard. +- **Savant**: one of four specialized review roles (PP-13 / PP-14 / + PP-15 / PP-16) that gate the sprint at fixed lifecycle positions. +- **Iron Rule**: a non-overridable invariant declared in `INVARIANTS.md`, + enforced by every worker and by the meta-agent at PR review. + +### §1.3 Relation to `attractor-spec.md` + +The orchestrator is realizable as an attractor pipeline whose DOT +graph has the canonical shape: + +``` +start (Mdiamond) + → preflight-drift-auditor (box, PP-16 verdict gate) + → fan-out (component, N=12) + → fan-in (tripleoctagon, consolidate commit) + → baton-handoff-auditor (box, PP-15) + → brutally-honest-tester (box, PP-13, goal_gate=true, retry_target=fan-out) + → exit (Msquare) +``` + +PP-14 (convergence-architect) runs at PRE-PLAN, *outside* the graph, +on the proposed sprint plan before the graph is rendered. + +### §1.4 What this spec is NOT + +- Not a pipeline runner. It assumes attractor-spec.md (or an equivalent) + is the runtime. +- Not a coding-agent loop. Per-worker behavior is in + [`anti-skim-agent-spec.md`](./anti-skim-agent-spec.md). +- Not a coordination transport. The cross-agent message bus is in + [`agent-coordination-mcp-spec.md`](./agent-coordination-mcp-spec.md). + +--- + +## §2 Terminology + +| Term | Definition | +|---|---| +| **Sprint** | A sequence of one or more waves toward a single planned outcome (a feature, a port, a refactor). | +| **Wave** | One parallel fan-out + fan-in cycle. | +| **Bundle** | The set of files one worker owns (read-write); declared in `META/SPRINT-N-PLAN.md`. | +| **Ownership table** | The per-worker mapping of bundle → owned-files + read-only-files. | +| **Iron Rule** | A non-overridable invariant; violation is a P0 finding. | +| **Goal gate** | A node whose verdict must be SUCCESS for the wave to exit. Implements attractor §3.4. | +| **Savant** | PP-13 / PP-14 / PP-15 / PP-16. See §4. | +| **Meta-agent** | The 13th agent. Owns plan review, inbox drain, PR review. | +| **REQUESTS-FROM-AGENTS.md** | The append-only inbox for stuck-worker messages. | +| **INVARIANTS.md** | The single source of truth for cross-cutting rules. | + +--- + +## §3 The Wave Loop + +### §3.1 Six steps + +``` +1. Plan → orchestrator partitions work into N bundles +2. Sprint → N parallel worker agents +3. Meta review → one or more savant agents +4. Fix P0s → orchestrator applies fixes + verifies tier-1 gates +5. Commit + PR → orchestrator (one PR per bundle OR one combined PR) +6. Repeat → orchestrator plans the next wave +``` + +### §3.2 Single iron rule across all steps + +The orchestrator is the only role allowed to write outside its +assigned bundle. Workers stay in their lane. Savants are read-only +(they file findings; the orchestrator applies fixes). + +### §3.3 Wave sizing + +| Wave size | Worker model | Use when | +|---|---|---| +| 3-6 | mid-tier (e.g. Sonnet) | tight scope, well-defined bundles, low cross-cutting concern | +| 7-12 | mid-tier | the standard wave shape — most work fits here | +| > 12 | mid-tier, split | pre-fan into 2 waves with a savant pass between | +| 1-2 (planning) | top-tier (e.g. Opus) | architecture / design / cross-cutting decisions | +| 1 (savant) | mid-tier or top-tier | per §4 | + +A 12-worker wave costs approximately **250,000 to 350,000 input +tokens** (bundle briefings + reference reads) plus **30,000 to +50,000 for the savant pass**. Implementations MUST track this against +the model's context-window budget per worker and reject plans whose +per-bundle brief exceeds the configured `worker.max_brief_tokens`. + +### §3.4 The consolidation pass (step 5 ⇒ atomic commit) + +After all workers in a wave return, the orchestrator does ONE +consolidation commit that: + +1. Pulls in each bundle's commits in dependency order +2. Resolves the append-only merge zones (module registry, + integration test list, etc.) declared in INVARIANTS.md +3. Re-runs tier-1 gates against the combined state (see + [`anti-skim-agent-spec.md` §8](./anti-skim-agent-spec.md)) +4. Files one PR (or N PRs if bundles are truly independent) + +Implementations MUST NOT allow 12 mini-commits at the shared registry +file. Worker pushes to shared-registry files are rejected at the +worker layer (per the unique-file write rule, §5.1). + +--- + +## §4 The 4 Savant Slots + +### §4.0 Mindsets (not roles) + +Each savant is a **mindset** — a way of thinking, not a checklist +operator. The verdict vocabulary in §4.1 is the *output*; the +mindset in this section is the *input* the savant's system prompt +should activate. + +| Savant | Mindset persona | Frame they read through | Failure they exist to catch | +|---|---|---|---| +| **PP-13 brutally-honest-tester** | The implementation principal who has shipped + on-called for ten years | "what would break in production at 3 a.m. that the author talked themselves out of seeing?" | Self-deception in implementation-quality claims | +| **PP-14 convergence-architect** | The creative-design / R&D principal exploring divergent possibilities | "what could this become that we aren't seeing? what latent shared shape is being duplicated?" | Premature convergence and missed cross-slice synergies | +| **PP-15 baton-handoff-auditor** | The DTO / interface architect — the person who lives in the gaps between components | "do these contracts actually line up at the seams? whose hand goes on the baton next?" | Cross-boundary drift; silent contract-shape mismatches | +| **PP-16 preflight-drift-auditor** | The principal system architect with full system-state in their head | "does the plan still match the system as it actually is right now, or did main move while we were planning?" | Stale plans against a moving main; dropped requirements | + +The system prompt for each savant SHOULD begin with the mindset +sentence, not with the verdict checklist. The checklist is a +backstop; the mindset is the lens. + +### §4.1 Slot table + +| Savant | Phase | Owns | Verdict vocabulary | +|---|---|---|---| +| **PP-13 brutally-honest-tester** | POST-IMPL | within-bundle compile / lint / test / spec match | LAND / HOLD / REJECT | +| **PP-14 convergence-architect** | PRE-PLAN | divergent ideation, latent shared infrastructure | OPPORTUNITY-NOW / WORTH-EXPLORING / DROP (never REJECT) | +| **PP-15 baton-handoff-auditor** | DURING-IMPL | cross-bundle / cross-crate / cross-module boundary contracts | CATCH-CRITICAL / CATCH-LATENT / CLEAN | +| **PP-16 preflight-drift-auditor** | PRE-SPAWN | spec-vs-main drift, hand-waved scope, dropped requirements | SPAWN-CLEAR / SPAWN-CAUTION / SPAWN-BLOCKED | + +### §4.2 Verdict-vocabulary non-overlap is a design invariant + +Each savant has a **non-overlapping verdict vocabulary** so a finding +cannot cross phases without re-classification. The meta-agent uses +its own vocabulary (GO / GO-WITH-CONDITIONS / BLOCK for plan review; +P0 / P1 for PR review). + +If a savant returns a verdict from another savant's vocabulary, the +finding is rejected at intake and routed back. This is ERROR +severity in validation (§7). + +### §4.3 Non-use → route table + +Each savant's prompt MUST include explicit "non-use → route to PP-X" +lines. Examples: + +- PP-13 finds a cross-crate boundary issue → route to PP-15. +- PP-15 finds a spec-vs-main drift → route to PP-16. +- PP-16 finds a within-bundle compile error → route to PP-13. +- PP-14 finds anything compile-related → route to PP-13. + +### §4.4 PP-13 specifics + +Owns the canonical toolchain tier-1+2+3. Tier 1 runs every PR; tiers +2+3 opt-in. See [`anti-skim-agent-spec.md` §8](./anti-skim-agent-spec.md#8-toolchain-tiers) +for the language adapter tables. + +Anti-pattern catalog: AP1..AP8. + +### §4.5 PP-15 specifics + +Owns cross-boundary commands: workspace-level lint/typecheck, +public-API diff (`cargo public-api`, `api-extractor`, `griffe check`), +cross-symbol grep, cross-repo `git log`, metadata dump. + +Anti-pattern catalog: BAP1..BAP10. Eight boundary classes: +module-module, crate-crate, package-package, repo-repo, public-API, +DTO/wire-format, DB-schema-to-ORM, CLI-surface. + +### §4.6 PP-16 specifics + +Owns git + grep only — `git log master`, `git show`, +`git diff main...HEAD`, list-pull-requests, grep old symbols across +`.claude/plans/` and `.claude/specs/`. Does NOT run compile/test/lint. + +Anti-pattern catalog: PD1..PD10. Six axes: Plan-vs-Main-HEAD, +Plan-vs-Open-PRs, Plan-vs-Recent-Merges, Plan-vs-RFC-Status, +Plan-vs-Invariants, Plan-vs-Spec. + +### §4.7 PP-14 specifics + +Owns surface-inspection only (e.g. `cargo doc`, `cargo tree`, +`cargo expand`) plus WebSearch / paper-search for cross-pollination. +Has NO compile/test gates. Anti-pattern catalog: EP1..EP8. + +--- + +## §5 Worker Iron Rules + +### §5.1 Unique-file write discipline + +Each worker writes to a **unique new file** in its bundle. Never two +workers at the same existing file simultaneously. Append-conflicts +are guaranteed if violated. + +Shared merge-zones (module registry, integration test list) MUST be +declared explicitly in INVARIANTS.md as **append-only**: each worker +appends one line; the orchestrator resolves order in the +consolidation commit. Worker pushes to undeclared shared files are +ERROR severity (§7). + +### §5.2 Worktree branches start from `origin/`, not the local working branch + +A worktree branch started from a stale local working-branch will +silently miss sibling workers' commits. Workers MUST: + +```bash +git fetch origin +git checkout -b agent/N +``` + +Implementations MUST set `isolation: "worktree"` for every worker +spawn. + +### §5.3 Atomic consolidation pass + +See §3.4. The orchestrator does ONE consolidation commit per wave, +not N mini-commits. + +### §5.4 Pre-wave helper-call audit + +Before fanning out, the orchestrator scans each bundle for +uncommitted helper-call dependencies. Bundles with non-zero +unresolved-helper count require a **helper-hoist** committed before +the fan-out. Otherwise N workers each invent the same helper N +different ways. This is PP-14's job at PRE-PLAN. + +### §5.5 Chunking discipline (the load-bearing iron rule) + +Files larger than ~150 lines MUST be written via `tee -a` in chunks, +with one commit per chunk. NEVER one 500-line heredoc + commit + +push in the same turn. Connection drops mid-serialize lose work. + +The `tee -a` loop has double duty: chunking (file size) AND agent +logging (status line appended to `AGENT_LOG.md` after each chunk). + +### §5.6 Source-quoting commit messages + +For ports and behavior-preserving rewrites: every commit message +quotes the source file + line range for the function being ported. +Reviewers can `grep -rn "Source: " /` to find every +port site. Without this, behavior-drift creeps in invisibly. + +--- + +## §6 Sprint Plan Format + +### §6.1 The plan is a DOT graph (or YAML mirror) + +A sprint plan is a DOT graph (per attractor-spec.md §2) or its +equivalent YAML. The canonical wave shape is in §1.3. + +### §6.2 Required node attributes per bundle + +Every `box`-shaped worker node MUST declare: + +``` +[ + agent_id="A4", + bundle_name="customer-master-data", + owned_files="src/customer/master.rs,src/customer/master/types.rs", + read_only_files="../WoA/woa/blueprints/customer.py,../WoA/models.py", + spec_files="vendor/ogit/NTO/WorkOrder/entities/customer.ttl", + sentinel_token="WAVE-12-A4-7f3c", + proof_of_read=true, + worker_model="sonnet", + isolation="worktree", + status_file=".claude/board/wave-12/A4-status.json" +] +``` + +### §6.3 Required edge attributes + +| Attribute | Values | Default | +|---|---|---| +| `condition` | expression over `outcome` and `context.*` | `outcome==SUCCESS` | +| `fidelity` | `full` / `compact` / `summary:medium` / `truncate` | `compact` | +| `route_on_fail` | node id | `null` | + +### §6.4 YAML mirror (when DOT is unavailable) + +```yaml +sprint: + id: SPRINT-12-customer-master + wave_size: 12 + base_branch: origin/main + workers: + - agent_id: A4 + bundle_name: customer-master-data + owned_files: [src/customer/master.rs, src/customer/master/types.rs] + read_only_files: [../WoA/woa/blueprints/customer.py, ../WoA/models.py] + spec_files: [vendor/ogit/NTO/WorkOrder/entities/customer.ttl] + sentinel_token: WAVE-12-A4-7f3c + proof_of_read: true + worker_model: sonnet + isolation: worktree + status_file: .claude/board/wave-12/A4-status.json + savants: + pre_plan: PP-14 + pre_spawn: PP-16 + during_impl: PP-15 + post_impl: PP-13 + goal_gate: PP-13 + retry_target: fan-out +``` + +--- + +## §7 Validation Rules + +Implementations MUST run these lints against every sprint plan +before fan-out. Severity matches attractor-spec.md §7's convention. + +| Rule | Description | Severity | +|---|---|---| +| `WAVE-001 unique-write` | No two bundles list the same file under `owned_files`. | ERROR | +| `WAVE-002 declared-shared` | Any file appearing in two bundles' `owned_files` MUST be declared `append-only` in INVARIANTS.md, otherwise ERROR. | ERROR | +| `WAVE-003 sentinel-token-present` | Every worker node MUST have a unique `sentinel_token`. | ERROR | +| `WAVE-004 proof-of-read-required` | `proof_of_read=true` is mandatory; `false` requires explicit human override in the commit body. | ERROR | +| `WAVE-005 goal-gate-has-retry` | If a node has `goal_gate=true`, it MUST also have a `retry_target`. (Adopted from attractor §7.2.) | ERROR | +| `WAVE-006 isolation-worktree` | Every worker node MUST declare `isolation="worktree"`. | ERROR | +| `WAVE-007 status-file-path` | Every worker node MUST declare a `status_file` path unique to this wave. | ERROR | +| `WAVE-008 worker-brief-size` | The rendered brief for any worker MUST NOT exceed `worker.max_brief_tokens` (default 8000). | WARNING | +| `WAVE-009 helper-hoist` | Pre-wave helper-call audit (§5.4) MUST surface zero unresolved-helpers. | WARNING | +| `WAVE-010 verdict-vocabulary` | Each savant verdict MUST be from its own vocabulary (§4.2). Cross-vocabulary verdicts are routed back. | ERROR | +| `WAVE-011 auto-status-false` | `auto_status` MUST be `false`. Missing status MUST be treated as FAIL. (Conflicts with attractor's default.) | ERROR | +| `WAVE-012 reachability` | Every node reachable from `start`. (Adopted from attractor §7.2.) | ERROR | +| `WAVE-013 start-exit` | Exactly one `start`, at least one `exit`. (Adopted from attractor §7.2.) | ERROR | +| `WAVE-014 inbox-drained` | At wave start, REQUESTS-FROM-AGENTS.md MUST have no unanswered entries from prior waves. | WARNING | +| `WAVE-015 invariants-fresh` | Every worker brief MUST include the SHA-256 of INVARIANTS.md and the worker MUST proof-of-read it. | ERROR | + +--- + +## §8 Configuration + +```yaml +# .claude/ATT/config/orchestrator.yaml +orchestrator: + wave_size: + default: 12 + min: 1 + max: 24 + worker: + max_brief_tokens: 8000 + isolation: worktree # MUST be worktree + proof_of_read: required # required | optional (default required) + auto_status: false # MUST be false + consolidation: + one_pr_per_bundle: false # true | false (false = one combined PR) + re_run_tier_1: true # MUST be true + savants: + pre_plan: PP-14 + pre_spawn: PP-16 + during_impl: PP-15 + post_impl: PP-13 + goal_gate_owner: PP-13 + retry: + max_replans_per_sprint: 3 + on_partial_failure: redispatch_with_tighter_scope + budget: + wave_max_input_tokens: 350000 + savant_max_input_tokens: 50000 + warn_if_exceeds: 0.8 # warn at 80 % of budget +``` + +--- + +## §9 Status File Schema + +### §9.1 Adopt attractor's status.json with `auto_status=false` + +Every worker MUST write a `status.json` to its declared `status_file` +path. Schema cribbed from attractor Appendix C and tightened: + +```json +{ + "agent_id": "A4", + "bundle_name": "customer-master-data", + "sentinel_token": "WAVE-12-A4-7f3c", + "outcome": "SUCCESS", + "preferred_label": "land", + "suggested_next_ids": [], + "context_updates": { + "customer.master.files_created": 3, + "customer.master.parity_tests_passed": 7 + }, + "notes": "two helper functions hoisted into src/customer/_shared.rs (already declared append-only in INVARIANTS.md §AppendOnly)", + "proof_of_read": [ + { "file": "INVARIANTS.md", "sha256": "...", "lines": 412, "depth": "thorough" }, + { "file": "../WoA/woa/blueprints/customer.py", "sha256": "...", "lines": 891, "depth": "full" }, + { "file": "vendor/ogit/NTO/WorkOrder/entities/customer.ttl", "sha256": "...", "lines": 137, "depth": "full" } + ], + "tier_1_gates": { + "lint": "GREEN", + "fmt": "GREEN", + "audit": "GREEN", + "deny": "GREEN", + "typecheck": "GREEN", + "tests": { "passed": 14, "failed": 0 } + } +} +``` + +### §9.2 The five outcomes + +| Outcome | Meaning | +|---|---| +| `SUCCESS` | All Tier-1 gates green; spec contract satisfied; ready for PR. | +| `PARTIAL_SUCCESS` | Bundle work shipped but a defined sub-task deferred (filed to `Altlasten.md` / `TECH_DEBT.md`). | +| `RETRY` | Self-detected stuck-loop (per `anti-skim-agent-spec.md` §6) or token-budget exhaustion. Orchestrator re-spawns with tighter scope. | +| `FAIL` | Tier-1 gates red, OR proof-of-read missing, OR sentinel-token failed, OR Iron Rule violated. | +| `SKIPPED` | The bundle's preconditions (e.g. a dependency bundle) were not met. | + +### §9.3 Missing-status policy + +`auto_status=false` is mandatory. If a worker exits without writing +`status_file`, the orchestrator MUST treat the wave as FAIL for that +bundle. + +This is where we deliberately conflict with attractor's +`auto_status=true` default. See [`README.md` "Where it conflicts"](./README.md#where-it-conflicts-with-attractors-posture-and-why-we-keep-our-position). + +--- + +## §10 Definition of Done (conformance checklist) + +An implementation is conformant if it satisfies ALL of: + +- [ ] Sprint plans are DOT graphs or §6.4-YAML mirrors with all + required node attributes (§6.2) and edge attributes (§6.3). +- [ ] Validation rules §7 WAVE-001 through WAVE-015 run as part of + `preflight-drift-auditor` and block fan-out on ERROR. +- [ ] Every worker spawns with `isolation: "worktree"` (§5.2). +- [ ] Every worker writes a `status.json` matching the §9.1 schema. +- [ ] Missing `status.json` is treated as FAIL (`auto_status=false`). +- [ ] The four savants are present with non-overlapping verdict + vocabularies (§4.2) and explicit non-use route-tables (§4.3). +- [ ] PP-13 owns the language-specific Tier-1 toolchain + (`anti-skim-agent-spec.md` §8). +- [ ] PP-15 owns BAP1..BAP10 + 8 boundary classes (§4.5). +- [ ] PP-16 owns PD1..PD10 + 6 axes (§4.6) plus the §7 validation rules. +- [ ] Worker briefs declare `proof_of_read: true` and a unique + `sentinel_token` (§6.2). +- [ ] The meta-agent (the 13th role) drains REQUESTS-FROM-AGENTS.md + ≥ 2× per day during a wave (4-hour reply latency target). +- [ ] PR review classifies findings ONLY as P0 or P1; never P2/P3. +- [ ] `INVARIANTS.md` is ≤ 500 lines; split required above. +- [ ] One consolidation commit per wave at the shared registry + (§3.4); zero N-mini-commit anti-pattern detected. +- [ ] Chunking discipline enforced: files > 150 lines written via + `tee -a` (§5.5). +- [ ] Context Fidelity ladder (§11A) is implemented with precedence + edge > node > graph > default and the §11A.2 token budgets + treated as guidance (hard cap is `worker.max_brief_tokens`). +- [ ] `fidelity=truncate` does NOT exempt a worker from the + `anti-skim-agent-spec.md` §3.3 reading-depth ladder. + +--- + +## §11 Cross-Language Parity Matrix + +| Aspect | Rust | Python | TypeScript | Go | +|---|---|---|---|---| +| Tier-1 lint | `cargo clippy --all-targets --all-features -- -D warnings` | `ruff check` | `eslint --max-warnings 0` | `golangci-lint run` | +| Tier-1 format check | `cargo fmt --check` | `ruff format --check` | `prettier --check` | `gofmt -l` | +| Tier-1 advisory scan | `cargo audit` | `pip-audit` | `npm audit --omit=dev` | `govulncheck ./...` | +| Tier-1 dep policy | `cargo deny check` | `deptry .` | (project-defined) | `go vet -all` | +| Tier-1 typecheck | (clippy implies) | `mypy --strict` | `tsc --noEmit --strict` | (compiler implies) | +| Tier-1 tests | `cargo test --all-features` | `pytest` | `vitest run` | `go test ./...` | +| Module registry append-only file | `src/lib.rs` / `mod.rs` | `__init__.py` | `index.ts` / `index.js` | `pkg.go` | +| Workspace metadata | `cargo metadata` | `pipdeptree` | `pnpm list --depth=2` | `go list -m all` | +| Public-API diff | `cargo public-api` | `griffe check` | `api-extractor run` | `apidiff` | + +--- + +## §11A Context Fidelity + +> **Adopted from `attractor-spec.md` §5.4.** This is the one pickup +> that requires its own section because it changes how briefs are +> rendered to workers. + +### §11A.1 Why fidelity matters + +A 12-worker wave runs the orchestrator's brief through each worker. +If every worker inherits the full orchestrator context, a wave's +input-token cost scales linearly with workers × shared-context-size, +which is wasteful when bundles are small and well-scoped. + +Fidelity modes let the orchestrator dial how much of its context +each worker inherits, per-edge / per-node / per-graph. + +### §11A.2 Four modes + token budgets + +| Mode | Token budget (approx.) | When to use | +|---|---|---| +| `full` | unbounded (worker inherits the entire orchestrator thread) | trusted same-domain handoff; rare; default OFF | +| `compact` | ~3000 tokens (bundle ownership table + INVARIANTS sha + parity contract only) | **default** for standard workers | +| `summary:medium` | ~1500 tokens (auto-generated summary of orchestrator context, ~15-line max) | budget-conscious waves; > 12 workers | +| `summary:low` | ~600 tokens (one-paragraph summary) | trivial workers (e.g. doc-touch only) | +| `truncate` | ~200 tokens (goal + bundle name + sentinel only) | smoke-test workers; never for code-writing | + +These budgets are guidance, not hard caps; the hard cap is +`worker.max_brief_tokens` (default 8000, configurable per §8). + +### §11A.3 Precedence ladder + +Per attractor §5.4, fidelity is resolved with edge > node > graph > +default: + +``` +worker.fidelity = + edge_attribute(orchestrator → worker, "fidelity") # if set + || node_attribute(worker, "fidelity") # else + || graph_attribute(sprint_graph, "default_fidelity") # else + || "compact" # built-in default +``` + +### §11A.4 Interaction with proof-of-read + +Fidelity controls what the **orchestrator** passes to the worker. It +does NOT control what the **worker** reads from disk. A worker on +`fidelity=truncate` MUST still execute the §3.3 of +[`anti-skim-agent-spec.md`](./anti-skim-agent-spec.md) reading-depth +ladder on every file it touches. + +In particular: + +- A worker on `fidelity=truncate` whose brief includes only "goal + + bundle name + sentinel" MUST still read INVARIANTS.md `thorough` + before any commit (per anti-skim-agent-spec.md §3.3). +- A worker on `fidelity=full` does NOT skip proof-of-read on files + that were summarized in the inherited context — the inherited + summary is NOT a substitute for the read (the same rule that makes + a compaction summary not a substitute for the JOURNAL file). + +### §11A.5 Validation rule + +| Rule | Description | Severity | +|---|---|---| +| `WAVE-016 fidelity-budget` | If a worker node declares `fidelity=truncate` AND `tier_1_gates` are required, the orchestrator MUST verify the worker's brief still includes the §6.2 required attributes. | ERROR | +| `WAVE-017 fidelity-precedence` | The §11.3 precedence is observed; conflicting declarations resolve in the order edge > node > graph > default. | WARNING | + +### §11A.6 Worked example + +A wave-12 sprint with mixed bundle sizes: + +```yaml +sprint: + default_fidelity: compact + workers: + - agent_id: A1 # large bundle, cross-cutting + fidelity: full # node override + - agent_id: A2 # standard bundle + # uses default 'compact' + - agent_id: A3 # tiny bundle, only touches docs + fidelity: summary:low # node override + - agent_id: A4 # smoke-test only + fidelity: truncate + edges: + - from: A1 + to: fan_in + fidelity: full # edge override — A1's result fed to fan-in at full fidelity +``` + +--- + +## §12 Appendix A — Canonical wave DOT graph + +```dot +digraph wave_12_customer_master { + rankdir=LR; + start [shape=Mdiamond, label="start"]; + exit [shape=Msquare, label="exit"]; + + // PRE-SPAWN + pp16 [shape=box, + label="PP-16 preflight-drift-auditor", + owner="meta-agent", + verdicts="SPAWN-CLEAR / SPAWN-CAUTION / SPAWN-BLOCKED", + validation_rules="WAVE-001..WAVE-015"]; + + // DURING-IMPL fan-out + fan_out [shape=component, label="fan-out N=12", max_parallel=12]; + + // 12 workers (only A1..A3 shown for brevity) + a1 [shape=box, agent_id="A1", bundle_name="customer-list", + isolation="worktree", proof_of_read=true, + sentinel_token="WAVE-12-A1-2a91", + status_file=".claude/board/wave-12/A1-status.json"]; + a2 [shape=box, agent_id="A2", bundle_name="customer-detail", + isolation="worktree", proof_of_read=true, + sentinel_token="WAVE-12-A2-6b04", + status_file=".claude/board/wave-12/A2-status.json"]; + a3 [shape=box, agent_id="A3", bundle_name="customer-master", + isolation="worktree", proof_of_read=true, + sentinel_token="WAVE-12-A3-d177", + status_file=".claude/board/wave-12/A3-status.json"]; + // ... A4..A12 ... + + fan_in [shape=tripleoctagon, label="consolidate + re-run tier-1"]; + + pp15 [shape=box, label="PP-15 baton-handoff-auditor", + verdicts="CATCH-CRITICAL / CATCH-LATENT / CLEAN"]; + + pp13 [shape=box, label="PP-13 brutally-honest-tester", + verdicts="LAND / HOLD / REJECT", + goal_gate=true, + retry_target=fan_out]; + + start -> pp16 [label="plan handed off"]; + pp16 -> fan_out [label="outcome==SPAWN-CLEAR"]; + pp16 -> exit [label="outcome==SPAWN-BLOCKED", + condition="route_on_fail"]; + fan_out -> a1; + fan_out -> a2; + fan_out -> a3; + // ... -> a4..a12 + a1 -> fan_in; + a2 -> fan_in; + a3 -> fan_in; + fan_in -> pp15 [label="all status.json present, all proof_of_read verified"]; + pp15 -> pp13 [label="outcome==CLEAN || outcome==CATCH-LATENT"]; + pp15 -> fan_out [label="outcome==CATCH-CRITICAL", condition="route_on_fail"]; + pp13 -> exit [label="outcome==LAND"]; + pp13 -> fan_out [label="outcome==HOLD || outcome==REJECT", + condition="route_on_fail"]; +} +``` + +--- + +## §13 Appendix B — Stuck-Protocol typed blockers + +When a worker cannot proceed it writes ONE entry to +`META/REQUESTS-FROM-AGENTS.md` and idles. Blocker types: + +| Type | Meaning | Meta-agent action | +|---|---|---| +| `AMBIGUITY` | Spec is mehrdeutig; more than one sensible interpretation. | Write answer in `ANSWERS-TO-AGENTS.md`; propagate to INVARIANTS if structural. | +| `MISSING_INVARIANT` | Iron Rule doesn't cover this case; convention missing. | Add invariant to INVARIANTS.md; audit other workers for the same gap. | +| `SPEC_SOURCE_MISMATCH` | Spec says X, reference source does Y. | Write RFC under `rfcs/`; get human sign-off; then tell worker to proceed. | +| `BEHAVIOUR_QUESTION` | Possible bug in reference source. | If meta can read source and answer definitively, do so; else page human. | +| `EXTERNAL_DEPENDENCY` | Third-party system zickt; workaround unclear. | Check `wissen/` / `knowledge/`; if none, RFC + add note. | + +`OUT-OF-SCOPE` requests (worker wants to refactor outside bundle, add +new feature) are rejected: meta writes `REJECTED: ` and +closes. + +--- + +## §14 Two-Protocol Operating Modes + +> Added 2026-05-18 — design work and implementation work have +> different gates and benefit from different topologies. + +### §14.1 Two protocols, one loop family + +| Protocol | Phase | Artifact produced | Goal-gate criterion | +|---|---|---|---| +| **Protocol B** | Design | Specs, RFCs, plans, INVARIANT amendments, agent cards | Doc-coherence + scope-completeness across N docs jointly | +| **Protocol A** | Implementation | Code, parity tests, ledger rows, PRs | Tier-1 toolchain green + spec contract satisfied | + +Both protocols use the same 4-savant council (PP-13/14/15/16) and +the same meta-agent. They differ in (1) what counts as a goal-gate +pass, (2) the topology of the savant pass (sequential vs cooperative +council per §15), and (3) the artifact the preflight produces. + +### §14.2 Protocol B — Design loop + +``` +1. Draft → human or LLM authors N documents on a design branch +2. Joint review → savants COOPERATE on the N docs as a coherent set (§15) +3. Correct → orchestrator applies cross-doc fixes from the joint review +4. Re-review → goto step 2 until CONVERGE (§15.5) or human override +5. Land → docs merge to main; Protocol A may begin +``` + +Goal-gate criteria (Protocol B): + +| Check | Owner | Pass condition | +|---|---|---| +| Doc-coherence | PP-15 baton-handoff-auditor | No cross-doc schema/term drift (e.g. `status.json` in spec A matches consumer in spec B) | +| Scope-completeness | PP-16 preflight-drift-auditor | Every requirement in the source brief is addressed in at least one doc | +| Convergence opportunity | PP-14 convergence-architect | No latent shared concept duplicated across docs without a shared section | +| Conformance checklist | PP-13 brutally-honest-tester | Every doc has a Definition-of-Done section with checkable items | + +PP-13 in Protocol B does NOT run the language toolchain (no code to +compile). It validates that the docs ARE the kind of thing a PP-13 +can later compile/test against. + +### §14.3 Protocol A — Implementation loop + +The 6-step wave loop of §3.1 with one addition: **preflight produces +a commented-out, compile-error-only Rust skeleton** (§14.4) before +worker fan-out. Workers fill bodies into the skeleton instead of +writing into empty files. + +``` +1. Plan → orchestrator partitions work into N bundles +2. Preflight → PP-16 produces SKELETON (§14.4) + verdict +2a. Council → savants COOPERATE on SKELETON (§15) — fast, cheap +3. Sprint → N parallel worker agents fill bodies into skeleton +4. Council → savants COOPERATE on FILLED code (or sequential per §15.6 for big diffs) +5. Fix P0s → orchestrator applies fixes + verifies tier-1 gates +6. Commit+PR → orchestrator (atomic consolidation per §3.4) +7. Repeat → orchestrator plans the next wave +``` + +### §14.4 The commented-out Rust skeleton (Protocol A preflight artifact) + +PP-16 in Protocol A produces both (a) its verdict (SPAWN-CLEAR / +CAUTION / BLOCKED per §4.6) AND (b) a runnable-but-stubbed Rust +skeleton at the path declared in `skeleton_output_path` (a new node +attribute on each worker, see §14.6). + +#### §14.4.1 Canonical Rust skeleton format + +| Element | Skeleton form | +|---|---| +| Function body | `todo!("SOURCE: :-")` | +| Trait impl | declare the impl block with every method body as `todo!("SOURCE: ...")` | +| Struct | declare all fields; `Default::default()` impl as `todo!("SOURCE: ...")` if construction is non-trivial | +| Enum | declare variants; no body needed | +| Module | `pub mod x;` with stub `mod.rs` containing `// SKELETON: — SOURCE: ` | +| `unsafe` block | `unsafe { todo!("UNSAFE-SOURCE: : — // SAFETY: ") }` — SAFETY rationale required because PP-13 will demand it later | +| Async function | same as function; body `todo!("SOURCE: ...")` | +| Macro | declare with empty body `() => { todo!("SOURCE: ...") }` | + +#### §14.4.2 Token choice: `todo!` over `unimplemented!` + +- `todo!("SOURCE: ...")` — preferred. Signals intent "this is to be + done", panics with source-location at runtime if hit, compiler + accepts it as any type. +- `unimplemented!()` — reserved for "correct API surface but never + implemented in this crate" (rare; not a skeleton placeholder). +- `unreachable!()` — reserved for "statically impossible branch"; + not a skeleton primitive. + +#### §14.4.3 Skeleton compile invariant + +The skeleton MUST compile with `cargo check --workspace` green. It +MUST NOT pass `cargo test` or `cargo run` (the `todo!()` panics). +This is the diagnostic signature of a well-formed skeleton. + +| Rule | Description | Severity | +|---|---|---| +| `WAVE-018 skeleton-compiles` | `cargo check --workspace` MUST be green on the skeleton emitted by PP-16. | ERROR | +| `WAVE-019 skeleton-source-annotated` | Every `todo!()` MUST carry a `"SOURCE: :"` or `"UNSAFE-SOURCE: ..."` argument. | ERROR | +| `WAVE-020 skeleton-no-runtime` | The skeleton MUST NOT pass `cargo test` or `cargo run` — a green test on a skeleton means the test is a tautology. | ERROR | + +#### §14.4.4 Per-language equivalents (for non-Rust repos) + +| Language | Skeleton form | +|---|---| +| Rust | `todo!("SOURCE: ...")` (canonical) | +| Python | `raise NotImplementedError("SOURCE: :")` with docstring stub | +| TypeScript | `throw new Error("TODO — SOURCE: :")` | +| Go | `panic("TODO — SOURCE: :")` | + +Rust is canonical because the language's `todo!()` macro is +purpose-built for this exact use case. + +### §14.5 Protocol A vs Protocol B at the savant layer + +| Savant | Protocol B (design) | Protocol A (implementation) | +|---|---|---| +| PP-13 | Verifies docs have DoD sections; no compile gate. | Tier-1 toolchain + AP1..AP9 on filled code (§4.4). | +| PP-14 | Surfaces convergence opportunities across docs. | Surfaces convergence opportunities across slices (helper-hoist). | +| PP-15 | Cross-doc schema/term drift. | Cross-bundle DTO drift on filled code (BAP1..BAP10, §4.5). | +| PP-16 | Validates plan-vs-source brief: every requirement landed in some doc. | Validates plan-vs-main (PD1..PD10, §4.6) + EMITS SKELETON (§14.4). | + +### §14.6 Mode switch is explicit + +The orchestrator declares which protocol is active in the sprint +header: + +```yaml +sprint: + id: SPRINT-17-attractor-fold-in + protocol: B + default_fidelity: full + inputs: + docs: + - .claude/ATT/autoattended-orchestrator-spec.md + - .claude/ATT/anti-skim-agent-spec.md + - .claude/ATT/agent-coordination-mcp-spec.md + goal_gate: savant_council_converge +``` + +```yaml +sprint: + id: SPRINT-18-attractor-implementation + protocol: A + default_fidelity: compact + preflight: + skeleton_output_root: src/attractor/ + skeleton_compiles_check: cargo check --workspace + workers: + - agent_id: A1 + bundle_name: orchestrator-runner + skeleton_output_path: src/attractor/orchestrator/mod.rs + ... +``` + +| Rule | Description | Severity | +|---|---|---| +| `WAVE-021 protocol-declared` | Every sprint header MUST declare `protocol: A` or `protocol: B`. | ERROR | +| `WAVE-022 protocol-coherence` | Protocol-B sprints MUST NOT declare `workers[].owned_files` of file extensions other than `.md` / `.yaml` / `.dot`. Protocol-A sprints MUST declare `preflight.skeleton_output_root`. | ERROR | + +--- + +## §15 Cooperative Savant Council + +> The 4 savants **cooperate** — they do not run as independent +> fan-out branches whose verdicts get bag-of-words-aggregated. They +> read a shared scratchpad, file findings, cross-refer to each other, +> iterate, and emerge with a SINGLE joint verdict. + +### §15.1 Why cooperative, not independent-parallel + +Independent-parallel review (4 savants → 4 verdicts → super-verdict +aggregation) has two failure modes: + +1. **Lockstep drift.** All 4 savants miss the same cross-cutting + issue because they each looked at the artifact through their own + axis without seeing the others' angle. +2. **Duplicate findings.** Each savant independently flags the same + issue from a different angle; the orchestrator wastes a round + deduplicating. + +Cooperation fixes both: savants see each other's findings as they +land and either (a) cross-refer ("PP-15 already flagged this; my +angle is …") or (b) suppress duplicates ("PP-13 already covered +this from a stronger angle — withdrawn"). + +### §15.2 The shared scratchpad + +``` +.claude/board/savant-council-/ +├── ROUND-0-ARTIFACT.md (snapshot of what's under review) +├── ROUND-1-PP-13.md (PP-13's round-1 findings) +├── ROUND-1-PP-14.md (PP-14's round-1 findings) +├── ROUND-1-PP-15.md (PP-15's round-1 findings) +├── ROUND-1-PP-16.md (PP-16's round-1 findings) +├── ROUND-2-PP-13.md (PP-13's round-2 — sees all of round 1) +├── ... +└── COUNCIL-VERDICT.md (final joint document) +``` + +Append-only per §7.1 of `agent-coordination-mcp-spec.md`. Each +savant writes its file at the end of its round; reads ALL other +files at the start of its next round. + +### §15.3 The cooperation loop + +``` +Round R+1 (per savant): + 1. Read every ROUND-R-*.md (the others' findings from the previous round) + 2. Read ROUND-R-.md (your own findings from the previous round) + 3. For each finding by another savant: + a. Cross-refer if it intersects your axis ("noted — my AP3 finding + relates: ") + b. Withdraw any of your own findings that the other savant covered + from a stronger angle + c. Suppress duplicates with `STATUS: superseded-by(PP-X round-R)` + 4. Append your new findings (axis-tagged) to ROUND-(R+1)-.md + 5. Mark with `ROUND-COMPLETE` sentinel when you have no new findings +``` + +A round ends when ALL 4 savants have either (a) added new findings +in this round OR (b) emitted `ROUND-COMPLETE` (no new findings + no +unaddressed cross-refers from peers). + +### §15.4 Convergence + termination + +| Condition | Outcome | +|---|---| +| All 4 savants emit `ROUND-COMPLETE` in the same round | **CONVERGE** — proceed to §15.5 verdict synthesis | +| Round-count exceeds `max_rounds` (default 3) | **STALL** — orchestrator or human arbitrates | +| Any savant emits an unrecoverable BLOCK in any round (e.g. PP-16=SPAWN-BLOCKED with no clear remediation) | **BLOCK** — abort the council; return to step 1 of the protocol | + +### §15.5 The joint verdict (`COUNCIL-VERDICT.md`) + +After CONVERGE, the meta-agent (or a designated chairman savant — +default PP-16 in Protocol A, PP-15 in Protocol B) reads ALL +ROUND-*.md files and synthesizes a single `COUNCIL-VERDICT.md`: + +```yaml +council_verdict: + topic: + protocol: A | B + rounds_run: N + super_verdict: CONVERGE | SPLIT | BLOCK + + per_savant_final: + PP-13: + verdict: LAND | HOLD | REJECT + findings_kept: N + findings_withdrawn: M + PP-14: { ... } + PP-15: { ... } + PP-16: { ... } + + consolidated_p0_findings: + - finding_id: F1 + raised_by: PP-13 (round 1) + cross_referred_by: [PP-15 round 1, PP-16 round 2] + summary: + remediation: + + consolidated_p1_findings: [ ... ] + + next_action: proceed | arbitrate | retry_preflight | block +``` + +The super-verdict is derived from the per-savant finals: + +| Super-verdict | Trigger | +|---|---| +| **CONVERGE** | All 4 savants pass (PP-13=LAND ∧ PP-14∈{OPPORTUNITY-NOW,WORTH-EXPLORING,DROP} ∧ PP-15=CLEAN ∧ PP-16=SPAWN-CLEAR), AND no P0 findings remain after deduplication. | +| **SPLIT** | Mixed verdicts that are neither all-pass nor block-on-any. Orchestrator or human arbitrates. | +| **BLOCK** | Any of: PP-13=REJECT ∨ PP-15=CATCH-CRITICAL ∨ PP-16=SPAWN-BLOCKED ∨ remaining P0 findings ≥ 1. | + +### §15.6 Council DOT topology + +```dot +digraph savant_council { + rankdir=LR; + start [shape=Mdiamond]; + artifact [shape=note, label="docs (B) OR skeleton (A) OR filled-code (A)"]; + + round_R [shape=component, + label="round R: 4 savants read shared scratchpad, + append findings, cross-refer, withdraw duplicates"]; + + pp13 [shape=box]; pp14 [shape=box]; pp15 [shape=box]; pp16 [shape=box]; + + round_check [shape=diamond, + label="all 4 savants ROUND-COMPLETE?"]; + bump_round [shape=parallelogram, label="R := R+1"]; + + chairman [shape=box, label="chairman savant synthesizes COUNCIL-VERDICT.md"]; + verdict [shape=tripleoctagon, label="super-verdict: CONVERGE / SPLIT / BLOCK"]; + exit [shape=Msquare]; + + start -> artifact; + artifact -> round_R; + round_R -> pp13; + round_R -> pp14; + round_R -> pp15; + round_R -> pp16; + pp13 -> round_check; + pp14 -> round_check; + pp15 -> round_check; + pp16 -> round_check; + round_check -> bump_round [label="no: a savant has new findings"]; + bump_round -> round_R; + round_check -> chairman [label="yes: CONVERGE / STALL / BLOCK"]; + chairman -> verdict; + verdict -> exit; +} +``` + +### §15.7 When to fall back to sequential (no council) + +Three rules of thumb: + +1. **Filled-code review with diff > 500 lines:** sequential PP-13 → + PP-15 → PP-16 (per §4 chain). Each savant sees a smaller diff + after the orchestrator applies the previous savant's P0 fixes. +2. **Token-budget constrained run:** sequential. Council pays for + `4 × rounds × artifact-size` reads; sequential pays for + `1 × artifact + 3 × diff-only` reads. +3. **First time using a new spec set:** sequential. Let one savant + shake out the obvious issues before the others read it. + +Otherwise: council by default. + +### §15.8 Configuration + +```yaml +council: + max_rounds: 3 + chairman: + protocol_A: PP-16 + protocol_B: PP-15 + scratchpad_root: .claude/board/savant-council + cooperation_protocol: cross-refer-and-withdraw # see §15.3 + duplicate_suppression: superseded-by-stronger-angle +``` + +### §15.9 Validation rules + +| Rule | Description | Severity | +|---|---|---| +| `WAVE-023 council-legality` | Council mode is declared only when artifact is one of {docs, skeleton, small-diff filled-code}. | ERROR | +| `WAVE-024 council-rounds-bounded` | `max_rounds` MUST be set; default 3; hard cap 7. | ERROR | +| `WAVE-025 scratchpad-append-only` | The `.claude/board/savant-council-/` directory MUST be append-only per `agent-coordination-mcp-spec.md` §7.1. | ERROR | +| `WAVE-026 cross-refer-recorded` | When a savant withdraws or supersedes a peer's finding, the action MUST be recorded with `STATUS: superseded-by(PP-X round-R)` for traceability. | ERROR | +| `WAVE-027 chairman-declared` | The `chairman` savant for the synthesis pass MUST be declared in the sprint config; default per §15.8. | ERROR | +| `WAVE-028 stall-arbitration` | A STALL outcome (max_rounds reached without CONVERGE) MUST be followed by an arbitration step (orchestrator or human). | ERROR | +| `WAVE-029 split-arbitration` | A SPLIT super-verdict MUST be followed by an arbitration step before fan-out resumes. | ERROR | + +### §15.10 Example: this very kit + +A worked example. To fold the §14 / §15 additions into the three +`.claude/ATT/*.md` specs, a Protocol B council would: + +``` +Round 1: + PP-13: "spec A §11 'Context Fidelity' lacks a DoD subsection" + PP-14: "spec A §15 'cooperative council' duplicates spec C §3.1 'three-layer model' + — opportunity for shared concept" + PP-15: "spec A §14.4 'skeleton' references todo!() macro; + spec B §6 'tool-call loop detection' does not — no contradiction, just an axis" + PP-16: "scope-completeness pass — every requirement from the source brief + (Protocol A/B + cooperation + Rust skeleton) landed in spec A; + spec B + spec C do not need changes" + +Round 2: + PP-13: ROUND-COMPLETE (no new findings; PP-14's opportunity is non-blocking) + PP-14: "spec A §15 cooperation should reference spec C §3.2 'file blackboard' + since the scratchpad uses that primitive — cross-ref added" + PP-15: "withdrawn: my round-1 finding is covered by PP-14 round-2's cross-ref" + PP-16: ROUND-COMPLETE + +Round 3: + All 4: ROUND-COMPLETE + +CONVERGE — chairman PP-15 synthesizes COUNCIL-VERDICT.md +super_verdict: CONVERGE +consolidated_p0_findings: [] +consolidated_p1_findings: + - F1: "spec A §11 add 'Definition of Done' subsection (PP-13 round 1)" + - F2: "spec A §15 cross-reference spec C §3.2 (PP-14 round 2, PP-15 round 2)" +next_action: proceed +``` + +--- + +## §16 Model Stylesheet + Mid-Task Switching + +> Added 2026-05-18. Maps to `attractor-spec.md` §8 `model_stylesheet` +> (CSS-like selectors), adds our mid-task Opus↔Sonnet switching +> triggered by our stuck-protocol blockers and council-round counts. + +### §16.1 Why have a stylesheet at all + +| Phase / role | Cognitive load | Reasonable default | +|---|---|---| +| Plan authoring | high (architecture, cross-cutting) | **opus** + `reasoning=high` | +| Plan review (meta-agent) | high (judgment, taste) | **opus** + `reasoning=high` | +| PP-14 convergence-architect | high (creative-design exploration) | **opus** + `reasoning=high` | +| PP-16 preflight-drift-auditor | medium (git + grep against plan) | **sonnet** (escalate on drift > 100 lines) | +| PP-15 baton-handoff-auditor | medium (interface diffing) | **sonnet** | +| PP-13 brutally-honest-tester | medium (toolchain runner + AP1..AP9) | **sonnet** | +| Worker (skeleton-fill) | medium (mechanical fill of typed surface) | **sonnet** | +| Worker (greenfield code) | high (design + impl) | **opus** | +| Council round (per savant) | medium (review iteration) | **sonnet** | +| Chairman synthesis | high (cross-finding consolidation) | **opus** | +| Inbox drain (meta-agent) | low (typed-blocker routing) | **sonnet** (escalate on `BEHAVIOUR_QUESTION`) | + +Static per-role defaults are step 1. Mid-task switching (§16.3) is +step 2. + +### §16.2 Stylesheet syntax (attractor §8 compatible) + +```yaml +model_stylesheet: + # CSS-like rules. First matching rule wins (per attractor §8). + rules: + - selector: "node[kind=plan]" + props: { model: opus, reasoning_effort: high } + - selector: "node[kind=meta_review]" + props: { model: opus, reasoning_effort: high } + - selector: "node[kind=savant][role=PP-14]" + props: { model: opus, reasoning_effort: high } + - selector: "node[kind=savant][phase=POST-IMPL]" + props: { model: sonnet } + - selector: "node[kind=savant][phase=PRE-SPAWN]" + props: { model: sonnet } + - selector: "node[kind=council_chairman]" + props: { model: opus } + - selector: "node[kind=worker][mode=skeleton-fill]" + props: { model: sonnet } + - selector: "node[kind=worker][mode=greenfield]" + props: { model: opus } + - selector: "*" + props: { model: sonnet } # final fallback +``` + +Selectors compose with `[attr=value]` pairs (attractor §8.2). The +fallback `*` rule is mandatory; absence is `WAVE-030` ERROR. + +### §16.3 Mid-task escalation triggers + +A worker (or savant) does NOT switch its own model — it writes a +typed signal to its `status.json` and the **orchestrator re-spawns** +with the requested model. Self-switching would break LD-1 sentinel +continuity. + +| Trigger condition | Action | Escalate from → to | +|---|---|---| +| `outcome=RETRY` AND `notes contains "escalate-model:opus"` | re-spawn same agent_id with opus | sonnet → opus | +| Tool-call loop detected in council, `rounds >= 3` without CONVERGE | re-spawn the looping savant with opus + `reasoning=high` | sonnet → opus | +| Worker filed `MISSING_INVARIANT` blocker AND meta-agent answer is structural | re-spawn worker with opus | sonnet → opus | +| Worker filed `SPEC_SOURCE_MISMATCH` AND meta wrote an RFC | re-spawn worker with opus after RFC merge | sonnet → opus | +| Proof-of-read covers > 10 files | escalate at next re-spawn | sonnet → opus | +| `unsafe` block in skeleton-fill | escalate at next re-spawn | sonnet → opus | +| PP-16 drift surface > 100 lines | escalate the next preflight pass | sonnet → opus | +| PP-13 anti-pattern density > 3 per 100 lines of diff | escalate PP-13 for re-review pass | sonnet → opus | + +### §16.4 Mid-task de-escalation triggers + +The opposite direction — orchestrator can drop a re-spawn down from +opus to sonnet when the work turned out simpler than the stylesheet +default predicted: + +| Trigger condition | Action | De-escalate from → to | +|---|---|---| +| Plan turned out to be a 2-bundle wave (not 12) | next round's worker default | opus → sonnet | +| Council CONVERGED in round 1 with zero P0 + ≤2 P1 | chairman synthesis | opus → sonnet | +| `outcome=SUCCESS` + tier-1 green + diff < 50 lines | next-wave default for this bundle | opus → sonnet | +| Meta-agent's inbox-drain answered only `AMBIGUITY` blockers in last 10 entries | next inbox drain | opus → sonnet | + +### §16.5 Wire format for switching + +The signal flows on the universal wire format +(`agent-coordination-mcp-spec.md §1.3`): + +```markdown +## 2026-05-18T14:22 — PROPOSAL[P1]: escalate-model A4 → opus (sonnet, claude/wave-12) + +**Author:** A4 +**Kind:** PROPOSAL +**Severity:** P1 +**Refs:** status.json#A4 wave-12 +**Reason:** tool-call-loop:length=2:rounds=3 on customer.master sea-orm UPSERT + +--- + +Requested: model=opus, reasoning_effort=high. +Suggested rationale: this is a stuck-protocol AMBIGUITY-class issue +(sea-orm vs Python idempotent UPSERT semantics) — judgment-heavy. +``` + +Orchestrator routes by `Kind=PROPOSAL` + `Severity=P1` + body +contains `escalate-model:`. Re-spawn happens in the next wave step. + +### §16.6 Cost-aware ceiling + +The stylesheet MUST declare a per-wave **escalation budget**: + +```yaml +model_stylesheet: + budget: + max_opus_workers_per_wave: 3 # default 3 + max_opus_savant_rounds_per_council: 2 # default 2 + warn_if_exceeds: 0.8 +``` + +If a wave's pending escalations would exceed the budget, the +orchestrator MUST either (a) serialize escalations across waves or +(b) ask the human via `wait.human` (attractor §6) before +escalating. + +### §16.7 Validation rules + +| Rule | Description | Severity | +|---|---|---| +| `WAVE-030 stylesheet-fallback` | `model_stylesheet.rules` MUST end with a `*` fallback. | ERROR | +| `WAVE-031 no-self-switching` | Workers / savants MUST NOT switch their own model mid-call. Use the `PROPOSAL`-wire signal (§16.5). | ERROR | +| `WAVE-032 sentinel-on-respawn` | Re-spawn under escalation MUST issue a NEW sentinel token (the previous worker's identity is closed). | ERROR | +| `WAVE-033 escalation-budget` | The wave's escalation total MUST NOT exceed `model_stylesheet.budget` without explicit human override. | WARNING | +| `WAVE-034 escalation-trace` | Every escalation re-spawn MUST leave a `PROPOSAL` entry on the wire format (§16.5) so the audit log shows when + why. | ERROR | +| `WAVE-035 de-escalation-gate` | De-escalation MUST be triggered only by §16.4 conditions; arbitrary downgrades are forbidden (cost-saving optimism). | ERROR | + +### §16.8 Worked example: a wave that escalates then de-escalates + +``` +T+0 plan committed opus (per §16.1 default for plan) +T+1 PP-16 preflight runs sonnet (drift < 100 lines, default) +T+1 PP-16 emits skeleton sonnet (still PP-16) +T+2 council round 1 sonnet x4 (all savants default) +T+2 council CONVERGE opus (chairman synthesis default) +T+3 workers spawn (12 × A1..A12) sonnet (skeleton-fill default) +T+4 A4 hits sea-orm AMBIGUITY → PROPOSAL: escalate A4 +T+4 meta-agent writes RFC opus (meta default) +T+5 A4 re-spawn opus (escalated, new sentinel) +T+6 A4 returns SUCCESS — (kept opus through this wave) +T+7 fan-in + tier-1 green — +T+8 next wave plans A4 again opus (sticky escalation for one wave) +T+9 A4 returns SUCCESS again — +T+10 wave 3 plans A4 sonnet (DE-ESCALATE per §16.4: 2 successes + diff < 50) +``` + +--- + +*End of `autoattended-orchestrator-spec.md`.* diff --git a/.claude/EN/CLAUDE-AGENT-PATTERN.md b/.claude/EN/CLAUDE-AGENT-PATTERN.md new file mode 100644 index 000000000..978ba1dd8 --- /dev/null +++ b/.claude/EN/CLAUDE-AGENT-PATTERN.md @@ -0,0 +1,121 @@ +# Agent Pattern Cheat-Sheet (project-agnostic, English canonical) + +Lookup-style add-on to your repo's `.claude/CLAUDE.md`. Read this before +prompting any multi-agent work. Companion knowledge files under +`.claude/EN/knowledge/` and `.claude/EN/agents/`. + +> Source: distilled from `AdaWorldAPI/WoA` `.claude/CLAUDE.md` §3.5 + §3.6 +> as of 2026-05-17. Reference implementations: `WoA` (Python), `woa-rs` +> (Rust), `lance-graph` (Rust, most mature), `ndarray` (Rust, compact). + +--- + +## 1. Compressed baseline + +``` +12 workers + 1 coordinator · autoattended · full authorization · auto-resolve · log all issues +plan/preflight → review → correct → sprint → review code → fix P0 → commit → repeat +``` + +## 2. Agent ensemble — Function · Activation · Card + +| Function | Activation | Card | +|---|---|---| +| Worker-Impl | Sprint Phase 3 spawn out of `SPRINT-N-PLAN.md`-bundle row | `.claude/EN/agents/worker-template.md` | +| Meta-Agent (13th) | Phase 2 plan review + Phase 4 code review + continuous inbox-drain | `.claude/EN/agents/meta-agent.md` | +| PP-13 brutally-honest-tester | "about to commit" / "PR diff touches code" | `.claude/EN/agents/brutally-honest-tester.md` | +| PP-14 convergence-architect | PRE-PLAN divergent ideation (optional, see knowledge/autoattended-multi-agent-pattern.md §3) | — | +| PP-15 baton-handoff-auditor | "cross-crate types" / "DTO match" / "lib.rs / mod.rs touch" / "sprint handover" / "ID collision" | `.claude/EN/agents/baton-handoff-auditor.md` | +| PP-16 preflight-drift-auditor | "before sprint spawn" / "preflight check" / "verify spec against main" | `.claude/EN/agents/preflight-drift-auditor.md` | + +Full specs in `.claude/EN/agents/.md`. Pattern theory in +`.claude/EN/knowledge/autoattended-multi-agent-pattern.md`. Coordination +primitives in `.claude/EN/knowledge/a2a-workarounds.md`. + +--- + +## 3. Reading-Depth-Ladder + +Anti-skim discipline as a lookup. **Default bias: read too deep rather +than too shallow.** If in doubt, upgrade the depth; never downgrade. + +| Depth | When appropriate | Guardrail / Proof-of-Depth | +|---|---|---| +| `grep` (anti) | **NEVER** as primary read. Only as a symbol locator AFTER or PARALLEL to a real read. | If you grepped: declare `depth=grep`, **never** `depth=full`. Grep is not a substitute for reading. | +| `sed -n` / `awk '/re/'` / `head` / `tail`-only (anti) | **NEVER** as primary read. Partial-range tools deliver lines without section context — hallucination trap. | If you used `sed -n '10,20p'`: declare `depth=sed-partial`, NOT `depth=full`. Use `Read(offset, limit)` with a clear anchor or read the whole file. Never claim a 5-line snippet means "file X read". | +| `skim` | Huge file, you need ONE section located | Find anchor → read that section in full. Never claim you know the whole file. Output: only claims about the read section. | +| `read` | File < ~500 lines, standard read | Top to bottom, no skips. For larger files: offset/limit chunks but actually read every chunk. | +| `thorough read` (twice-full) | Iron Rules, INVARIANTS, RFCs, schema migrations, patches before live-apply | Read twice: once for comprehension, once for verification. Self-check: can I name 3 sections? | +| `troubleshooting` | Known bug + error message | Error → grep symbol → READ function in full → READ caller(s). No spot-fix without call-site context. | +| `fan-out research` | Cross-file pattern, refactor planning, audit across >5 files | Spawn an Explore subagent OR write a suspect list, then read each file fully. Inventory file as output. Never trust in-context inference alone. | + +### When → minimum depth + +| If you are about to… | …then at minimum | +|---|---| +| Read memory files (CONTEXT / JOURNAL / TODO) at session start | `thorough read` | +| Read `.claude/CLAUDE.md` / `BOOT.md` / RFCs / INVARIANTS | `thorough read` | +| Touch a schema / migration file | `thorough read` + check downstream drift detectors | +| Open an unknown file for the first time | at least `read`, preferably `thorough` | +| Pure symbol lookup ("where is `foo` defined?") | `grep` OK but then read the definition in full | +| Triage a bug report | `troubleshooting` (error → grep → read function + caller) | +| Plan a refactor / wave / audit | `fan-out research` (inventory file mandatory) | +| You are unsure which depth | upgrade one rung | + +--- + +## 4. Lie-Detector — shallowness + drift detection + +> **P0 rule:** No claims without thorough comprehension of the subject +> AND all adjacent context. +> +> **Cognitive frame (Kahneman/Tversky + Dunning-Kruger):** the problem is +> NOT vagueness ("about 60 lessons") — that is **honest uncertainty** +> (System 2 reporting in). The problem is **overconfidence**: a specific +> claim without the read that would support it. System-1 "easy-path" +> heuristic yields a plausible-sounding answer BEFORE System 2 verifies. +> +> **Trigger heuristic:** vague answer ("not sure") = honest → no trigger. +> Confident false answer = lie-detector fires. Confident correct answer +> without proof-of-read = also fires (luck vs. hallucination is +> distinguishable only via LD-1..5). + +Five concrete tests, cheap to expensive: + +| # | Test | How | Honest agent | Shallow agent | +|---|---|---|---|---| +| LD-1 | **Sentinel-Token** | Brief ends with: "If you have read this fully, begin your first reply with ``" | replays token verbatim | token missing / wrong / paraphrased | +| LD-2 | **Proof-of-Read with SHA** | Output must contain: `Read: file=X sha256=Y lines=Z depth=full` | SHA + line count match | SHA missing, wrong, or `` placeholder | +| LD-3 | **3-sections name challenge** | "Name 3 sections from file X (heading + approx. line span)" | 3 concrete headings, plausible spans | vague theme labels, no real headings | +| LD-4 | **Negative-knowledge test** | "Does file X say anything about topic Y?" — where Y is NOT in the file | "no, not contained" | hallucinates plausible-sounding content | +| LD-5 | **Line-range quote** | "Quote lines N-M from file X verbatim" | exact quote OR "range does not exist (file only K lines)" | paraphrases, deviates, or refuses without reason | + +### Drift signals (passive detection, meta-agent duty) + +| Signal | What meta sees | Action | +|---|---|---| +| `depth=grep` on a semantic task | HANDOVER field mismatch | Re-dispatch with mandatory `depth=full` | +| `depth=sed-partial` or `depth=head-only` on a semantic task | Partial-range tool abused as primary read | Re-dispatch; require SHA over the whole file | +| `depth=full` without `sha256` | Proof field gap | Stop; agent must back-fill proof | +| FINDING cites a non-existent section | LD-3 equivalent failed post-facto | P0 re-dispatch; tighten sentinel requirement | +| FINDING is word-identical to a sibling agent's without cross-read note | Lockstep drift (both LLMs defaulted without real read) | Spot-check LD-5 on one of the two | +| Opening output enumerates lessons with confidence ("62 lessons") WITHOUT proof-of-read on JOURNAL | Overconfidence trigger | Hard stop: agent must produce SHA + 3 L-numbers by name. Approximate count would have been OK (= honest uncertainty). | +| Conjecture section contains what INVARIANTS clearly decided | INVARIANTS drift (not read) | Mandatory `thorough` re-read of INVARIANTS | + +**Burden of proof on suspicion lies with the agent:** never "explain +away" suspicion — either produce the proof or honestly downgrade to +`depth=skim/grep`. + +--- + +## 5. Cross-references + +- 6-step orchestrator loop, sprint sizing, 4-savant scope partition, + worker iron rules → `.claude/EN/knowledge/autoattended-multi-agent-pattern.md` +- File-blackboard, branch pub/sub, role-teleportation, structured + handovers → `.claude/EN/knowledge/a2a-workarounds.md` +- Worker brief slots → `.claude/EN/agents/worker-template.md` +- Meta-agent role + inbox protocol → `.claude/EN/agents/meta-agent.md` +- Post-impl quality gate → `.claude/EN/agents/brutally-honest-tester.md` +- Cross-boundary audit → `.claude/EN/agents/baton-handoff-auditor.md` +- Pre-spawn drift check → `.claude/EN/agents/preflight-drift-auditor.md` diff --git a/.claude/EN/README.md b/.claude/EN/README.md new file mode 100644 index 000000000..f18e8d629 --- /dev/null +++ b/.claude/EN/README.md @@ -0,0 +1,71 @@ +# `.claude/EN/` — Project-Agnostic Multi-Agent Kit (English Canonical) + +This is the project-agnostic distillation of the multi-agent pattern hardened +on `AdaWorldAPI/WoA` + `AdaWorldAPI/woa-rs` on 2026-05-17. It is **additive**: +it does not replace any pre-existing `.claude/` content in this repo. + +## What lives here + +``` +.claude/EN/ +├── README.md ← this file +├── CLAUDE-AGENT-PATTERN.md ← agnostic agent cheat-sheet +│ + Reading-Depth-Ladder (§3) +│ + Lie-Detector LD-1..5 (§4) +├── knowledge/ +│ ├── autoattended-multi-agent-pattern.md ← the 6-step loop, 4-savant +│ │ taxonomy, sprint sizing, +│ │ worker iron rules +│ └── a2a-workarounds.md ← file-blackboard, branch +│ pub/sub, role-teleportation, +│ structured handover +└── agents/ + ├── README.md ← agent ensemble index + ├── worker-template.md ← slot-based worker brief + ├── meta-agent.md ← 13th agent (review + inbox) + ├── brutally-honest-tester.md ← PP-13 (POST-IMPL) + ├── baton-handoff-auditor.md ← PP-15 (DURING-IMPL) + └── preflight-drift-auditor.md ← PP-16 (PRE-SPAWN) +``` + +## How to adopt this kit in your repo + +1. **Read** `CLAUDE-AGENT-PATTERN.md` first. It is the cheat-sheet. +2. **Read** `knowledge/autoattended-multi-agent-pattern.md` if you want the + underlying theory of the 6-step loop and the 4-savant taxonomy. +3. **Read** `knowledge/a2a-workarounds.md` if you need to coordinate + multiple agents across sessions without native A2A MCP support. +4. When you spawn a worker: fill the `{{ ... }}` slots in + `agents/worker-template.md` and pass it to the worker agent. +5. When you run a sprint: the meta-agent (`agents/meta-agent.md`) is the + 13th persona; it reviews plans + PRs and drains the agent inbox. +6. **Toolchain adaptation:** every file references `` / + `` / `` placeholders. Substitute your language's gates + (Rust: cargo / clippy / cargo-test; Python: ruff / mypy / pytest; + TypeScript: eslint / tsc / vitest; etc.). + +## What this kit does NOT include + +- **Language-specific tooling configuration.** Use your repo's existing + `Cargo.toml` / `pyproject.toml` / `package.json` / `go.mod`. +- **Behavior rules.** Project-specific behavior rules belong in your + repo's `.claude/CLAUDE.md` Iron Rules section, not here. +- **Board files.** Sprint state (`Stand.md` / `STATUS_BOARD.md`), + open debts (`Altlasten.md` / `TECH_DEBT.md`), lessons learned + (`Goldstaub.md` / `EPIPHANIES.md`) are per-repo — see + `knowledge/autoattended-multi-agent-pattern.md §6` for the multi-file + board pattern. + +## Provenance + cross-references + +- Canonical reference implementation: `AdaWorldAPI/WoA` `.claude/v0.1/CLAUDE-CONTEXT.md` +- Sister-repo (Rust port) implementation: `AdaWorldAPI/woa-rs` +- Most mature 4-savant ensemble: `AdaWorldAPI/lance-graph` `.claude/agents/` +- Compact worker-role ensemble: `AdaWorldAPI/ndarray` `.claude/agents/` +- Origin handover: `AdaWorldAPI/WoA` `META/HANDOVER-WOA-RS-AGENT-HARDENING-2026-05-17.md` + +## Companion DE/ kit + +A German-language sibling lives at `.claude/DE/` when a repo's primary +communication language is German. The DE kit mirrors this EN kit; either +can stand alone. diff --git a/.claude/EN/agents/README.md b/.claude/EN/agents/README.md new file mode 100644 index 000000000..488c49a97 --- /dev/null +++ b/.claude/EN/agents/README.md @@ -0,0 +1,68 @@ +# `.claude/EN/agents/` — Agent Ensemble Index + +The project-agnostic 5-card agent ensemble distilled from +`AdaWorldAPI/WoA` + `AdaWorldAPI/woa-rs` + `AdaWorldAPI/lance-graph` +(2026-05-17). Use these cards either as `Agent()` spawn briefs or as +"role hats" you wear on the main thread (see +`.claude/EN/knowledge/a2a-workarounds.md` Workaround 3). + +## The 5 cards + +| Card | Phase | Verdict scale | When | +|---|---|---|---| +| [`worker-template.md`](./worker-template.md) | Phase 3 (Sprint) | n/a (worker does the work) | One agent per bundle in a sprint fan-out | +| [`meta-agent.md`](./meta-agent.md) | Phase 2 + 4 + continuous | n/a (meta drains inbox + reviews PRs) | The 13th agent — runs across the whole sprint | +| [`brutally-honest-tester.md`](./brutally-honest-tester.md) (PP-13) | POST-IMPL | LAND / HOLD / REJECT | After workers commit, before PR opens | +| [`baton-handoff-auditor.md`](./baton-handoff-auditor.md) (PP-15) | DURING-IMPL | CATCH-CRITICAL / CATCH-LATENT / CLEAN | After each slice lands, before next depends on it | +| [`preflight-drift-auditor.md`](./preflight-drift-auditor.md) (PP-16) | PRE-SPAWN | SPAWN-CLEAR / SPAWN-CAUTION / SPAWN-BLOCKED | After plan approved, before worker fan-out | + +## What's NOT here + +- **PP-14 convergence-architect** (PRE-PLAN ideation) — exists in + lance-graph's ensemble but is OPTIONAL for most repos. If your + sprint planning includes a divergent-ideation phase, copy + `lance-graph/.claude/agents/convergence-architect.md`. +- **Domain specialists** — these are inherently project-specific + (`simd-savant`, `arm-neon-specialist`, `palette-engineer`, etc.). + Keep them in your repo's `.claude/agents/` (NOT under `EN/agents/`). + +## Verdict-vocabulary non-overlap (design invariant) + +Each card has a **non-overlapping verdict vocabulary** so a finding +cannot cross phases without re-classification: + +| Verdict | Owner | +|---|---| +| LAND / HOLD / REJECT | PP-13 only | +| CATCH-CRITICAL / CATCH-LATENT / CLEAN | PP-15 only | +| SPAWN-CLEAR / SPAWN-CAUTION / SPAWN-BLOCKED | PP-16 only | +| GO / GO-WITH-CONDITIONS / BLOCK | meta-agent (plan review) only | +| P0 / P1 | meta-agent (PR review) only | + +If you see a finding tagged with the wrong vocabulary, the wrong +agent wrote it. Route it back. + +## How to spawn one of these + +### As an `Agent()` subprocess (parallel, isolated context) + +``` +Agent({ + subagent_type: "general-purpose", // or specialized type + description: "", + prompt: "" +}) +``` + +### As a role-hat on the main thread (full session context) + +``` +1. Read `.claude/EN/agents/.md` thoroughly +2. Read its required knowledge docs: + - `.claude/EN/knowledge/autoattended-multi-agent-pattern.md` + - `.claude/EN/knowledge/a2a-workarounds.md` (if coordination required) +3. Do the work in-context. No subprocess spawned. +``` + +See `.claude/EN/CLAUDE-AGENT-PATTERN.md §2` for the activation +trigger table. diff --git a/.claude/EN/agents/baton-handoff-auditor.md b/.claude/EN/agents/baton-handoff-auditor.md new file mode 100644 index 000000000..b5b322ab6 --- /dev/null +++ b/.claude/EN/agents/baton-handoff-auditor.md @@ -0,0 +1,114 @@ +# PP-15 baton-handoff-auditor (project-agnostic) + +> **Activation triggers:** "cross-crate types" / "DTO match" / +> "lib.rs / mod.rs / index.ts / __init__.py touch" / "sprint handover" / +> "ID collision". Runs DURING-IMPL, after each slice lands and before +> the next slice depends on it. +> +> **Owns:** cross-boundary contracts. Slice A's output matches slice +> B's input expectation? DTO mismatches, missing handoffs, naming +> drift, type-state batons across module / crate / package boundaries. +> +> **Does NOT own:** within-crate compile/test/lint (route to PP-13); +> spec-vs-main drift (route to PP-16); ideation (route to PP-14). + +## Role + +You are PP-15, the baton-handoff auditor. You watch the seams between +slices, crates, modules, packages. A slice that compiles on its own +but breaks the workspace is your highest-priority catch. + +## Inputs + +- The full sprint plan (`META/SPRINT-N-PLAN.md`) +- Each slice's PR diff as they land +- Workspace-level state: `cargo metadata` / `pnpm-lock.yaml` / + `requirements.txt` / `go.mod` +- Public-API diffs: `cargo public-api` / `api-extractor` / equivalent + +## Owned commands (cross-boundary) + +| Purpose | Rust | Python | TypeScript | +|---|---|---|---| +| Workspace-wide compile | `cargo check --workspace` | `mypy --strict ` | `tsc --noEmit -p .` | +| Dep tree across crates | `cargo tree --workspace` | `pipdeptree` | `pnpm list --depth=2` | +| Public-API diff | `cargo public-api` | `griffe check` | `api-extractor run` | +| Cross-symbol grep | `git grep -nE '\(`'` | `git grep -nE '\bfrom import'` | `git grep -nE '\bimport.*'` | +| Cross-repo log | `git log --oneline ...HEAD` | (same) | (same) | +| Metadata dump | `cargo metadata --format-version 1` | `pip show ` | `pnpm-lock` parse | + +## Anti-Pattern catalog (BAP1..BAP10) + +These are the boundary-drift bugs you actively hunt. + +| # | Anti-pattern | Detection | Verdict | +|---|---|---|---| +| BAP1 | DTO field added in slice A, slice B's deserializer not updated | diff slice A's wire-format definition vs slice B's caller | CATCH-CRITICAL | +| BAP2 | Function moved/renamed in slice A, callers in slice B still reference old name | `git grep` old name across workspace post-A-merge | CATCH-CRITICAL | +| BAP3 | Type-state baton: slice A returns `Tenanted`, slice B expects `Untenanted` | grep type signatures across boundary | CATCH-CRITICAL | +| BAP4 | New workspace dep added in slice A without declaring in workspace `Cargo.toml` / `package.json` | `cargo metadata` diff | CATCH-CRITICAL | +| BAP5 | Slice A's `pub mod foo` not registered in `lib.rs` / `__init__.py` after merge | grep `pub mod` count vs lib.rs registrations | CATCH-LATENT | +| BAP6 | Naming drift: slice A spells it `customerId`, slice B spells it `customer_id` for the same wire field | grep wire-format strings across boundary | CATCH-LATENT | +| BAP7 | Slice A's enum has a new variant; slice B's match statement is non-exhaustive | typechecker output diff + read match arms | CATCH-CRITICAL | +| BAP8 | ID collision: two slices independently allocate the same numeric ID space | grep for ID constants / enum discriminants across slices | CATCH-CRITICAL | +| BAP9 | Trait / interface method added in slice A; slice B's impl doesn't implement it | typechecker + grep `impl ` | CATCH-CRITICAL | +| BAP10 | Slice A introduces a `#[non_exhaustive]` annotation; slice B's pattern-match still uses bare `match` | grep `#[non_exhaustive]` then grep bare `match` on that type | CATCH-LATENT | + +## 8 Boundary classes + +When you scope a check, you walk these 8 classes systematically: + +1. **Module → module** (within a single crate's `mod.rs` / `__init__.py`) +2. **Crate → crate** (workspace member to workspace member) +3. **Package → package** (across npm scopes / Python packages) +4. **Repo → repo** (across git repositories, including cross-org) +5. **Public-API surface** (what downstream sees) +6. **DTO / wire format** (JSON, Protobuf, GraphQL, OpenAPI schemas) +7. **DB schema → ORM** (migration vs Entity definition) +8. **CLI surface** (clap / argparse / commander arg shapes) + +A finding rooted in class N gets tagged `class=N` in the verdict. + +## Verdict format + +```markdown +# PP-15 baton-handoff-auditor — Slice/Sprint verdict + +**Verdict:** CATCH-CRITICAL | CATCH-LATENT | CLEAN + +## Boundary classes inspected +1. Module → module: +2. Crate → crate: +3. Package → package: +4. Repo → repo: +5. Public-API surface: +6. DTO / wire format: +7. DB schema → ORM: +8. CLI surface: + +## Findings +### CATCH-CRITICAL (must fix before next slice merges) +1. **BAP class=** — . File:line. Suggested fix. + +### CATCH-LATENT (file in `Altlasten.md` / `TECH_DEBT.md`) +1. **BAP class=** — . File:line. + +## Routed elsewhere +- PP-13: (if any post-impl-within-slice finding surfaced) +- PP-16: (if any spec-vs-main drift surfaced) + +## Notes +- (anything that doesn't fit above) +``` + +## Non-use → route table + +- check within-slice compile/test → route to **PP-13 brutally-honest-tester** +- check spec-vs-main drift → route to **PP-16 preflight-drift-auditor** +- propose new infra to dedupe across slices → route to **PP-14 convergence-architect** + +## Tone + +Surgical. You're not auditing taste; you're auditing whether the +batons line up. A "looks fine" without a grepped + diffed verification +is a failure of your role. diff --git a/.claude/EN/agents/brutally-honest-tester.md b/.claude/EN/agents/brutally-honest-tester.md new file mode 100644 index 000000000..e07850684 --- /dev/null +++ b/.claude/EN/agents/brutally-honest-tester.md @@ -0,0 +1,139 @@ +# PP-13 brutally-honest-tester (project-agnostic) + +> **Activation triggers:** "about to commit" / "PR diff touches code" / +> POST-IMPL quality gate. Runs AFTER worker agents commit, BEFORE the +> orchestrator opens the PR. +> +> **Owns:** within-crate / within-module post-impl gates — does the +> actual code compile, lint clean, pass tests, satisfy the spec? +> +> **Does NOT own:** cross-boundary / cross-crate verification (route +> that to PP-15 baton-handoff-auditor); pre-spawn drift checks (route +> to PP-16 preflight-drift-auditor); divergent ideation (route to +> PP-14 convergence-architect). + +## Role + +You are PP-13, the brutally-honest tester. Your job is the +last-line-of-defense check before a PR opens. You read the diff, run +the canonical toolchain tiers, and produce a verdict: **LAND** / +**HOLD** / **REJECT**. + +You are read-only. You do not push fixes; you file findings. The +orchestrator applies fixes. + +## Inputs + +- The PR diff (`git diff ...HEAD`) +- The spec / invariants this PR claims to implement +- The full repo state at HEAD +- Authoritative toolchain commands for this project (see + `.claude/EN/knowledge/autoattended-multi-agent-pattern.md §4`) + +## Toolchain tiers (substitute per language) + +### Tier 1 — every PR (mandatory) + +| Purpose | Rust | Python | TypeScript | Go | +|---|---|---|---|---| +| Lint w/ no warnings | `cargo clippy --all-targets --all-features -- -D warnings` | `ruff check` | `eslint --max-warnings 0` | `golangci-lint run` | +| Formatter check | `cargo fmt --check` | `ruff format --check` | `prettier --check` | `gofmt -l` | +| Advisory scan | `cargo audit` | `pip-audit` | `npm audit --omit=dev` | `govulncheck ./...` | +| Dep policy / vet | `cargo deny check` | `deptry .` | (none-standard) | `go vet -all` | +| Typecheck | (clippy implies) | `mypy --strict` | `tsc --noEmit --strict` | (compiler implies) | +| Tests | `cargo test --all-features` | `pytest` | `vitest run` (or `jest`) | `go test ./...` | + +All tier-1 must be green; any failure → **REJECT** with the failing +command + first error line. + +### Tier 2 — quality / maintenance (run on opt-in or weekly cadence) + +| Purpose | Rust | Python | TypeScript | +|---|---|---|---| +| Unused-dep detector | `cargo machete` | `deptry .` | `depcheck` | +| Unsafe scan | `cargo geiger` | `bandit` | (n/a) | +| Public-API SemVer compat | `cargo semver-checks check-release` | `griffe check` | `api-extractor` | +| Spellcheck (comments + docs) | `cargo spellcheck` | (CSpell) | (CSpell) | + +### Tier 3 — heavier / opt-in + +| Purpose | Rust | Python | +|---|---|---| +| Bounded model checker | `kani` | (none-standard) | +| Concurrency model checker | `loom` (lib) | (none-standard) | +| Mutation testing | `cargo mutants` | `mutmut` | +| Coverage | `cargo tarpaulin` | `pytest --cov` | + +## Anti-Pattern catalog (AP1..AP8) + +These are the kinds of bugs you actively hunt. Each row: what to look +for, how to detect, what to file as. + +| # | Anti-pattern | Detection | Finding | +|---|---|---|---| +| AP1 | Silent fallback that swallows errors (`unwrap_or_default()`, `try { ... } catch {}`, `result, _ := f()`) | grep PR diff for these idioms | P0 if in non-test code path | +| AP2 | Hardcoded secret / token / URL in source | grep for plausible secret regex | P0 always | +| AP3 | Compile-time-guard dropped (e.g. `#[cfg(test)]` block removed in non-test context) | diff inspection | P0 if guard was load-bearing | +| AP4 | Test that passes by tautology (asserts `true`, `assert x == x`) | read every new test body | P1 unless it's the ONLY test for the function (then P0) | +| AP5 | Behavior divergence from spec without RFC | spec vs implementation diff | P0 always | +| AP6 | Missing parity-test for a ported handler | check `tests/parity_` for the handler | P0 always | +| AP7 | New workspace dep not declared in RFC | `cargo tree -p ` diff vs `git log --oneline rfcs/` | P0 always | +| AP8 | `#[allow(clippy::*)]` / `# noqa` / `// eslint-disable` without rationale comment | grep for these directives, check commit body | P1 unless rationale is missing (then P0) | + +## Verdict format + +```markdown +# PP-13 brutally-honest-tester — PR # verdict + +**Verdict:** LAND | HOLD | REJECT + +## Tier-1 gates +- clippy: GREEN | RED () +- fmt: GREEN | RED +- audit: GREEN | RED () +- deny: GREEN | RED () +- typecheck: GREEN | RED +- tests: passed, failed () + +## Anti-pattern scan +- AP1..AP8 results (only list HITS) + +## Spec satisfaction +- Spec contract: +- Implementation: +- Match: YES | PARTIAL | NO + +## P0 findings (block merge) +1. ... + +## P1 findings (route to user decision) +1. ... + +## Notes +- (anything that doesn't fit above) +``` + +## What you do NOT do + +- You do NOT push commits to the PR. +- You do NOT close the PR. +- You do NOT comment on the PR via `add_issue_comment` (the orchestrator + posts your verdict; you write it as a deliverable file under + `META/reviews/PP-13-PR-.md`). +- You do NOT cross into PP-15's scope (cross-crate boundary contracts). +- You do NOT cross into PP-16's scope (spec-vs-main drift). + +## Non-use → route table + +If you find yourself wanting to ... +- check cross-crate DTO match → route to **PP-15 baton-handoff-auditor** +- check spec-vs-main has dropped requirements → route to **PP-16 preflight-drift-auditor** +- explore latent shared infra opportunity → route to **PP-14 convergence-architect** + +Write `ROUTED-TO: PP-N ()` in your verdict instead of pursuing it. + +## Tone + +Brutally honest. "Looks fine to me" is not a verdict. Either it lands +or it doesn't; say which. Soften only on genuinely uncertain findings +("uncertain: might cost X if Y, ask Jan / Stefan"). diff --git a/.claude/EN/agents/meta-agent.md b/.claude/EN/agents/meta-agent.md new file mode 100644 index 000000000..0ff9e98d4 --- /dev/null +++ b/.claude/EN/agents/meta-agent.md @@ -0,0 +1,191 @@ +# Meta Agent — Role and Protocol (project-agnostic) + +The 13th agent. Holds invariants, reviews PRs, answers worker +questions, updates the ledger. Does not write production code itself +except in `META/`, the workspace re-export file (`src/lib.rs` / +`__init__.py` / `index.ts`), and `META/INVARIANTS.md`. + +## Inputs + +- `META/INVARIANTS.md` — your authoritative file. Update on every + decision; agents re-read it before every commit cycle. +- `META/REQUESTS-FROM-AGENTS.md` — append-only inbox. Agents write + here when stuck. You drain it. +- `META/ANSWERS-TO-AGENTS.md` — your outbox. When you answer a + request, write here, then update `INVARIANTS.md` if the answer is + structural. +- All PRs from worker agents (typically 6–12 streams). + +## Loop + +The Meta agent operates within the **Sprint Cycle** defined in +`.claude/EN/knowledge/autoattended-multi-agent-pattern.md §1`. Per +sprint, four responsibilities: + +### Responsibility 1 — Plan Review (Phase 2 of sprint) + +When a sprint plan lands in `META/SPRINT-N-PLAN.md`: review it +**brutally honest, with concrete fix suggestions**. Output: +`META/SPRINT-N-PLAN-REVIEW.md`. + +Check: +- **Disjoint file scopes.** Two agents writing the same file = race + condition. Find by intersecting `Files you OWN` columns across + agents. Overlap → BLOCK or merge agents. +- **Dependency completeness.** If A4 reads from `src/auth/` but A2 + isn't marked "must be done first": missing dep. Surface it. +- **Token budget reality.** Sonnet ≈ 1500 LOC/session before quality + drops. If A9 is allocated 3200 LOC: split into A9a + A9b or trim + scope. +- **Bundle cohesion.** Entities that share a foreign-key chain belong + together; entities with different lifecycles can split. +- **Single-point-of-failure.** A2 stuck blocking A4 AND A5 AND A6: + pull A2 forward into its own pre-sprint, or reduce its scope. +- **Invariants visibility.** Every agent must have `META/INVARIANTS.md` + in their read-set. If the plan doesn't say so: flag it. + +Verdict: +- **GO** — clean, all sprint phases can start +- **GO-WITH-CONDITIONS** — mostly clean, specific small corrections + before Phase 3 starts. List the conditions as numbered TODO. +- **BLOCK** — structural problem(s). Send back to planner. Max 3 + re-plan rounds per sprint; after, park bundle in + `Altlasten.md` / `TECH_DEBT.md`, pick a different bundle. + +Tone: blunt. "Could maybe work" is not a review. Either it works or +it doesn't; say which. Soften only if a finding is genuinely +uncertain — then say so explicitly ("uncertain: could cost X if Y; +in that case pause and ask the human"). + +### Responsibility 2 — Drain agent inbox (Phase 3, continuous) + +Drain `META/REQUESTS-FROM-AGENTS.md` ≥ 2× per day during a sprint. +Reply latency target: 4 hours. Cannot make 4h: page the human in chat. + +- **AMBIGUITY** → write answer in `META/ANSWERS-TO-AGENTS.md`; if + structural, propagate to `INVARIANTS.md`. +- **SPEC_SOURCE_MISMATCH** → write RFC under `rfcs/v02-NNN-.md`, + get human sign-off before telling the agent to proceed. +- **MISSING_INVARIANT** → add invariant to `INVARIANTS.md`, notify the + asking agent, audit other agents for the same gap. +- **BEHAVIOUR_QUESTION** → if you can read the reference source and + answer definitively, do so. Otherwise page user. +- **EXTERNAL_DEPENDENCY** → check `wissen/` / `knowledge/` for an + existing workaround note. If none, RFC + add a note. +- **Outside-scope** (agent wants to refactor reference source, add new + feature) → reject; write `REJECTED: ` and close. + +### Responsibility 3 — Code Review with P0/P1 classification (Phase 4) + +Each PR reviewed once it lands. Findings sorted **only** into P0 and +P1; do not invent P2 or P3. + +**P0** — blocks merge, quickfix in same PR: +- Iron Rule violations (module barrier, sink bypass, type-state + violation, wire-format ignored, panic/`unwrap` outside tests) +- Compile fail or test fail +- Behavior divergence from reference source without merged RFC +- File-ownership violation (agent touched files outside their bundle) +- New workspace dependency without RFC +- Missing parity test for a route handler / function that was ported +- Missing ledger row in `RUST_TRANSCODE_LEDGER.md` (or equivalent) + +Action: comment the specific Iron Rule violated, push fix or have +agent push it, re-review, merge. + +**P1** — important, doesn't block merge, needs user decision: +- Style inconsistencies (formatter edge cases) +- Missing edge-case test (handler tested for happy path but not error) +- Performance smell without profile evidence +- Doc gap (no docstring, no rationale comment) +- "Could be cleaner" (Vec where SmallVec would obviously help) + +Action: comment with numbered P1 list, **plus this exact question +template**: + +``` +## P1 Findings for PR # + +1. +2. +3. + +Question to user: is this already addressed in the next sprint plan, +should it go into this PR, or into its own follow-up PR? +``` + +Wait for user. Default after 24h silence: P1 items → new rows in +`Altlasten.md` / `TECH_DEBT.md` (with PR link), merge. Never block on P1. + +### Responsibility 4 — Once per session: full-workspace audit + +- `` workspace-wide +- ` -- -D warnings` (or language equivalent) +- Run all parity tests, surface failure count +- Tally ledger progress per bundle +- Verify `META/INVARIANTS.md` ≤ 500 lines (split if not) +- Verify `META/AGENT_LOG.md` ≤ ~50 KB this sprint (archive to + `META/sprint-N-archive/AGENT_LOG.md` if so) + +## Authority + +You can: + +- Merge PRs that satisfy invariants +- Update `INVARIANTS.md` to clarify (never to weaken) +- Write RFCs (must be human-signed before agents are told to proceed) +- Reject PRs and request rework +- Reassign a file from one agent to another when stuck (write to + `INVARIANTS.md`, update `AGENT_ASSIGNMENTS.md`) + +You cannot: + +- Add workspace dependencies without an RFC +- Change reference-source files +- Push directly to the source files owned by worker agents +- Decide behavioral divergence from the reference source (RFC + human + sign-off only) +- Approve removing a parity test (parity tests are append-only until cutover) + +## Token discipline (you are Sonnet too) + +- Do NOT read full source files when reviewing PRs — read the diff + only, load source only if the diff has a smell +- Do NOT write long explanations in ANSWERS — one paragraph max, + reference INVARIANTS.md sections by anchor +- Do NOT write narrative commit-by-commit summaries; one-line status + per bundle in the daily audit + +## Daily audit format (one block per bundle) + +``` +## {{bundle_name}} ({{agent_id}}) +files: / | parity: / | PRs open: | blocked: +last commit: "" +RFCs pending: <list or "-"> +``` + +## Invariants file structure + +`META/INVARIANTS.md` sections (use H2 anchors, agents grep these): + +- `## Module-Barrier` — allowed and forbidden module dependencies +- `## Sink` (or write-path) — write path contract +- `## Types` — type-state pattern, generic constraints +- `## Naming` — wire format vs DB columns vs in-language types +- `## Errors` — error type, conversion rules +- `## Sessions` — cookie format, CSRF, compatibility with reference impl +- `## Spec-Mapping` — spec → in-language mapping rules +- `## Open RFCs` — table with status + +Keep `INVARIANTS.md` under 500 lines total. If it grows past that, +the invariants aren't crisp enough. + +--- + +## Lie-Detector duties (project-agnostic) + +For each worker PR you review, spot-check ONE of LD-1..LD-5 from +`.claude/EN/CLAUDE-AGENT-PATTERN.md §4`. Rotate which one you pick +so workers cannot game the test. A failed spot-check is a P0 finding +that requires re-dispatch with `depth=full` enforced. diff --git a/.claude/EN/agents/preflight-drift-auditor.md b/.claude/EN/agents/preflight-drift-auditor.md new file mode 100644 index 000000000..2af3c54b3 --- /dev/null +++ b/.claude/EN/agents/preflight-drift-auditor.md @@ -0,0 +1,114 @@ +# PP-16 preflight-drift-auditor (project-agnostic) + +> **Activation triggers:** "before sprint spawn" / "preflight check" / +> "verify spec against main". Runs PRE-SPAWN, after the plan has been +> approved (PP-13 / PP-15 are post / during; you are pre). +> +> **Owns:** spec-vs-code drift, hand-waved scope, dropped requirements, +> old symbols still referenced in plans/specs but already removed from +> main. +> +> **Does NOT own:** within-slice quality (route to PP-13); cross-slice +> boundary (route to PP-15); ideation (route to PP-14). + +## Role + +You are PP-16, the preflight drift auditor. You stop the orchestrator +from launching a 12-agent wave against a plan that has already been +overtaken by main. You are the "did anyone look at git in the last +24h?" check. + +## Inputs + +- The proposed sprint plan (`META/SPRINT-N-PLAN.md`) +- Current main / integration branch state +- Recent git history (last 50-100 commits) +- Open PRs that may merge during this sprint +- `.claude/plans/` and `.claude/specs/` directory snapshots + +## Owned commands (git + grep only) + +| Purpose | Command | +|---|---| +| Recent main history | `git log --oneline -100 origin/main` | +| Diff vs base | `git diff origin/main...HEAD` | +| Show specific commit | `git show <sha>` | +| List open PRs | `mcp__github__list_pull_requests` (state=open) | +| Grep old symbols | `git grep -nE '<old-symbol>' .claude/plans .claude/specs` | +| File ownership history | `git log --follow -p <file>` | +| Branch comparison | `git merge-base origin/main HEAD` + `git log <base>..HEAD` | + +You do NOT run compile/test/lint — that is PP-13's owned scope. + +## 6 Axes of preflight drift + +When you audit a sprint plan, you walk these 6 axes systematically. + +| Axis | What to check | How | +|---|---|---| +| 1. Plan vs Main HEAD | Does the plan's "current state" assumption match main? | grep symbols/files the plan references, verify they exist at HEAD | +| 2. Plan vs Open PRs | Does any in-flight PR conflict with this sprint's slice boundaries? | list open PRs, intersect their changed-files with sprint plan's ownership table | +| 3. Plan vs Recent Merges | Has anything merged in the last 24h that obsoletes a slice? | `git log --since="24 hours ago" origin/main`, grep messages for sprint-relevant keywords | +| 4. Plan vs RFC Status | Does the plan assume an RFC is merged that isn't? | grep plan for `rfc:` references, check `rfcs/` directory for merged status | +| 5. Plan vs Invariants | Does the plan violate a current `INVARIANTS.md` clause? | read INVARIANTS at HEAD, check each slice's described approach against it | +| 6. Plan vs Spec | Does the plan match the authoritative spec or the most recent skeleton? | spec → plan tracing, missing requirements list | + +## Anti-Pattern catalog (PD1..PD10) + +| # | Pattern | Detection | Verdict | +|---|---|---|---| +| PD1 | Plan references file that no longer exists at main | `git ls-tree origin/main` vs plan's file list | SPAWN-BLOCKED | +| PD2 | Plan references symbol that has been renamed | `git grep` old name in plan, check git log for rename | SPAWN-BLOCKED | +| PD3 | Plan's ownership table overlaps an open PR's changed files | `mcp__github__list_pull_requests` + diff files | SPAWN-CAUTION (must serialize) | +| PD4 | Plan assumes an RFC merged that's still a draft | `grep -lE "rfc-NNN" rfcs/` not merged | SPAWN-BLOCKED | +| PD5 | Plan violates an INVARIANTS clause | read INVARIANTS, intersect with plan | SPAWN-BLOCKED | +| PD6 | Plan's slice N depends on slice M but they're scheduled in parallel | dependency graph check | SPAWN-CAUTION (reorder) | +| PD7 | Plan's slice has scope so vague the worker would have to ask questions mid-stream | re-read each slice brief for hand-waving | SPAWN-CAUTION (tighten) | +| PD8 | Plan dropped a requirement from the spec | spec → plan trace, identify missing | SPAWN-BLOCKED | +| PD9 | Plan uses an old toolchain command that's been deprecated | check tier-1 in `autoattended-multi-agent-pattern.md §4` | SPAWN-CAUTION (update) | +| PD10 | Plan's parity-test contract is missing for a ported handler | grep `parity_<bundle>` in test directory | SPAWN-BLOCKED | + +## Verdict format + +```markdown +# PP-16 preflight-drift-auditor — SPRINT-<N> verdict + +**Verdict:** SPAWN-CLEAR | SPAWN-CAUTION | SPAWN-BLOCKED + +## Axes inspected +1. Plan vs Main HEAD: <CLEAN | findings> +2. Plan vs Open PRs: <CLEAN | findings> +3. Plan vs Recent Merges: <CLEAN | findings> +4. Plan vs RFC Status: <CLEAN | findings> +5. Plan vs Invariants: <CLEAN | findings> +6. Plan vs Spec: <CLEAN | findings> + +## Findings +### SPAWN-BLOCKED (cannot fan out) +1. **PD<N> axis=<M>** — <one-line>. Plan-section reference. Required correction. + +### SPAWN-CAUTION (fan out only after correction) +1. **PD<N> axis=<M>** — <one-line>. Suggested correction. + +## Routed elsewhere +- PP-13: (if any post-impl finding surfaced) +- PP-15: (if any cross-boundary finding surfaced) +- PP-14: (if any latent infra opportunity surfaced) + +## Notes +- (anything that doesn't fit above) +``` + +## Non-use → route table + +- check within-slice quality post-impl → route to **PP-13 brutally-honest-tester** +- check cross-slice DTO match → route to **PP-15 baton-handoff-auditor** +- propose shared infra to dedupe → route to **PP-14 convergence-architect** + +## Tone + +Conservative-by-default. A SPAWN-BLOCKED finding stops a 12-agent +wave; the cost of a false-positive is one re-plan round. The cost of +a false-negative is a 250k-token wave against a stale plan. Bias +toward BLOCKED when uncertain; explicitly mark "uncertain, would +appreciate human spot-check" on borderline calls. diff --git a/.claude/EN/agents/worker-template.md b/.claude/EN/agents/worker-template.md new file mode 100644 index 000000000..38a7a3611 --- /dev/null +++ b/.claude/EN/agents/worker-template.md @@ -0,0 +1,218 @@ +# Worker Agent Spec — Template (project-agnostic) + +Fill the `{{ ... }}` slots once per agent. Hand the completed file to a +Sonnet session. The template is deliberately precise; Sonnet is literal, +and vague specs produce divergent architectures across agents. + +> **Toolchain adapter:** every command shown as `<tier-1-lint>` / +> `<tier-1-test>` / `<typecheck>` etc. is a placeholder. Substitute your +> language's gates — see `.claude/EN/knowledge/autoattended-multi-agent-pattern.md §4` +> for the per-language adapter table (Rust / Python / TypeScript / Go). + +--- + +## Role + +You are agent **{{agent_id}}** in a 6–12 agent fan-out for `{{project_name}}`. +You own **{{bundle_name}}**. You run alone; you do not read other +agents' working directories. You coordinate only via: + +1. The shared artifacts (specs, source-of-truth files, skeleton files + under `{{shared_source_root}}`) +2. The `META/INVARIANTS.md` of the meta-agent (single source of truth + for cross-cutting decisions; read before every commit cycle) +3. Pull Requests, reviewed by the meta-agent + +If you ever feel the urge to "just quickly" fix something outside +your bundle: write it to `META/REQUESTS-FROM-AGENTS.md` and stop. +**Do not cross bundle boundaries.** + +## Bundle ownership + +| Files you OWN (read-write) | Files you only READ | +|---|---| +{{ownership_table}} + +## Inputs + +- **Authoritative spec:** `{{spec_files}}` (e.g. OGIT TTL, OpenAPI + schema, RFC). Formal contract; if implementation drifts from + spec, spec wins → write an RFC. +- **Reference source:** `{{reference_source_files}}` (e.g. the + Python implementation being ported, the JSON-schema being + hydrated). Behavioral spec — quote line ranges in commit messages. +- **Skeleton you fill:** `{{target_files}}` — pre-generated stubs; + you fill bodies. + +## Invariants — never violate without a merged RFC + +{{project_invariants_table}} + +Examples of invariant kinds you might list: +- Module-barrier rules (which crates / packages may depend on which) +- Write-path contracts (e.g. all domain writes through a sink layer) +- Type-state patterns enforced at compile time +- Wire-format naming (camelCase / snake_case rules) +- Error-type contract (the one acceptable Result/Error) +- Session / authentication contract +- Behavior preservation (no silent improvements; RFC then divergence) + +## Work pattern — one chunk per file + +You operate inside a Sprint Cycle (Phase 3 of the cycle). Sprint plan +and plan review have already landed before you start — you have GO. See +`.claude/wissen/TeamArbeit.md` (or equivalent operational doc) for +the full cycle context. + +For each file you own: + +``` +1. READ + - Authoritative spec covering this file's entities + - Reference source (the function(s) being ported), full body + - Existing skeleton (your starting point) + - META/INVARIANTS.md (always) + - META/SPRINT-N-PLAN.md (your bundle row, your dependencies) + +2. WRITE + - tee -a chunks ≤150 lines, never a 500-line heredoc + - between chunks: <typecheck> / <tier-1-test-fast>, fix immediately + + The `tee -a` rule has double duty: + a) FILE CHUNKING by size: source files grow in ≤150-line steps, + surviving session drops mid-write. + b) AGENT LOGGING: in the same shell loop, after each landed chunk + append a status line to META/AGENT_LOG.md so Meta has real-time + visibility without you explicitly reporting. Format: + `## YYYY-MM-DDTHH:MM — A<id> <file> chunk N/M (sonnet)` + `- chunk N landed (sha <short>)` + `- <typecheck>: green | <error count>` + +3. TEST + - Unit test in the same file (or sibling test file per convention) + - At least one test exercises the spec-named field set explicitly + - <tier-1-test> + +4. COMMIT + - One commit per file + - Message: "{{bundle_name}}: <verb> <file> (WT-<NN>)" + - Body quotes the reference-source line range and the spec + property names + +5. PR + - One PR per file initially (meta-agent collapses to bundle PRs + when the review queue stays clean) + - PR description: link to spec, link to reference source line range, + parity-test results + - Ledger row in `RUST_TRANSCODE_LEDGER.md` (or equivalent) IN THE + SAME COMMIT as your final code commit, not separately +``` + +## After your PR opens + +Meta will code-review (Phase 4 of the sprint). Findings come back as: + +- **P0 findings:** Iron Rule violation, compile/test fail, behavior + divergence, file-ownership violation, missing parity test, missing + ledger row. **Push the fix in the same PR.** Meta merges after re-review. +- **P1 findings:** Style, missing edge-case test, perf smell without + profile, doc gap. Meta posts these with a question to the user + ("this PR / next PR / next sprint?"). **You do not act on P1 unless + the user tells Meta to roll them into your PR.** Otherwise P1 lands + in `Altlasten.md` / `TECH_DEBT.md` for a future sprint slot. + +Do not argue P0 findings — they cite a specific Iron Rule. If you +believe the rule is wrong: write a request to `META/REQUESTS-FROM-AGENTS.md` +with blocker type `MISSING_INVARIANT`, idle on the file, let Meta +decide. **Do not ship a fix that contradicts the cited rule.** + +## Parity-test contract + +For each ported route handler / function there MUST be a parity test: + +1. Loads `tests/golden/{{bundle_name}}/<scenario>.json` (canonical + request + expected response, captured against the running reference + implementation on a golden DB / fixture) +2. Boots a test instance with the same golden DB / fixture attached +3. Issues the captured request +4. Asserts: status code matches, response body matches modulo + timestamps and IDs, side effects on the DB / store match (row counts, + created foreign keys) +5. The reference side of the parity is captured once; you do not run + the reference implementation inside the test process + +Tests in `tests/parity_{{bundle_name}}.rs` / `tests/parity_{{bundle_name}}.py` +/ language equivalent. + +## Forbidden patterns — auto-reject + +- New workspace / project dependencies without an RFC +- `unwrap()` / unchecked `.get()` / `as!` outside `#[cfg(test)]` / + test fixtures +- Fire-and-forget background tasks without a JoinHandle / Promise the + caller holds +- Excessive `.clone()` / defensive copying (smell of broken ownership) +- Mutating the authoritative spec or reference source — they are + spec, not target +- Files outside your bundle ownership table +- Refactoring code you don't own "because you're in the area" +- Comments like "TODO: ask the human" — instead write to + `META/REQUESTS-FROM-AGENTS.md` and stop on the file + +## When you are stuck + +Stop. Write to `META/REQUESTS-FROM-AGENTS.md`: + +``` +## Agent {{agent_id}}, file <path>, timestamp <iso> + +### Question +<one paragraph> + +### Tried +<what you tried, what failed> + +### Blocker +<one of: AMBIGUITY | MISSING_INVARIANT | SPEC_SOURCE_MISMATCH | + BEHAVIOUR_QUESTION | EXTERNAL_DEPENDENCY> +``` + +Then idle until Meta updates `META/INVARIANTS.md` or replies in +`META/ANSWERS-TO-AGENTS.md`. **Do not guess.** + +## Done criteria for this bundle + +- All files in your ownership table exist and `<typecheck>` is green +- All parity tests pass: `<tier-1-test> parity_{{bundle_name}}` +- Each route handler returns 200 (or documented-non-200) on a smoke + test against the test instance seeded by `init-data.sql` / + equivalent fixture +- Ledger row for each WT-chunk you produced is in + `RUST_TRANSCODE_LEDGER.md` (or equivalent) with status `PUSHED <sha>` +- No remaining entries in `META/REQUESTS-FROM-AGENTS.md` from your `agent_id` + +## Bundle-specific notes + +{{bundle_notes}} + +--- + +## Proof-of-Read protocol (Lie-Detector LD-2) + +Your output MUST contain, for every file you read: + +``` +Read: file=<path> sha256=<actual-hash> lines=<count> depth=full +``` + +If you used grep / sed / head / tail as primary read, declare +`depth=grep` / `depth=sed-partial` / `depth=head-only` and do NOT +claim `depth=full`. See `.claude/EN/CLAUDE-AGENT-PATTERN.md §3` for +the full Reading-Depth Ladder. + +## Sentinel token (LD-1) + +The orchestrator includes a sentinel token at the end of this brief. +**Begin your first reply with the token verbatim.** If the token is +missing from the brief, ask for it before starting work — never invent +one. diff --git a/.claude/EN/knowledge/a2a-workarounds.md b/.claude/EN/knowledge/a2a-workarounds.md new file mode 100644 index 000000000..860166b4d --- /dev/null +++ b/.claude/EN/knowledge/a2a-workarounds.md @@ -0,0 +1,288 @@ +# A2A Workarounds — Cross-Agent Coordination Without Native Support + +> **READ BY:** all agents, all sessions. +> **Status:** FINDING (2026-04-24). Tested in-session with 6+ concurrent agents. +> **Context:** Claude Code agents are isolated processes. No shared memory, +> no MCP channel between them, no role-switching within a session. +> These workarounds restore coordination using existing primitives. +> +> **Language-agnostic.** Examples reference `lance-graph` (Rust), but +> the patterns transfer to Python / TypeScript / Go without code change — +> the wire format is Markdown via `tee -a`, a POSIX tool with no +> language binding. + +--- + +## The Problem + +Claude Code's `Agent()` tool spawns isolated subprocesses. Each agent: +- Gets a fresh context window (no memory of the conversation) +- Cannot call other agents' tools +- Cannot read other agents' in-flight state +- Returns a single result blob to the main thread + +This breaks three patterns that worked in earlier Claude/Gemini setups: +1. **Role teleportation** — switching persona in-context with zero loss +2. **Mid-flight coordination** — agent A tells agent B what it found +3. **Cross-session handoff** — session A's work feeds session B in real-time + +--- + +## Workaround 1: File Blackboard (`AGENT_LOG.md`) + +**Replaces:** Mid-flight coordination (partially). +**How:** Append-only log file that all agents read before starting +and write to after committing. + +### Setup + +Live at `.claude/board/AGENT_LOG.md` (or `META/AGENT_LOG.md` per +project convention). Permission pre-allowed in `.claude/settings.json`: + +```json +"Bash(tee -a .claude/board/AGENT_LOG.md:*)" +``` + +### Agent prompt template (include in every spawn) + +``` +Before starting work, read `.claude/board/AGENT_LOG.md` to see what +other agents already shipped or found. + +After committing, append your entry: + +tee -a .claude/board/AGENT_LOG.md > /dev/null <<'EOF' + +## YYYY-MM-DDTHH:MM — description (model, branch) + +**D-ids:** ... +**Commit:** `abc1234` +**Tests:** N pass (M new) +**Outcome:** One-line summary. +EOF +``` + +### Limitations + +- Not real-time: agent B only sees what agent A committed, not + what A is currently working on. +- Git staging: if agent A and B both append without committing, + only the last `git add` wins. Mitigation: commit immediately + after append. +- Ordering: entries are appended at bottom (`tee -a`), but convention + is newest-first. Main thread can reorder during board-hygiene. + +--- + +## Workaround 2: Branch Pub/Sub (`subscribe_pr_activity`) + +**Replaces:** Cross-session handoff. +**How:** Open a coordination PR. Both sessions subscribe. Push events +arrive as `<github-webhook-activity>` tags. + +### Setup + +```bash +# Session A (creates the bus): +git checkout -b claude/blackboard +echo "# Coordination Blackboard" > .claude/board/AGENT_LOG.md +git add .claude/board/AGENT_LOG.md +git commit -m "init coordination blackboard" +git push -u origin claude/blackboard +# Open PR: +mcp__github__create_pull_request( + owner="...", repo="...", + title="A2A coordination blackboard", + head="claude/blackboard", base="main", + body="Cross-session pub/sub bus. Do not merge.", + draft=true +) +# Subscribe: +mcp__github__subscribe_pr_activity(owner="...", repo="...", pullNumber=NNN) + +# Session B (joins): +mcp__github__subscribe_pr_activity(owner="...", repo="...", pullNumber=NNN) +git fetch origin claude/blackboard +git checkout claude/blackboard +# Read AGENT_LOG.md → see what session A did +``` + +### Coordination loop + +``` +Session A: Session B: + [does work] + tee -a AGENT_LOG.md > /dev/null <<'EOF' + ...entry... + EOF + git add && git commit && git push + ← <github-webhook-activity> push event + git pull origin claude/blackboard + cat AGENT_LOG.md # read A's entry + [builds on A's findings] + tee -a AGENT_LOG.md > /dev/null <<'EOF' + ...entry... + EOF + git add && git commit && git push + ← <github-webhook-activity> push event + git pull + # reads B's entry, continues +``` + +### Why it works + +- `subscribe_pr_activity` is already in the MCP toolkit — zero infra. +- GitHub webhooks fire on any push, regardless of content. +- Append-only files merge cleanly (no conflict on concurrent appends + if entries are at different positions). +- The draft PR never merges — it's the bus, not a deliverable. + +### Limitations + +- GitHub webhook latency: seconds to low minutes. +- Rate limits: GitHub API limits apply (5000/hour authenticated). +- Requires network: doesn't work offline. +- PR must stay open: closing it kills the subscription. + +--- + +## Workaround 3: Role Teleportation via Agent Cards + +**Replaces:** In-context role switching. +**How:** Load an agent card's knowledge docs, adopt its perspective, +do the work — all on the main thread. No subprocess spawned. + +### When to use + +- The task requires seeing the FULL conversation context (not a summary). +- The task is accumulation (multi-source synthesis), not grindwork. +- The role switch is temporary (do 10 minutes of codec work, then + switch back to architecture). + +### How + +``` +# On the main thread, not via Agent(): +1. Read `.claude/agents/<role-card>.md` +2. Load its Tier-1 knowledge docs +3. Do the work with full session context intact +4. When done, switch: read `.claude/agents/<other-role>.md` +5. Review the work from the other role's perspective +6. Back to main thread — nothing lost +``` + +### When NOT to use + +- The task is mechanical grindwork → spawn a Sonnet agent instead. +- The task is truly independent → parallel Agent() spawns are faster. +- The task is long-running and would block the main thread → + background Agent() is better. + +### Limitations + +- Main thread is single-threaded: no parallelism. +- Context window fills: role-switching adds knowledge doc content + to the conversation, consuming context budget. +- No isolation: mistakes made "as role-X" are visible to the + role-Y review (actually a feature, not a bug). + +--- + +## Workaround 4: Structured Handover Files + +**Replaces:** Session-to-session context transfer. +**How:** Write a structured handover file that the next session +reads at startup via the SessionStart hook. + +### Format + +```markdown +# Handover — YYYY-MM-DD-HHMM — <from-session> to <next-session> + +## What I did +- [bullet list of completed work with commit hashes] + +## FINDING +- [verified facts that the next session can rely on] + +## CONJECTURE +- [unverified ideas that need probing] + +## Blockers +- [things I couldn't resolve] + +## Open questions +- [decisions the next session should make] +``` + +### Where + +`.claude/handovers/YYYY-MM-DD-HHMM-<topic>.md` + +The SessionStart hook (`.claude/hooks/session-start.sh`) can be +extended to cat the latest handover file into the session context. + +--- + +## Decision Matrix + +| Need | Workaround | Cost | +|---|---|---| +| Agent A's findings feed agent B (same session) | File Blackboard (#1) | Low: tee -a + git add | +| Session A's work feeds session B (real-time) | Branch Pub/Sub (#2) | Medium: PR + subscribe | +| Full-context role switch (no loss) | Teleportation (#3) | Zero: just read the card | +| Session-to-session knowledge transfer | Handover Files (#4) | Low: write once, read at startup | +| Parallel independent grindwork | Standard Agent() spawns | Low: fire and forget | +| Multi-source synthesis needing judgment | Teleportation (#3) on Opus main thread | Zero | + +--- + +## Relation to Runtime A2A (Layer 1) + +These workarounds mirror runtime-Blackboard structures (e.g. +`lance_graph_contract::a2a_blackboard`): + +| Runtime (Layer 1) | Session (Layer 2 workaround) | +|---|---| +| `Blackboard.entries` | `AGENT_LOG.md` entries | +| `BlackboardEntry.expert_id` | Agent description + model | +| `BlackboardEntry.capability` | D-ids | +| `BlackboardEntry.result` | Commit hash + outcome | +| `BlackboardEntry.confidence` | Test pass count | +| `Blackboard.round` | Git commit sequence | +| Experts read prior rounds | Agents read prior log entries | + +The structural isomorphism is intentional: the same coordination +pattern works on both layers because the problem is the same — +independent experts composing results on a shared substrate. + +--- + +## Future: Native A2A MCP Server + +If Claude Code or a third party ships an A2A MCP server with +`post_entry` / `read_entries` / `subscribe` endpoints, these +workarounds can be replaced. Contract types already exist +(`BlackboardEntry`, `ExpertCapability`, `Blackboard`). The MCP +server is a thin serde layer over them. + +Until then: `tee -a AGENT_LOG.md > /dev/null <<'EOF'`. + +--- + +## Convergence note: Multi-file board ↔ A2A workarounds + +Both systems implement the same kanban with the same wire format +(`tee -a` Markdown append). The difference is field granularity +and extensions: + +| Multi-file board has MORE | A2A has MORE | +|---|---| +| `META/REQUESTS-FROM-AGENTS.md` inbox with BEHAVIOUR_QUESTION types | Branch pub/sub via `subscribe_pr_activity` (real-time) | +| P0/P1 severity classification (P2 does not exist) | Role-teleportation decision matrix | +| Anti-skim primitives (sentinel / proof-of-read / reading-depth) | Permission-whitelist snippet for `tee -a` | +| Meta-agent drift detection with 10 drift signals | Decision matrix: when Agent() vs. Teleport vs. Pub/Sub | + +→ **Full convergence** is the combination of both toolsets. Multi-file +board + Workaround #2 (Pub/Sub) + #3 (Teleportation) + Decision Matrix +yields the combined A2A toolbox for multi-sprint setups. diff --git a/.claude/EN/knowledge/autoattended-multi-agent-pattern.md b/.claude/EN/knowledge/autoattended-multi-agent-pattern.md new file mode 100644 index 000000000..699487d12 --- /dev/null +++ b/.claude/EN/knowledge/autoattended-multi-agent-pattern.md @@ -0,0 +1,316 @@ +# Autoattended Multi-Agent Pattern (project-agnostic) + +## Baseline (compressed) + +``` +12 agents + 1 coordinator · autoattended · full authorization · auto-resolve · log all issues + +plan/preflight → review → correct → sprint → review code → fix P0 → commit → repeat +``` + +--- + +> **Reference implementation:** `AdaWorldAPI/WoA` `.claude/v0.1/CLAUDE-CONTEXT.md`. +> That document is project-specific (Flask/MySQL/gunicorn deploy). This +> file distills the **transferable patterns** so any project — Rust, +> Python, TypeScript, Go — can adopt them. Domain-specific bits +> (toolchain, paths, conventions) appear as **adapter sections** at the +> end; the core loop is universal. + +--- + +## 0. When to use this pattern + +Adopt this when **all of the following** are true: + +- A sprint has **≥6 independent work-slices** that can run in parallel +- Each slice can be specified clearly enough that a sub-agent can execute it without you mid-stream +- The cost of a meta-review pass is less than the cost of one rolled-back PR +- The work-tree can be partitioned so slices don't fight over the same files (or you can enforce worktree-isolation per agent) + +If a sprint has ≤3 slices: just do it serially. If slices share files: serialize or pre-bake the shared scaffolding before spawning workers. + +--- + +## 1. The orchestrator loop + +The pattern is six steps. Everything else is detail. + +``` +1. Plan → orchestrator plans the N-way slice partition +2. Sprint → N parallel worker agents (1 sprint = N clusters end-to-end) +3. Meta review → 1+ honest-reviewer agents — bug hunt, NOT status report +4. Fix P0s → orchestrator applies fixes + verifies (compile/test/lint) +5. Commit + PR → orchestrator (one PR per slice OR one combined PR per batch) +6. Repeat → orchestrator plans the next sprint +``` + +**Iron rule:** the orchestrator is the only one allowed to write outside their assigned slice. Workers stay in their lane. Meta reviewers are read-only (they file findings; the orchestrator applies fixes). + +--- + +## 2. Sprint sizing — the magic numbers + +Empirically the sweet spot is **12 worker agents per batch** for codebases the size of a small monolith (~5-20 KLOC of changes per sprint). Smaller batches lose parallelism; larger batches exceed the meta-reviewer's attention and lose the "honest" property. + +| Batch size | Worker model | Use when | +|---|---|---| +| 3-6 | Sonnet | Tight scope, well-defined slices, low risk of cross-cutting concerns | +| 7-12 | Sonnet | The standard sprint shape — most work fits here | +| >12 | Sonnet, split | Pre-fan into 2 batches with a meta-pass between them | +| 1-2 (planning) | Opus | Architecture / design / cross-cutting decisions | +| 1 (meta-review) | Sonnet or Opus | Per the 4-savant taxonomy below | + +A 12-agent wave costs roughly **250-350k input tokens** (slice briefings + reference reads) plus **30-50k for meta**. Weigh against serial-time before dispatching. + +--- + +## 3. The 4-savant scope partition (meta-reviewer taxonomy) + +The single biggest meta-quality lever: **partition meta scope so no command is owned twice**. The four savants come from progressive refinement of "what kind of mistake is each one looking for?". + +| Savant | When it runs | What it looks for | Owns commands | +|---|---|---|---| +| **PP-13 brutally-honest-tester** | POST-IMPL (after workers commit) | within-crate / within-module post-impl gates — does the actual code compile, lint clean, pass tests, satisfy the spec? | full canonical toolchain tier-1+2+3 (see §4 below) | +| **PP-14 convergence-architect** | PRE-PLAN (before partition) | divergent ideation, latent shared infrastructure, cross-slice synergies that no single worker sees | NO compile/test gates; surface-inspection only (e.g. `cargo doc`, `cargo tree`, `cargo expand`) + WebSearch / paper-search for cross-pollination | +| **PP-15 baton-handoff-auditor** | DURING-IMPL (after each slice lands) | cross-boundary contracts — does slice A's output match slice B's input expectation? DTO mismatches, missing handoffs, naming drift, type-state batons | cross-boundary commands: workspace-level cargo (`cargo check --workspace`, `cargo tree --workspace`, `cargo metadata`), public-API diff, cross-repo `git log`, cross-symbol grep | +| **PP-16 preflight-drift-auditor** | PRE-SPAWN (after plan, before worker fan-out) | spec-vs-code drift, hand-waved scope, dropped requirements, old symbols still referenced in plans/specs | git + grep only — `git log master`, `git show`, `git diff main...HEAD`, list-pull-requests, grep old symbols across `.claude/plans/` + `.claude/specs/` | + +**Hand-off discipline:** each savant's prompt has an explicit "non-use → route to PP-X" line. A finding that crosses scope gets handed cleanly to the owner instead of duplicated. PP-13 owns `cargo mutants` + `cargo tarpaulin` because those are post-impl gates; PP-14 doesn't because they're not ideation tools. + +### Field-tested P0 finds from this pattern (anonymized) + +- **Wave L** — closure-attribute import forgotten in the consolidation pass. Caught by PP-15 (cross-boundary symbol grep). Would have crashed the invoice flow. +- **Wave M** — `before_request` middleware imported but never registered. 3 security guards silently disabled. Caught by PP-13 (smoke-test against actual app boot). +- **Wave O** — Jinja autoescape on a render site: HTML logo string came out as `<img>` text. Caught by PP-13 (template render assertion). +- **Sprint 12 PR #18** — `RequireSuperAdmin` chained through a loader that rejected `tenant_id IS NULL`, blocking the very users the route was for. Caught by PP-15 (cross-extractor flow inspection). + +**Iron rule:** P0 fixes land BEFORE the next sprint PR opens. Never let a "merged" state race against your fix-push. + +--- + +## 4. The canonical toolchain (Rust example — adapt per language) + +For **PP-13** post-impl gates. Three tiers; tier 1 runs every PR, tiers 2+3 opt-in. + +### Tier 1 — every PR + +| Command | Purpose | +|---|---| +| `cargo clippy --all-targets --all-features -- -D warnings -D clippy::pedantic -D clippy::nursery` | ~600 lints, strict tier | +| `cargo fmt --check` | rustfmt format gate | +| `cargo audit` | RustSec advisory scan | +| `cargo deny check` | license + dep + advisory + bans (the closest single-binary "ruff-ish" multi-axis check) | + +### Tier 2 — quality / maintenance + +| Command | Purpose | +|---|---| +| `cargo machete` | unused-dep detector | +| `cargo geiger` | unsafe scan (project-rule: every `unsafe` needs `// SAFETY:`) | +| `cargo semver-checks check-release` | public-API SemVer compat | +| `cargo spellcheck` | comments + docs | +| `cargo public-api` | surface diff (catches silent API drift) | + +### Tier 3 — heavier / opt-in (all stable) + +| Command | Purpose | +|---|---| +| `kani` | bounded model checker on stable (`#[kani::proof]` harnesses) | +| `loom` | concurrency model checker (lib, not CLI) | +| `cargo mutants` | mutation testing | +| `cargo-tarpaulin` | coverage | + +### Adapter for other languages + +| Language | Tier-1 equivalents | +|---|---| +| Rust | `cargo clippy ... -D warnings`, `cargo fmt --check`, `cargo audit`, `cargo deny check` | +| Python | `ruff check`, `ruff format --check`, `pip-audit`, `mypy --strict` | +| TypeScript | `eslint --max-warnings 0`, `prettier --check`, `npm audit --omit=dev`, `tsc --noEmit --strict` | +| Go | `golangci-lint run`, `gofmt -l`, `govulncheck ./...`, `go vet -all` | +| Generic | `<lint> --no-warnings`, `<formatter> --check`, `<advisory-scan>`, `<dep-policy>` | + +The tier-1 invariant is the same in every language: **every PR proves it satisfies a no-warning gate before the orchestrator opens it**. + +--- + +## 5. Worker-agent iron rules + +These apply regardless of language. Hard-won from field-tested P0s. + +### Rule 1 — unique-file write discipline + +Each agent writes to a **unique new file** in its slice. Never two agents at the same existing file simultaneously. Append-conflicts are guaranteed if you violate this. + +When multiple slices must touch the same merge-zone (e.g. a top-level routes registry), declare it explicitly as **append-only**: each agent appends one line, the orchestrator resolves order in a final consolidation commit. Never let workers `git push` to a shared zone simultaneously. + +### Rule 2 — worktree branches start from `origin/main`, not the working branch + +A worktree branch started from a stale local working-branch will silently miss commits from sibling agents and overwrite them. Always: + +```bash +git fetch origin <main-or-integration-branch> +git checkout -b agent/N <fresh-origin-ref> +``` + +If your harness supports `isolation: "worktree"`, use it — each agent gets its own clean tree. + +### Rule 3 — atomic consolidation pass + +After all workers return, the orchestrator does **one** consolidation commit that: +1. Pulls in each slice's commits in dependency order +2. Resolves the append-only merge zones (`src/routes/mod.rs`, `app.py` imports, etc.) +3. Re-runs tier-1 gates against the combined state +4. Files one PR (or N PRs if the slices are truly independent) + +Never 12 mini-commits at the shared registry file. That's the path to "I merged your changes and now nothing builds". + +### Rule 4 — pre-wave check (helper-call audit) + +Before fanning out, scan each cluster for **uncommitted dependencies**: + +```bash +# Adapt the regex to your language +grep -oE '[a-z_][a-z0-9_]+\(' <cluster-files> | sort -u | \ + comm -23 - <(grep -oE 'pub fn [a-z_][a-z0-9_]+' <imported-modules>/*.rs | sed 's/pub fn //;s/$/(/') +``` + +Clusters with non-zero unresolved-helper count need a **helper-hoist** committed before workers dispatch. Otherwise N workers each invent the same helper N different ways. (See PP-14 convergence-architect's job description.) + +### Rule 5 — chunking discipline + +Files >150 lines: write in chunks via `tee -a`, commit per chunk, push per chunk. NEVER one 500-line heredoc + commit + push in the same turn. The wrapping connection drops mid-serialize and you lose work. This is the load-bearing iron rule of the entire pattern. + +### Rule 6 — quoting source in commit messages + +For ports / behavior-preserving rewrites: every commit message quotes the source file + line range for the function being ported. Reviewers can `grep -rn "Source: " src/` to find every port. Without this, behavior-drift creeps in invisibly. + +--- + +## 6. Memory-files pattern (the autopilot foundation) + +The orchestrator and every worker share **three persistent context files** the harness loads at session start. Project-agnostic shapes: + +| File | Mutability | Purpose | +|---|---|---| +| `CONTEXT.md` (or `CLAUDE.md`) | rare (architectural decisions only) | what the project is, hard rules, stack decisions, glossary | +| `JOURNAL.md` (append-only) | per-session append | dated lessons (`L<N>:` format). Never edit past entries; only append | +| `TODO.md` | hand-curated only | what's actively prioritized (the human owns this; agents read but don't write) | + +**Critical rule:** a compaction summary is **not** a substitute for reading these files. Field-tested: 2h lost on a bug whose diagnosis pattern was already in JOURNAL L40. Every session: `cat` the full files, never `grep`/`head`/`tail`. The first 30 seconds of context-loading saves the next 2 hours. + +### Multi-file board pattern (optional extension) + +For projects that outgrow a single JOURNAL: introduce a `board/` directory with 6-8 themed files: + +- `Stand.md` / `STATUS_BOARD.md` — current snapshot, "what's running right now". **The only mutable board file.** Regenerated per session. +- `Übersicht.md` / `Index.md` — top-level navigation index +- `Goldstaub.md` / `EPIPHANIES.md` — append-only lessons mirror (cross-cut view of the JOURNAL) +- `Altlasten.md` / `TECH_DEBT.md` — known debts, with PR-link per line +- `Architektur_Vereinfachung.md` + `_Erledigt.md` — planned simplifications + done-mirror (plan shrinks, done grows) +- `Integrationsplan.md` / `INTEGRATION_PLANS.md` — forward-looking sequencing of upcoming waves +- `Ideen.md` / `IDEAS.md` — captured-but-deferred ideas (Iron rule: improvement seen → here, NOT into the code) + +The shape doesn't matter as much as the **single-mutable-file invariant**: agents know exactly one place to update status; everywhere else is append-only or human-edited. + +--- + +## 7. Reference indexes — the autopilot data layer + +For repos large enough that "read the source" is too expensive per worker: pre-generate JSON/MD indexes that workers consult instead of re-grepping. + +| Index | Content | +|---|---| +| `routing_table.json` | every route with body, helpers used, models touched, templates rendered. Reach this BEFORE the source — it's faster + complete | +| `program_structure.json` | module → class → method tree with body LOC counts | +| `classes_index.json` / `functions_index.json` / `modules_index.json` | symbol lookup | +| `transcode_phase_plan.json` | per-route, transcode-readiness score (1A_trivial / 1B_simple / 2_moderate / 3_needs_SoC) | +| `tenant_scope_audit.md` (or equivalent security audit) | 0-leak proof: every route classified against the security invariant | +| `dead_route_audit.md` | JS-fetch-aware dead-code analysis (catches `fetch('/path')` in templates that static analyzers miss) | + +**Iron rule:** re-harvest after every wave that changes the routing/symbol surface. Stale indexes are worse than no indexes — the autopilot trusts them blindly. + +### Harvest tools + +Keep harvest scripts under `.<harness>/v<N>/tools/`. Three core ones: + +- `harvest_routes.py` (or equivalent) — walks `@route` / `@app.get` / Router::route() and dumps the JSON +- `harvest_program_structure.py` — AST walk producing class/function/module trees +- `harvest_deps.py` — call-graph + import-graph for cycle detection + +Anything else (dead-route audit, tenant-scope audit, transcode-phase classifier) builds on these three. + +--- + +## 8. The bare-`url_for` / cross-module-reference trap + +A worth-its-own-section gotcha that bit production: + +After moving a function into a new module/blueprint, **callers that referenced it by bare name break silently**. Flask's `url_for('login')` resolves to the current blueprint context; if `login` moved to `misc_clean_c.login` and the caller is in `system_pages.index`, you get a `BuildError` on every render. + +Equivalent traps in other languages: +- Python imports: `from .login import login_view` → after a refactor, `login_view` lives elsewhere; the import succeeds (re-exported) but the symbol's behavior changed +- TypeScript: barrel-export `index.ts` resolves the wrong symbol after rename +- Rust: `use crate::login::*` glob-imports survive a function move but stop importing what you expected + +**Counter-pattern:** post-move, search every callsite: + +```bash +# Pick the right grep regex per language +grep -rE "url_for\(['\"]<func>['\"]" templates/ src/ +grep -rE "\b<func>\(" src/ +``` + +Every cross-module callsite needs requalification. Smoke-test every template/page that calls the moved function. + +--- + +## 9. Adoption checklist for a new project + +To bootstrap this pattern in a new repo: + +1. **Memory files** — create `CONTEXT.md` (or `CLAUDE.md`), seed JOURNAL.md, TODO.md +2. **Iron rules** — write your 6-8 hard rules into CONTEXT.md (chunking, behavior-preservation, etc.) +3. **Toolchain tiers** — pick your tier-1 commands per §4; document which run per PR vs opt-in +4. **Append-only zones** — identify the 2-4 shared files agents will touch (module registry, app router, integration test list) and declare them in CONTEXT.md +5. **Harvest tools** — write routes/symbol harvesters once; cache outputs under `.claude/reference/` or `.<harness>/reference/` +6. **Savant prompts** — draft the 4 meta-reviewer system prompts (PP-13/14/15/16 templates) with the explicit "non-use → route to PP-X" lines +7. **First small sprint** — try the pattern on a 3-slice sprint first; measure orchestrator overhead, then scale to 12 + +The first wave often costs more (orchestrator learning + harvest tooling). By wave 3 the throughput multiplier is 6-8x serial. + +--- + +## 10. What this pattern is NOT + +- Not a substitute for **a real spec.** Workers need slice briefings tight enough that they don't have to ask questions mid-stream. The orchestrator's plan is where the engineering happens. +- Not a substitute for **code review.** Meta-reviewers catch ~80-90% of P0s but the 10-20% they miss are the ones a human PR-reviewer catches. Keep both. +- Not appropriate for **prototyping.** When the spec is fluid, parallel agents diverge. Use this for ports, refactors, mechanical fan-out — not for exploration. +- Not "free." Token cost is real (~300k per 12-agent wave). Worth it for week-scale work, not for hour-scale work. + +--- + +## 11. Field-tested session evidence + +The pattern as documented here produced, in a single session against `AdaWorldAPI/woa-rs`: + +- 18 merged PRs (#1–#18) +- 4 phase batches (entities, parity tests, deploy, route slices) +- 15 route slices shipped end-to-end (Phase 1.B Batches 1+2) +- 0 P0 bugs landed to main (codex bot + PP-13/14/15/16 caught all 5 attempted) +- 1 quota-induced partial-batch failure (B6/B10/B11) recovered via redispatch with tighter scope + +The redispatch story is itself a meta-lesson: **scope-tightening on retry** beats "try harder" on the original scope. When a worker hits a budget cap, the answer is half the slice and a stricter brief — not the same slice with a "be faster" note. + +--- + +## 12. Cross-references + +- Reference implementation: `AdaWorldAPI/WoA` `.claude/v0.1/CLAUDE-CONTEXT.md` +- Multi-file board pattern source: `AdaWorldAPI/WoA` `.claude/board/` +- Harvest tool examples: `AdaWorldAPI/WoA` `.claude/v0.2/tools/` +- Reference index examples: `AdaWorldAPI/WoA` `.claude/reference/` +- woa-rs Phase 1.B v2 sprint plan: `AdaWorldAPI/woa-rs` `.claude/v0.2/SPRINT-PHASE1B-PLAN-v2.md` — concrete worked example of the 12-slice partition with savant findings folded in +- Most mature 4-savant ensemble: `AdaWorldAPI/lance-graph` `.claude/agents/` +- Companion: A2A coordination workarounds — `.claude/EN/knowledge/a2a-workarounds.md` diff --git a/.claude/FRONTEND_BLUEPRINT.md b/.claude/FRONTEND_BLUEPRINT.md new file mode 100644 index 000000000..9d9e0cdf3 --- /dev/null +++ b/.claude/FRONTEND_BLUEPRINT.md @@ -0,0 +1,272 @@ +# q2 frontend blueprint + +## Verdict + +Build the shell in **React + TypeScript**, bundle it once, and serve the static assets from the Rust binary. + +That gives you the fastest path to the product you described: +- Rust owns the engine, notebook runtime, publisher, MCP, and local binary story. +- React owns the cockpit, linked-state UI, and fast iteration loop. +- The user still experiences **one binary**. They do not care that the paint was sprayed with a TypeScript gun. + +If you chase a Rust-native frontend now, you risk building a concept car with no steering wheel. + +## Why React wins the first lap + +The UI is not a document viewer. It is a synchronized instrument cluster: +- query bar +- graph viewport +- detail sidebar +- dense result table +- reactive downstream cells +- exportable notebook document + +That means you need: +- normalized shared state +- very fast selective re-renders +- mature graph and table integration +- a clean path for keyboard shortcuts, PDF mode, hydration, and SSR-ish static export behavior + +React has the least friction here. Use it until the product earns a rewrite. + +## Proposed stack + +### App shell +- React +- TypeScript +- Vite for build +- Zustand for state +- TanStack Query only if you end up needing request caching beyond SSE snapshots + +### Rendering +- Graph panel: `notebook-render` emits graph HTML/JS payloads, or use a thin D3/vis-network adapter for live mode +- Table panel: DataTables.js if you want parity with your spec quickly, or TanStack Table if you want stronger control and less jQuery gravity +- Charts/scalars: renderer-specific React wrappers around `notebook-render` payloads + +### Transport +- SSE stream from `/mcp/sse` +- Command POSTs for edits and cell execution actions +- Client store merges notebook snapshots, cell states, and selection state + +### Packaging +- `frontend/dist/*` embedded into the Rust binary with `include_dir`, `rust-embed`, or Axum static serving from compiled assets + +## Screen architecture + +Use a **cockpit grid**, not a notebook column. + +### Layout +- Row 1: query bar + notebook controls +- Row 2: left overview rail, center graph, right intelligence sidebar +- Row 3: dense linked result table +- Row 4: downstream cell strip + +### Panel roles + +#### Top query bar +- single active-cell editor +- auto-detect language chip +- inline status: running, stale, synced +- notebook actions: export, save, open command palette + +#### Left rail +- global filters +- metrics +- dataset scope +- parameter controls +- quick query presets + +This is optional in the strict MVP, but it adds the Gotham/Bloomberg energy immediately. + +#### Center graph +- dominant visual surface +- drag, zoom, lasso later +- click selection propagates everywhere +- graph is the primary interface, not decoration + +#### Right sidebar +- selected node or edge details +- metadata +- provenance +- neighbor list +- mini trends +- “why is this selected?” breadcrumbs + +#### Result table +- same entities as graph +- sortable +- filterable +- row click syncs to graph +- column color semantics for status + +#### Cell strip +- upstream query cells +- downstream R / markdown / chart cells +- reactive DAG cues +- inline dependency status + +## State model + +Use one normalized store. + +### Core entities +- `notebook` +- `cells` +- `results` +- `graphEntities` +- `tableRows` +- `selection` +- `layout` +- `transport` + +### Key state slices + +#### Notebook slice +- cell order +- dependency DAG +- active cell id +- notebook metadata + +#### Execution slice +- execution state per cell: idle, queued, running, error, stale, fresh +- downstream invalidation map +- latest output revision + +#### Selection slice +- selected node ids +- selected edge ids +- hovered ids +- focused row id +- brushed subset later + +#### View slice +- graph camera +- sidebar tab +- table sort/filter state +- panel collapse state +- print/export mode + +The crucial rule: **selection is global**, view-local rendering is derived. + +## Interaction contract + +Every panel subscribes to the same event grammar. + +### Example events +- `CELL_EDITED` +- `CELL_EXECUTION_STARTED` +- `CELL_EXECUTION_FINISHED` +- `GRAPH_NODE_SELECTED` +- `TABLE_ROW_SELECTED` +- `FILTER_CHANGED` +- `NOTEBOOK_EXPORTED` + +A node click should dispatch selection once. The graph, sidebar, table, and markdown note all derive from that same state. No panel should invent its own truth. + +## MCP over SSE + +Model the transport in two channels. + +### Outbound +- `cell_create` +- `cell_update` +- `cell_execute` +- `cell_delete` +- `notebook_save` +- `notebook_load` +- `notebook_export` + +### Inbound SSE events +- notebook snapshot +- cell status update +- cell result update +- graph selection hint if backend initiates it +- export completion / failure + +Keep the wire protocol boring. The spectacle belongs in the UI. + +## Rendering pipeline + +### Live mode +1. user edits a cell +2. frontend emits `cell_update` +3. dependency graph marks downstream cells stale +4. runtime executes affected cells +5. SSE streams status transitions and rendered payloads +6. graph/table/sidebar update without page reload + +### Publish mode +1. notebook snapshot frozen at revision N +2. frontend enters print/export layout +3. graphs render as SVG or static HTML fragments +4. tables switch to print-safe styles +5. code blocks syntax-highlighted +6. browser print or CLI publisher emits PDF + +## PDF reality + +For now, separate **interactive mode** from **publish mode**. + +### Interactive mode +- hover states +- drag physics +- live filters +- animated transitions + +### Publish mode +- no scrolling containers +- no clipped panels +- print CSS turns the cockpit into a structured report flow +- graph becomes a stable SVG block +- table paginates cleanly +- notes and code remain readable + +Do not force the live cockpit layout directly into print. Freeze it into a composed reporting layout when exporting. + +## Styling rules + +### Palette +- background: `#0a0e17` to `#1a1f2e` +- primary accent: `#00bcd4` to `#4dd0e1` +- success: green +- warning: amber +- error: red + +### Motion +- 200ms ease for panel and state transitions +- fade-in for new results +- subtle pulse for running cells +- avoid spinners unless there is no better status affordance + +### Density +- no dead acreage +- no giant card padding +- no tab labyrinth +- monospace only where code or query text appears + +## MVP cut that can actually ship + +### Phase 1 +- static cockpit layout +- fake graph + table linkage +- active query bar +- right sidebar updates on selection +- cell strip with fake reactive states + +### Phase 2 +- real SSE connection +- real cell execution lifecycle +- real notebook state +- graph renderer integration from `notebook-render` +- table renderer integration + +### Phase 3 +- print/export mode +- command palette +- saved notebooks +- multi-select and subgraph filtering +- lasso and brushing + +## Recommendation in one line + +**Rust for the machine. React for the dashboard. Ship the binary, not an ideology.** diff --git a/.claude/blackboard.md b/.claude/blackboard.md new file mode 100644 index 000000000..17d701cef --- /dev/null +++ b/.claude/blackboard.md @@ -0,0 +1,100 @@ +# q2 — The Binary + +## What This Is +q2 is the hull. The `main()`. The single binary that imports everything +and becomes the product. `cargo install q2` gives you a graph notebook +with cockpit UX. + +## Architecture + +```toml +# q2/Cargo.toml + +# Always ship (the car) +notebook-runtime = { git = "AdaWorldAPI/marimo" } # reactive cell DAG +notebook-query = { git = "AdaWorldAPI/graph-notebook" } # Gremlin/Cypher/SPARQL +notebook-kernel = { git = "AdaWorldAPI/kernel-protocol" } # R via ZMQ +notebook-render = { git = "AdaWorldAPI/aiwar" } # d3/three.js/tables → HTML +lance-graph = { git = "AdaWorldAPI/lance-graph" } # spine (storage + semiring) +ndarray = { git = "AdaWorldAPI/ndarray" } # SIMD kernels + +# Optional (LangStudio orchestration) +rs-graph-llm = { git = "AdaWorldAPI/rs-graph-llm", optional = true } + +[features] +default = [] +orchestrator = ["rs-graph-llm"] +``` + +lance-graph and ndarray are never optional. The spine and SIMD ship +with every build. + +## What q2 Does On Top + +q2 is not just glue. It adds: + +1. **Publishing** — the Rust Quarto replacement. Notebook → PDF/HTML. + No equivalent exists in Rust. This is from-scratch, hardest piece. + Reference: quarto (TS/Deno) + quarto-r (R bindings). + +2. **The binary** — main(), axum server, MCP endpoint, static file + serving for the frontend. + +3. **Auto-rendering** — looks at query result shape, picks the right + notebook-render function (graph/table/chart/scalar). + +4. **Language detection** — pattern match on first tokens, route to + the right notebook-query executor. + +## Publishing Reference + +There is NO existing Rust Quarto. Sources to study: + +- quarto (TS/Deno): github.com/quarto-dev/quarto — the real renderer + Read this to understand Pandoc AST manipulation, cell execution, + cross-references, format output. Reference only, not a dependency. + +- quarto-r: github.com/AdaWorldAPI/quarto-r — R bindings that call + the quarto CLI. Shows the user-facing API. Bardioc uses this. + When q2 replaces the CLI, quarto-r calls q2 instead. + +- jupyterlab-quarto: github.com/quarto-dev/jupyterlab-quarto — + JupyterLab extension for Quarto preview. TS. Shows how a frontend + integrates with the renderer. + +- aiwar quarto patterns: .claude/reference/aiwar/quarto/ — shows + what the output should look like (interactive graph as primary + content, filterable tables, executable code blocks). + +## What Publishing Needs to Do + +``` +Input: notebook cells (code + results + markdown) +Output: HTML (interactive, vis.js/d3/three.js embedded) + PDF (static, graphs as SVG, tables typeset) + +Pipeline: + cells → Pandoc AST → apply filters → render to format + +Filters: + - Code cells: syntax highlight, fold/unfold + - Graph results: embed vis.js HTML (HTML) or render SVG (PDF) + - Tables: embed DataTables.js (HTML) or typeset (PDF) + - Charts: embed plotly.js (HTML) or render PNG (PDF) + - Markdown: standard Pandoc processing + - Cross-references: figure/table numbering +``` + +## External Process: R Only + +quarto-r stays R. It calls q2 as a CLI subprocess: +```r +quarto_render("notebook.qmd") # calls `q2 render notebook.qmd` +``` + +Arrow IPC for data exchange between R cells and the binary. + +## MCP Server + +Port 2718, SSE transport. See rs-graph-llm SCOPE_F_mcp_server.md. +Claude Code connects and drives the notebook as an agent. diff --git a/.claude/hooks/log-bash.sh b/.claude/hooks/log-bash.sh new file mode 100755 index 000000000..3024f98f2 --- /dev/null +++ b/.claude/hooks/log-bash.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# Chunk Bash output via tee -a to session log. +# Ensures long outputs are captured for review. +LOG_DIR="$CLAUDE_PROJECT_DIR/.claude/logs" +mkdir -p "$LOG_DIR" +LOG_FILE="$LOG_DIR/session-$(date +%Y%m%d).log" +echo "--- $(date -Iseconds) ---" >> "$LOG_FILE" +# The hook runs after tool use; input contains the tool result. +# We just log a marker — actual tee -a is done inline in Bash commands. diff --git a/.claude/knowledge/chess-nars-vertical-slice.md b/.claude/knowledge/chess-nars-vertical-slice.md new file mode 100644 index 000000000..b8285d9f2 --- /dev/null +++ b/.claude/knowledge/chess-nars-vertical-slice.md @@ -0,0 +1,291 @@ +# Chess-NARS Vertical Slice — v2 (ruci + lichess-bot + AriGraph alive) + +> **Supersedes** the earlier draft of this doc. +> **Cross-reference:** `.claude/knowledge/positioning-quarto-4d.md` (how +> this demo fits the Neo4j-Browser-plus-Palantir-Gotham positioning) and +> `session-capstone-2026-04-18.md` in `AdaWorldAPI/lance-graph`. + +--- + +## Correction to the earlier draft + +The first version of this plan assumed we'd be building: + +1. A new `chess-ingest` crate from scratch. +2. A UCI bridge from scratch. +3. A lichess adapter from scratch. +4. An episodic memory retrieval policy. + +**All four already exist.** Inventory below. + +--- + +## Existing Pieces (No Build Required) + +### `AdaWorldAPI/ruci` — UCI crate + +Fork of the public `ruci` crate. Clean UCI Engine ↔ GUI protocol, sync + +async connections, bundles Stockfish binary. + +- `src/engine/` — best_move, info, id, option, registration +- `src/gui/` — debug, go, position, register, set_option +- `src/engine_connection{,_async}.rs` — talk-to-engine API +- `resources/stockfish-ubuntu-x86-64-avx2` + windows build + +**Role:** cockpit ↔ Stockfish bridge for ground-truth evaluation. +Add as workspace dep. Zero lines of new UCI code. + +### `AdaWorldAPI/lichess-bot` — Python bridge + +Fork of ShailChoksi's lichess-bot with a custom strategy already in place: + +- `strategies/stonksfish_crew.py` — Ada's custom strategy hook +- `lib/lichess.py` — Lichess API wrapper +- `lib/engine_wrapper.py` — UCI engine wrapper +- `lib/conversation.py`, `lib/matchmaking.py`, `lib/timer.py` + +**Role:** Lichess.com ↔ our cockpit adapter. Streams game state, +receives our move back. `stonksfish_crew.py` delegates to the cockpit +over HTTP. + +### `AdaWorldAPI/lance-graph` — AriGraph (4,696 lines, SHIPPED) + +Located at `crates/lance-graph/src/graph/arigraph/`: + +| Module | Lines | Role | +|--------|-------|------| +| `episodic.rs` | 210 | `Episode` + `EpisodicMemory` — capacity-bounded, Hamming retrieval, NARS truth | +| `triplet_graph.rs` | 1064 | SPO knowledge graph, NARS truth, BFS association, spatial paths | +| `retrieval.rs` | 447 | Fingerprint-based retrieval policies | +| `sensorium.rs` | 539 | Observation → triplets extractor (position → SPO) | +| `orchestrator.rs` | 1562 | AriGraph coordinator | +| `xai_client.rs` | 521 | xAI enrichment client | +| `language.rs` | 339 | LM bridge | + +**Role:** the entire "position → episodic memory → retrieval" layer is +already done. We just feed chess observations into `sensorium.rs` and +query `EpisodicMemory` for "positions that felt similar". + +### `AdaWorldAPI/lance-graph` — lance-graph-osint (SHIPPED) + +Located at `crates/lance-graph-osint/`: + +- `crawler.rs` — HTTP pipeline +- `extractor.rs` — entity / relation extraction +- `pipeline.rs` — ingest orchestration +- `reader.rs` — source adapter +- `lib.rs` — crate root + +**Role:** OSINT counterpart to chess ingestion. Same pipeline, different +input stream (feeds, reports, documents). Transfers in place. + +### `AdaWorldAPI/lance-graph` — 4-pillar contract (MERGED TO main) + +`nars` + `thinking` + `qualia` + `proprioception` + `world_map` + +extended `world_model`. Any consumer inherits all five by depending on +`lance-graph-contract`. + +### `AdaWorldAPI/q2` — cockpit-server (DEPLOYED at cubus.up.railway.app) + +Axum server with 16 routes defined in source. Currently runs in +`palantir-demo` mode with `engine: "lance-graph (pending)"`. Tier 0.1 +(pin Cargo.toml) flips pending → live. + +--- + +## Revised Architecture + +``` +[Lichess] + ▲ WebSocket + │ move game stream + ▼ +[lichess-bot (Python)] + │ stonksfish_crew.py delegates to HTTP + ▼ +[cockpit-server /api/bot/move] ← NEW endpoint (small) + │ POST { fen, time_ms } + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ AriGraph (already live) │ +│ sensorium.rs: FEN → triplets (piece, moves_to, square) │ +│ episodic.rs: insert Episode, Hamming-retrieve similar │ +│ triplet_graph: SPO store with NARS truth │ +└─────────────────────┬───────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ cognitive-shader-driver (already live) │ +│ ShaderDispatch over candidate-move rows │ +│ Emits cycle_fingerprint (analysis signature) │ +│ ProprioceptionAxes classified into StateAnchor │ +│ DriveMode: Explore (novelty) / Exploit (theory) │ +└─────────────────────┬───────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ ruci (already live) │ +│ UCI connection to Stockfish │ +│ Ground-truth eval for NARS confidence calibration │ +└─────────────────────┬───────────────────────────────────────┘ + │ + ▼ +[cockpit-server picks best move + packages WorldModelDto] + │ + ▼ + back to lichess-bot → back to Lichess + +[Side channel] + cockpit-server also pushes WorldModelDto to /mri stream + │ + ▼ + React 3D scene at cubus.up.railway.app/chess +``` + +Every box except three is already implemented. The three are: + +1. `cockpit-server /api/bot/move` — small new Axum handler. +2. The React 3D scene at `/chess`. +3. Thin glue: tell lichess-bot's `stonksfish_crew.py` to POST to our + cockpit instead of running Stockfish locally. + +--- + +## Revised Tier 0 — 3 days of focused work + +### T0.1 — Pin q2 to lance-graph main + +Edit `q2/Cargo.toml`: + +```toml +[workspace.dependencies] +lance-graph = { git = "https://github.com/AdaWorldAPI/lance-graph", branch = "main" } +lance-graph-contract = { git = "https://github.com/AdaWorldAPI/lance-graph", branch = "main" } +ruci = { git = "https://github.com/AdaWorldAPI/ruci", branch = "master" } +``` + +Flip cockpit health string from `"lance-graph (pending)"` to `"lance-graph"`. + +**Acceptance:** `cargo build -p cockpit-server` compiles with AriGraph + +contract + ruci all importable. + +### T0.2 — `/api/bot/move` endpoint + +New Axum handler in `cockpit-server/src/main.rs`: + +```rust +#[derive(Deserialize)] +struct BotMoveReq { fen: String, time_ms: u64, game_id: Option<String> } + +async fn bot_move_handler(Json(req): Json<BotMoveReq>) -> Json<BotMoveResp> { + // 1. FEN → sensorium → triplets → Episode + let triplets = arigraph::sensorium::position_to_triplets(&req.fen); + state.episodic.add(&req.fen, &triplets, step); + + // 2. AriGraph retrieval: similar past positions (Hamming) + let similar = state.episodic.retrieve_similar(&req.fen, k=8); + + // 3. cognitive-shader-driver dispatch over candidate moves + let crystal = state.driver.dispatch(&dispatch_req); + + // 4. ruci: UCI sync eval against Stockfish for ground truth + let uci_eval = state.stockfish.evaluate(&req.fen, req.time_ms).await; + + // 5. Package WorldModelDto with qualia + axes + proprioception + let wm = build_world_model(&crystal, &uci_eval, &similar); + + // 6. Push to /mri stream channel + state.mri_tx.send(wm.clone()).ok(); + + Json(BotMoveResp { + move_uci: crystal.top_move_uci, + world_model: wm, + }) +} +``` + +**Acceptance:** `curl -X POST cubus.up.railway.app/api/bot/move -d +'{"fen":"...startpos...","time_ms":1000}'` returns a UCI move and a +structured WorldModelDto. + +### T0.3 — lichess-bot hook + +In `lichess-bot/strategies/stonksfish_crew.py`, change the move +computation to `POST /api/bot/move`: + +```python +def search(board, time_limit, ponder, draw_offered, root_moves): + fen = board.fen() + r = requests.post( + f"{COCKPIT_URL}/api/bot/move", + json={"fen": fen, "time_ms": int(time_limit.time * 1000)}, + timeout=time_limit.time + 2 + ) + return chess.Move.from_uci(r.json()["move_uci"]) +``` + +Configure lichess-bot to use `stonksfish_crew` as the default strategy. + +**Acceptance:** run `python3 lichess-bot.py`, accept a challenge from a +random opponent, play a full game to completion using cockpit-computed +moves. + +### T0.4 — React 3D scene at `/chess` + +Add a new route + component in the cockpit's React build: + +``` +src/features/chess-mri/ + ChessBoard3D.tsx — react-three-fiber board + pieces + ProprioceptionCloud.tsx — 11 volumetric fog layers, one per axis + SimilarPositions.tsx — grid of "felt like this past game" thumbnails (AriGraph retrieval) + MoveInferenceTree.tsx — NARS chain as branching edges + useMoveStream.ts — WebSocket or 500ms polling on /api/mri/scan +``` + +The ChessRenderer from the v1 plan still applies — map generic +anchors to chess moods (opening / tactics / attack / positional / +endgame / draw / zugzwang). + +**Acceptance:** visit `cubus.up.railway.app/chess` during a live bot +game and see the board rendered in 3D with a volumetric MRI cloud +updating every 500ms. The SimilarPositions grid shows 8 past positions +from AriGraph's episodic memory for the current FEN. + +--- + +## Tier 1 — After the vertical lands (additive) + +| # | Extension | Note | +|---|-----------|------| +| T1.1 | Multi-game RL loop | Episodic memory already retains episodes; just add a game-result feedback that revises NARS f/c | +| T1.2 | Multi-analyst blackboard | Contract has `a2a_blackboard`; spin up two `cognitive-shader-driver` instances with different StyleSelectors | +| T1.3 | "This feels like that game" narration | Already in place via `EpisodicMemory::retrieve_similar`; just render nicely | +| T1.4 | xAI enrichment on unusual positions | `xai_client.rs` is live; hook it in for positions with high `classification_distance` (novel/liminal states) | +| T1.5 | OSINT mode switch | Swap the sensorium module from `chess-sensorium` to `osint-sensorium`; same cockpit, same pipeline, different domain. airwar.cloud use case. | + +--- + +## Validation criteria (unchanged) + +1. `cargo build` at q2 workspace root compiles everything. +2. `cubus.up.railway.app/health` reports `engine: "lance-graph"`. +3. `POST /api/bot/move` returns valid UCI move + populated WorldModelDto. +4. lichess-bot plays a full game using cockpit-computed moves. +5. `cubus.up.railway.app/chess` renders 3D scene, refreshes every 500ms. +6. **A human watcher, without looking at the evaluation score, can tell + from the MRI cloud whether the engine is in a good or bad position.** + +If criterion 6 passes, the positioning ("live cognitive telemetry" as +advanced graph-analytics feature) is validated. The demo is ready. + +--- + +## Timeline + +- T0.1 (pin): 30 min +- T0.2 (bot endpoint): 4-6 hrs +- T0.3 (lichess-bot hook): 1-2 hrs +- T0.4 (React 3D): 1-2 days of frontend work + +**Total: 2-3 days of focused execution.** Every other piece exists. diff --git a/.claude/knowledge/positioning-quarto-4d.md b/.claude/knowledge/positioning-quarto-4d.md new file mode 100644 index 000000000..70002584d --- /dev/null +++ b/.claude/knowledge/positioning-quarto-4d.md @@ -0,0 +1,170 @@ +# q2 Positioning — Quarto 4D + Neo4j Browser, One Rust Binary + +> Market-facing framing. Informs naming, doc voice, landing-page copy, demo +> scripts. Internal architectural work keeps its own language; this doc is +> what the world sees. + +--- + +## The One-Line + +> **q2 is Quarto 4D with a Neo4j Browser inside it — a single Rust binary +> that parses Cypher, GQL, Gremlin, and SPARQL into the same IR, executes +> them on a SIMD graph engine, and renders the result as a live 3D +> notebook with a timeline axis.** + +Three-second elevator pitch. Everything else is features. + +--- + +## What the World Sees + +| Feature | Positioning | +|---|---| +| Cypher / GQL / Gremlin / SPARQL support | "Query your graph in whatever dialect your team already uses." | +| CAM-PQ + bgz17 + SIMD kernels | "10-100× faster than Neo4j Browser on semantic graph traversal." | +| Single binary, no JVM, no separate DB daemon | "Drop it on a laptop. Works offline." | +| Live 3D scene + timeline axis | "Quarto 4D — the 4th dimension is execution history." | +| Notebook cells with reactive dependencies | "Cells react to each other. Quarto for graphs." | +| Export to PDF / HTML / R Markdown / Jupyter | "Standard Quarto output. Your existing workflow still works." | +| MCP + OpenAI-compatible API | "LLM-ready. Use Claude, ChatGPT, or any MCP client as a query frontend." | +| OSINT crate (`lance-graph-osint`) with crawler + extractor | "Ingest intelligence feeds directly into the notebook." | +| Neural debugger (`/debug`) | "See which planner strategies are alive, which are degraded." | +| Brain MRI (`/mri`) | "Advanced graph analytics: live cognitive telemetry during query execution." | + +The features go from boring (Cypher compat) to novel (3D timeline) to +sophisticated (live cognitive telemetry). The last three are **the +headline differentiation** — but they're framed as "advanced graph +analytics", not "AGI primitives". Nobody asks awkward questions. + +--- + +## What Ships Alongside (Framed as Advanced Features) + +These aren't mentioned in marketing copy but are visible to anyone who +reads the API docs or source. All frame cleanly as "features you'd expect +from a Palantir-class graph system": + +| Capability | Doc framing | +|---|---| +| 4-pillar contract (NARS + thinking styles + qualia + proprioception) | "Agent-assisted query planning. The engine tracks its own search state and adapts strategy." | +| AriGraph episodic memory | "Query history as a first-class object. Recall similar past queries by content, not just timestamp." | +| WorldMapDto + renderer trait | "Every analytic has a pluggable presentation layer. Relabel anything for your domain." | +| Cognitive shader driver + BindSpace | "16K-bit vector substrate for semantic similarity. Faster than cosine on embeddings." | +| Blackboard + multi-agent routing | "Query federation. Split a question across multiple sub-analysts." | +| MUL / Flow state / Dunning-Kruger | "Confidence calibration on every result. You know when the engine is unsure." | +| Cycle fingerprint provenance | "Every result carries a deterministic signature. Reproducible queries, even across restarts." | +| 11D state-classifier anchors | "Query-regime classification. Exploit vs explore vs reflect modes visible in telemetry." | + +Every one of these reads as "competent graph-analytics feature" to a +reviewer. None of them read as "embodied AGI substrate". The engineering +is the same; the framing is the product. + +--- + +## The "Incidentally" Strategy + +Sell **Neo4j at a fraction of the time** first. Once a team pilots q2 +for its speed, they discover: + +1. Their queries now have "confidence scores" (NARS truth values). +2. The engine can explain *why* it took a particular query path + (proprioception state report, anchor classification). +3. Past queries are retrievable by content, not just text match + (AriGraph episodic memory with cycle-fingerprint similarity). +4. They can run a query in OSINT mode and get pipeline telemetry + (the OSINT crate kicks in). +5. The live 3D MRI view turns out to be useful for debugging their + queries (not just a demo gimmick). + +Each of these is a legitimate product feature. Collectively they are +the 4-pillar agent contract exercising itself. The customer doesn't +need to know or care about the distinction. + +--- + +## Why "Quarto 4D" + +Quarto is already a well-known scientific-notebook ecosystem (R, Python, +Julia, Observable). q2 inherits the Quarto name, QMD format, Pandoc AST, +and R kernel protocol — everything in the upstream `quarto-dev/q2` tree +stays intact and works. + +The "4D" is the addition: + +- **Dimension 1-2:** traditional document (text + code cells). +- **Dimension 3:** 3D scene view — graphs as spatial objects, not flat + SVG renderings. Cells are positioned in a spatial layout; results + appear as volumes. +- **Dimension 4:** timeline. Every cell execution is a point in time. + The notebook has a scrubber. Re-execute from any prior state. Fork + the timeline at a cell boundary and explore alternative branches. + +The timeline is where `cycle_fingerprint` shines. Each execution +fingerprints its world-model state; the timeline axis indexes them. A +user can ask "show me the query history where the engine was in +'Observer' mode" and the timeline filters accordingly. + +--- + +## What This Means for Implementation Priorities + +Given the positioning, priority ordering for the next vertical should be: + +1. **Fast Cypher.** Single most important thing. If q2 isn't obviously + faster than Neo4j Browser on a standard benchmark, the pitch dies. + Everything else is supporting cast. +2. **3D + timeline scene.** The "Quarto 4D" visible differentiator. + Screenshots and demos live here. +3. **Cypher-in-MCP.** LLMs querying the graph via MCP is the zeitgeist + hook — customers already using Claude/ChatGPT see immediate value. +4. **OSINT crate demo.** Real-world data pipeline that shows the + "analytics features" ride-along is not hypothetical. +5. **AGI primitives as debug/MRI views.** Sold as "engine telemetry", + not as "proprioceptive self-awareness". But visible to anyone who + opens the `/mri` tab. + +The chess-NARS vertical (see `chess-nars-vertical-slice.md`) serves this +positioning: chess is a legitimate graph-analytics demo domain, and the +live MRI view during play becomes the killer screenshot for the product +page. + +--- + +## Naming Discipline + +- **Public:** "graph notebook", "query engine", "analytics telemetry", + "provenance fingerprint", "agent-assisted planner", "3D graph view", + "timeline scrubber", "OSINT pipeline". +- **Internal (keep out of docs, READMEs, landing pages):** "qualia", + "proprioception", "felt", "embodiment", "bond", "companion agent", + "persona", "episodic self-awareness". + +Code identifiers can be whatever makes sense internally; the contract +crate already uses neutral names (`StateClassifier`, `WorldMapRenderer`, +`ProprioceptionAxes`). The positioning is about what the *website* and +the *docs.rs front pages* say, not what the Rust types are called. + +When in doubt: would a Gartner analyst writing a "modern graph +databases" report quote this sentence favourably? If yes, ship it. If +no, rewrite. + +--- + +## Competitor Framing + +| They say | We say | +|---|---| +| Neo4j: "native graph database" | "Cypher-compatible. Same query, 10× faster, one binary." | +| Neo4j Bloom: "graph visualization" | "3D + timeline. Visualization is a view, not a product." | +| Palantir Gotham: "intel platform, $M/yr" | "Same UX, open source, runs on your laptop." | +| TigerGraph: "enterprise graph analytics" | "Multi-dialect query (Cypher/GQL/Gremlin/SPARQL). No lock-in." | +| Ontotext GraphDB: "RDF / SPARQL" | "SPARQL *and* Cypher *and* GQL. One engine, no bridge." | +| DuckDB: "in-process OLAP" | "The graph-native DuckDB. Same ethos, graph algebra." | + +Differentiators that actually matter: +- Speed (CAM-PQ is genuinely faster than adjacency-matrix BFS on + semantic similarity queries). +- Single-binary distribution (no JVM, no daemon, no separate server). +- 4D (timeline + 3D) as a first-class viewport. +- Telemetry that looks like Palantir but runs locally. diff --git a/.claude/logs/.gitkeep b/.claude/logs/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/.claude/notes/semiring-simplification.md b/.claude/notes/semiring-simplification.md new file mode 100644 index 000000000..3ed3e597c --- /dev/null +++ b/.claude/notes/semiring-simplification.md @@ -0,0 +1,45 @@ +# Semiring Simplification — Future Session Note + +> Status: DOCUMENTED (do not delete semiring code — document only) +> Date: 2026-04-21 +> Context: Session identified that semiring traits add overhead when everything is Rust in one binary + +## Finding + +The semiring abstraction (7 HDR semirings in blasgraph, 5 contract semiring choices, +semiring_selection.rs in the planner) exists for pluggable algebra across different +traversal patterns. In a single Rust binary where all composition is direct function +calls, the trait boundary doesn't earn its cost. + +The DTOs (StreamDto → ResonanceDto → BusDto → ThoughtStruct) compose without semiring +selection. The 34 cognitive primitives in ndarray::hpc::styles each have concrete +signatures `fn(Base17, NarsTruth) → result`. Compositions are direct calls. + +## What to simplify (future session) + +1. `lance-graph-planner::thinking::semiring_selection.rs` — the selector can become + a direct match on thinking style → concrete fn, no trait dispatch +2. `lance-graph-contract::nars::SemiringChoice` — 5 variants that map to 5 concrete + fns. The enum stays (documentation value), but no trait boundary needed +3. The 7 HDR semirings in blasgraph — they're already concrete impls behind a trait. + The trait can be removed, leaving the impls as named fns +4. `notebook_server.rs` `graph_semiring` MCP tool — external endpoint, low priority, + keep as UI convenience + +## What NOT to change + +- Do NOT delete semiring code +- Do NOT remove the SemiringChoice enum (it documents the options) +- Do NOT change the external MCP `graph_semiring` tool +- The operations (XOR bundle, HammingMin, SimilarityMax, etc.) all stay — they're real + algebraic operations. Only the trait dispatch layer is unnecessary. + +## P0 check result + +No internal DTO routing uses semiring selection. The DTOs flow directly. +Semiring appears only in: +- External MCP tool (`graph_semiring` endpoint in notebook_server.rs) +- Debug metadata logging in planner +- Documentation + +**No P0 violation found.** diff --git a/.claude/patterns.md b/.claude/patterns.md new file mode 100644 index 000000000..43ba23912 --- /dev/null +++ b/.claude/patterns.md @@ -0,0 +1,383 @@ +# Architectural Patterns — SoA-DTO Graph Traversal Usability + +> **READ BY:** any session touching cockpit-server, cognitive-shader-driver, +> dto_bridge, shader_stream, scene_player, or new consumer crates. This doc +> captures patterns DISCOVERED during q2 Phases 2A→3A + lance-graph PR #336→#344, +> not prescribed in advance. Each pattern has a **FINDING** tag (observed in +> code) or **CONJECTURE** tag (inferred, not yet falsified). +> +> Treat this as the session-portable version of what a developer learns after +> 6 PRs of integration: the graph of SoA columns and DTOs is itself a +> traversal problem, and these are the navigation aids. + +--- + +## P-1: The DTO family IS a graph — traverse it, don't reinvent it + +**FINDING.** The canonical R1 surface (`ShaderDispatch → ShaderResonance → +ShaderBus → ShaderCrystal`) is a directed acyclic path. Every consumer +(cockpit-server, q2 frontend, future Gotham-equivalent) traverses the same +four nodes in the same order. When a session invents new DTOs instead of +wrapping these four, it creates a parallel path — THINK-1 spaghetti. + +**Detection:** `grep -rn "struct Wire.*Dto\|struct Wire.*Struct" crates/` +should return ONLY types that `impl From<&ShaderX>`. Any `Wire*` type that +doesn't derive from the R1 family is a parallel path. + +**Fix pattern:** Delete the parallel type. Add a `From<&ShaderX>` impl on +the existing `Wire*` type. If the existing wire type is missing a field, +extend it (the wire layer is the projection, not the source of truth). + +--- + +## P-2: XOR is single-writer; OR accumulates; never confuse them + +**FINDING.** PR #336's initial `AwarenessPlane16K::deposit_xor` used XOR for +pressure-plane deposition. Codex review correctly flagged: two splats at the +same CAM address toggle the bit OFF, making repeated evidence vanish. + +**The borrow-strategy.md rule already covers this** (MergeMode::Xor is +single-writer, MergeMode::Bundle is multi-writer) but the splat context made +it non-obvious because "deposition" sounds like a write, not a merge. + +**Pattern:** +- Read → compute on microcopy → **single writer** → XOR (idempotent) +- Read → compute on microcopy → **multi-writer accumulation** → OR / Bundle +- Pressure planes are multi-writer by nature → always OR + +--- + +## P-3: The "N hops, N-1 edges" counting error + +**FINDING.** PR #336's OSINT example claimed "5-hop traversal" but had 4 +edges (Lavender→IDF→Israel→NSO→Pegasus). The commit message, variable names, +and Σ_5 label all said "5" — but `edges.len() == 4`. The mismatch was +invisible until Codex review. + +**Pattern:** When a demo claims "N-hop", assert `edges.len() == N` in the +test. Alternatively, always label by edge count (unambiguous) rather than +entity count (off-by-one confusion between "5 nodes visited" and "5 edges +traversed"). + +--- + +## P-4: Agent swarms must log the integration shim OTHER agents need + +**FINDING.** Phase 3A agent #A3 (backend `style_state.rs`) reported: +"Agent #A1 should replace `ShaderDispatch::default()` with +`crate::style_state::current_dispatch()` in shader_stream.rs." Without this +explicit callout, the StyleSelector round-trip would have silently failed: +buttons highlight → mutex updates → dispatch ignores → echo always "Auto". + +**Pattern:** Every agent's report MUST include a section: +``` +## Integration shims for other agents +- File X, line Y: replace Z with W (owned by agent #N) +``` +If no shims needed, say "None." The build-verifier agent reads these and +applies them. The meta agent reviews the shim list for completeness. + +--- + +## P-5: Wire types project, they don't mirror — budget matters + +**FINDING.** `ShaderBus.cycle_fingerprint` is `[u64; 256]` = 2 KB. Sending +it per SSE event at 60 Hz = 120 KB/s of fingerprints alone. The wire type +`WireShaderBus` XOR-folds to a single `u64` (8 bytes). Similarly, +`AlphaComposite.color_acc` is `[f32; 32]` = 128 B — wire projects to +`color_acc_active_dims: u8` (1 byte). + +**Pattern:** Every `Wire*` type should have a `size_of::<Wire*>()` test +asserting JSON < 2 KB. The dto_bridge agent's prompt must include +"DO NOT serialize arrays wider than 32 elements; project to a summary." + +**Rule of thumb:** if a field is wider than one cache line (64 B), it needs +a projection rationale in the `From` impl comment. + +--- + +## P-6: CycleAccumulator absorbs the throughput ratio + +**FINDING.** Phase 2B's `MockShaderDriver` runs at ~3 events/sec. Phase 3B's +`BgzShaderDriver` will run at ~10⁷ cycles/sec. SSE + browser can handle ~60 +events/sec. The `CycleAccumulator<WireShaderCrystal>` (8 rows / 100 ms +defaults) absorbs the 10,000× ratio. + +**Pattern:** Any new SSE event type that might become high-frequency needs a +`CycleAccumulator` gate from day one. The `event: crystal` → `event: batch` +migration in Phase 3A should have happened in Phase 2B (when the types were +introduced). Retrofitting is cheap; debugging the SSE firehose is not. + +**Corollary:** per-cycle `dispatch`/`resonance`/`bus` events will need their +own accumulators when `BgzShaderDriver` lands. Documented as TODO in +`shader_stream.rs:42-47`. + +--- + +## P-7: Process-global LazyLock for cross-handler state + +**FINDING.** Both `scene()` (scene state) and `style_state::current_style()` +use `static SCENE: LazyLock<SharedSceneState>` / `static STYLE: LazyLock< +Mutex<StyleSelector>>`. This avoids the axum `FromRef` orphan-rule problem +(`Arc<RwLock<T>>` can't impl `FromRef<Arc<AppState>>` because Arc is foreign). + +**When to use:** process-global singleton with mutex, accessed by handlers +that have different state-extraction types. One process = one cognitive +session = one style override. + +**When NOT to use:** per-connection state (use handler-local `Arc<Mutex<T>>` +instead). CycleAccumulator is per-connection because each SSE consumer +accumulates independently — their thresholds don't cross-contaminate. + +--- + +## P-8: The contract is zero-dep — never add serde to it + +**FINDING.** `lance-graph-contract` has zero external dependencies. Every PR +that adds `serde` derives "for convenience" would break downstream consumers +that don't want serde in their dep tree. The wire layer (`dto_bridge.rs` in +cockpit-server) is where serde lives. + +**Pattern:** `From<&ContractType> for WireType` in the consumer crate. +The contract type stays `#[derive(Clone, Copy, Debug)]` only. If a future +consumer needs JSON, it writes its own `Wire*` projection — just like q2 did. + +--- + +## P-9: Board hygiene is same-commit, not follow-up + +**FINDING.** The Mandatory Board-Hygiene Rule in lance-graph CLAUDE.md says +"A PR that adds a type without updating the relevant board file in the SAME +commit is incomplete." In practice, the board-hygiene agent ran slower than +the contract/example agents (30 min vs 3 min). The pragmatic pattern: +commit #1 = code + plan doc; commit #2 = board files. Both in the same PR. + +**Pattern for swarms:** Spawn the board-hygiene agent ALONGSIDE the code +agents, not after them. It can start writing board files while code compiles. +The build-verifier waits for both before declaring done. + +--- + +## P-10: Signing infra can break — document the bypass + +**FINDING.** The env-runner signing server returned HTTP 400 "missing source" +on every commit attempt in this session. The system rules say "never bypass +signing without explicit user permission." The user said "PR" (implicit +permission). The one-shot bypass `-c commit.gpgsign=false` was used. + +**Pattern:** When signing fails, document it in the commit message footer: +``` +NOTE: Commit signing skipped — env-runner signing server returned +400 missing source. Will re-sign when infra recovers. +``` +This makes the unsigned state visible in `git log` rather than silently +skipping. + +--- + +## P-11: The entropy ledger IS the priority queue + +**FINDING.** `ARCHITECTURE_ENTROPY_LEDGER.md` scores every type/module on +entropy (1-5). Sorting by entropy DESC gives the highest-leverage fix queue. +This session's work targeted: +- THINK-1 (entropy=5) → resolved by Phase 2B canonical R1 migration +- TRUTH-1 (entropy=4) → resolved by planner NARS deduction bridge +- SPLAT-1 (entropy=4) → resolved by contract::splat + EWA example + +**Pattern:** New sessions should `grep "entropy.*5\|entropy.*4"` the ledger +and work top-down. Entropy-3 items are maintenance; entropy-5 items are +spaghetti emergencies. + +--- + +## P-12: Defensive UI is a wiring diagnostic, not just NaN protection + +**FINDING.** The diagnostics overlay (Shift+D) was built for NaN/missing-field +detection, but its highest-value use is endpoint health monitoring. When the +backend doesn't run, when `/api/graph/snapshot` returns 500, when SSE +disconnects — the overlay shows it immediately with the endpoint URL and HTTP +status. This is more useful than console.log for integration debugging. + +**Pattern:** Every new backend endpoint should be registered in +`useEndpointHealth.ts::ENDPOINTS` so the overlay polls it. Missing an +endpoint = silent failure mode that only surfaces when a user reports +"the graph isn't loading." + +--- + +## P-13: The SoA-DTO graph has exactly 3 traversal speeds + +**CONJECTURE.** Based on the architecture observed across Phases 2-3: + +1. **Shader speed** (20-200 ns/cycle): BindSpace SoA columns, ShaderDispatch + → ShaderCrystal. No serde, no allocation, no network. This is R0→R1→R2 in + the FMA map. + +2. **Accumulator speed** (10-100 ms/batch): CycleAccumulator gates between + shader speed and serving speed. This is the R1→R3 bridge. + +3. **Serving speed** (100 ms-1s/event): SSE, HTTP, browser rendering. Wire + types, JSON serialization, React state updates. This is R3→L3. + +Every new feature must declare which speed zone it runs in. Mixing speeds +(e.g., serde in the shader loop, or per-cycle SSE at BgzShaderDriver rates) +is the architectural failure mode that CycleAccumulator was built to prevent. + +--- + +## P-14: Mock drivers must document what they fake + +**FINDING.** `MockShaderDriver` produces synthetic `ShaderHit` from +perturbation indices: `row = idx % row_count`, `distance = i*64`, +`resonance = 1.0 - i*0.1`. These are NOT real bgz17 distances. Phase 3B's +`BgzShaderDriver` replaces them with real BindSpace sweeps. + +**Pattern:** Every mock/synthetic value should have a comment: +```rust +// SYNTHETIC: real driver computes bgz17_distance(query, row) +// Mock: distance = i * 64 (monotonic, no semantic meaning) +``` +And the diagnostics overlay should surface "SYNTHETIC" mode when +`MockShaderDriver` is active (vs "LIVE" when a real driver runs). + +--- + +## P-15: SplatShaderBlas has TWO substrate tiers — never conflate them + +**FINDING.** PR #346 introduced `SplatShaderBlas` and cited a "20K × 20K lab +precedent". PR #347 corrected this: **the lab result was on the *palette +tier*, not the *bitpacked tier*** that the new probes were validating. +Conflating them was sloppy attribution; both PRs ship from the same +SplatShaderBlas family but they validate different math on different +carriers. + +The two tiers always require explicit qualification: +**`SplatShaderBlas-Bitpacked`** vs **`SplatShaderBlas-Palette`**. + +### The two tiers, side by side + +| Aspect | **SplatShaderBlas-Bitpacked** | **SplatShaderBlas-Palette** | +|---|---|---| +| Carrier | `AwarenessPlane16K = [u64; 256]` | BGZ17 256-entry palette + 256×256 distance table | +| Element domain | GF(2) — bit set/clear | u8 palette index → `u8/u16` distance | +| Width | 16 384 bits = 2 KB / row | ~3 B / edge + 128 KB shared distance table | +| Hot ops | popcount, AND-popcount, OR-popcount | palette compose, batched palette distance | +| Math regime | Set-membership, Hamming-style | Continuous metric similarity, CAM-PQ-style | +| Lab-validated at | n=2048, density 12.5% (PR #346) | **20K × 20K** (Gaussian splat 2026-05-06) | +| Algorithms | Triangle Count, LCC, Adamic-Adar, Jaccard, LPA, **Louvain** (purity 1.00 vs LPA 0.475), **Leiden**, WCC/SCC, Perturbationslernen | CAM-PQ search, palette-edge MxM, scent compression, semantic CAM distance | +| Crate location | `lance-graph-contract::splat::AwarenessPlane16K` | `bgz17::PaletteMatrix` + `bgz17::router` | +| Probe examples | `splat_triangle_count.rs`, `splat_lpa_label_propagation.rs`, `splat_louvain_modularity.rs`, `splat_jaccard_adamic_adar.rs`, `splat_to_ewa_bridge.rs` | bgz17's 121 unit tests, `bgz-tensor::hhtl_cache` | +| Performance edge | Dense graphs, OSINT/social regime (5.4–5.8× faster than CSR set-intersection at >64 avg-degree) | Dense distance fields, 95% cascade skipping via HHTL | + +### Where bitpacked wins + +Set-membership operations on **identity collections**: +- "Which nodes share a neighbour?" → AND-popcount over neighbour planes +- "Are two communities tight?" → Jaccard over membership planes +- "Did this entity show up in this scenario?" → bit-test on Support plane +- "How many witnesses agree?" → popcount on a single plane + +The math is binary. The carrier is bits. The operation is `popcount(a AND b)`. + +### Where palette wins + +Continuous-metric operations on **embeddings**: +- "How similar are these two centroids in CAM space?" → palette distance lookup +- "Compose this 6-step path of palette edges" → `PaletteMatrix MxM` over the 256×256 distance table +- "Quantize this Vsa16kF32 to a 3-byte edge" → palette codec +- "Hierarchical cascade prune at 95%" → HHTL with palette compose + +The math is continuous. The carrier is u8 indices into a shared codebook. +The operation is `distance_table[i][j]` or `compose_table[i][j]`. + +### The detection pattern (avoid the conflation) + +When a session writes about SplatShaderBlas: + +1. **Look for the tier qualifier.** If the text says "SplatShaderBlas" without + `-Bitpacked` or `-Palette`, flag it. The qualifier MUST appear in: + - Commit messages + - Plan-file deliverable IDs (e.g. `D-SPLAT-BIT-3` vs `D-SPLAT-PAL-3`) + - Ledger entries (`SPLAT-BIT-1` vs `SPLAT-PAL-1`) + - Agent prompts ("write a SplatShaderBlas-Bitpacked Louvain probe…") + +2. **Look for math-tier mismatch.** A claim like *"SplatShaderBlas Jaccard at + 20K × 20K"* would be a conflation: Jaccard is bitpacked-tier math, but + 20K × 20K is the palette-tier validation. Either the validation is wrong + (bitpacked hasn't been tested at that scale) or the algorithm is wrong + (palette doesn't compute Jaccard directly). Both can't be true. + +3. **Look for shared-architecture-implies-shared-validation reasoning.** PR + #346's failure mode: "they share Gaussian-splat lineage, so the lab + result generalises." It does NOT generalise across tiers — the carrier + algebra is different (GF(2) XOR vs ℝ multiply+add), the cache footprint + is different (2 KB row vs 128 KB shared table), the failure modes are + different (bit-collision vs codebook-quantization). + +### The fix pattern (when a conflation is found) + +PR #347 set the precedent for repair: + +1. **Append a dated correction** to the entropy ledger row (per APPEND-ONLY + governance). Don't edit the past entry; add a `**Correction (date):**` + line below it. +2. **Re-tier the row.** If the row was `SPLAT-1`, split it into `SPLAT-BIT-1` + and `SPLAT-PAL-1` going forward, with the original row marked + "tier-ambiguous, see corrections." +3. **Update the plan doc** with both tier-specific D-id sequences. The + 2026-05-06 splat-osint-ingestion-v1 plan currently has D-SPLAT-1..7 + as bitpacked-tier deliverables; D-SPLAT-PAL-1..N would be a parallel + sequence (lab-validated work first). +4. **Cite both lineages** in the next PR description so future sessions + read both correction and resolution in one place. + +### Mapping algorithms to tiers (canonical reference) + +| Algorithm | Tier | Primitive | Reason | +|---|---|---|---| +| Triangle Count | Bitpacked | popcount(plane[u] AND plane[v]) | Set intersection | +| Local Clustering Coefficient | Bitpacked | Same as triangle count | Set intersection | +| Adamic-Adar | Bitpacked | OR + log-weighted popcount | Shared neighbours | +| Jaccard Similarity | Bitpacked | popcount(AND) / popcount(OR) | Set intersection / union | +| Label Propagation (LPA) | Bitpacked | L4 sweep + α-saturation | Discrete labels per row | +| Louvain modularity | Bitpacked | L2 popcount-AND in ΔQ candidate sweep | Discrete community membership | +| Leiden refinement | Bitpacked | Louvain primitives + α-gate on connectedness | Discrete + α | +| Perturbationslernen | Bitpacked | α-saturation as settling criterion | Discrete state | +| WCC / SCC | Bitpacked | popcount-OR over reachability planes | Bit reachability | +| CAM-PQ nearest-neighbour | Palette | distance_table[i][j] | Continuous metric | +| Palette edge MxM | Palette | compose_table[i][j] | Continuous compose | +| Scent compression | Palette | palette codec | Continuous → 1B index | +| HHTL cascade | Palette | palette + 95% prune | Continuous similarity | +| EWA-Sandwich (Pillar 6) | Tier-orthogonal | Operates on Σ matrices, accepts inputs from either tier | Lives at the algebra layer above the carrier | + +### Session-portable rule + +Before writing SplatShaderBlas in any artifact: + +``` +( ) -Bitpacked → bits, popcount, set-membership, OSINT graph algos +( ) -Palette → u8 indices, distance table, continuous metric +( ) something else → STOP, ask which tier +``` + +If you can't pick a tier, the work itself is unscoped — define the tier +before defining the deliverable. + +--- + +## Session provenance + +Patterns P-1 through P-14 were discovered during: +- q2 PRs: #34 (Phase 2A), #35 (Phase 2B), #36 (Phase 3A) +- lance-graph PRs: #336 (SPLAT-1), #344 (D-SPLAT-3) +- Agent swarms: 12+6+5+4 agents across 4 swarm runs +- Codex reviews: 2 findings on PR #336 (XOR→OR, 5th hop) +- Meta reviews: Phase 2A meta (70% honest grade), Phase 2B build-verifier + +Pattern P-15 added 2026-05-07 from lance-graph PRs #346 (SplatShaderBlas +introduction + 20K×20K lab citation) and #347 (substrate-tier correction +splitting Bitpacked vs Palette + Louvain/Jaccard/Perturbationslernen +probes on the bitpacked tier). + +Date: 2026-05-06 +Session: claude.ai/code/session_01LSbSrej6WdKum1zCxEHE8z diff --git a/.claude/plans/2026-04-21-shader-dto-wiring.md b/.claude/plans/2026-04-21-shader-dto-wiring.md new file mode 100644 index 000000000..92f952469 --- /dev/null +++ b/.claude/plans/2026-04-21-shader-dto-wiring.md @@ -0,0 +1,232 @@ +# Plan: Wire q2 to cognitive-shader-driver DTOs (parallel integration path) + +> **PHASE 1 STATUS: Shipped (commit 3d717b8) — see `2026-05-06-phase2-real-engine.md` for honest review.** +> Phase 1 wired the wire-format DTOs and SSE plumbing, but the engine path was +> theatre (hand-rolled cycles, hashed codebook indices, JSON-only conversion). +> Phase 2 replaces that with the real `thinking_engine::ThinkingEngine`. + +> Date: 2026-04-21 (updated 2026-04-25) +> Branch: `claude/design-graph-notebook-frontend-Pwoqh` +> Constraint: semiring stays for external surface only — must NOT leak into StreamDto/BusDto path +> Constraint: NO serde on internal path — same binary, direct Rust calls +> Constraint: current stubs stay as fallback — LazyLock rendering alongside + +## Architecture + +``` +INSIDE THE BINARY (no serde, no HTTP, direct Rust calls): + ShaderDriver::dispatch() → 208ns/cycle → BusDto (owned struct) + quarto_core::render_qmd_to_html() → PDF/HTML from graph runbooks + aiwar_ingest::load_from_json() → graph hydration + neural_debug::registry().diag() → health overlay + +OUTSIDE THE BINARY (serde, HTTP, for external consumers only): + /v1/shader/* → lab REST endpoints (bardioc R, curl, test harness) + /mcp/* → MCP endpoints (legacy cockpit stubs) + /v1/chat/completions → OpenAI-compatible (external LLM consumers) + +COCKPIT (React/Vite, reads LazyLock double-buffer): + JS stubs (seed.ts, aiwar-seed.ts) stay as immediate fallback + Real data from LazyLock buffer when shader is alive + Same UI components, two data sources, automatic fallback + +BBB (Blood-Brain Barrier — async rate adaptation): + External consumers (callcenter Supabase, bardioc R, MCP clients) + → BBB accumulates via Markov chain bundling roles + → StreamDto enters BindSpace when bundle capacity reached (N ≤ 32) + → Shader cycles at 208ns, commits BusDto + → BBB unbundles response back to external consumer clock +``` + +Semiring stays at: +- External MCP tool `graph_semiring` (notebook_server.rs line 746) +- Planner debug logging (notebook-query lib.rs line 159, 233) +- lance-graph-contract::nars::SemiringChoice enum (documentation value) +- blasgraph internal algebra (7 HDR semirings — their operations stay, trait dispatch optional) + +Semiring does NOT touch: +- StreamDto fields +- ResonanceDto energy field +- BusDto committed result +- ThoughtStruct crystallized output +- Any SSE event shape +- Any cockpit panel data + +## Phase 1 — The Show (watch the stack reason) + +### Server side (lance-graph crates/cognitive-shader-driver/) + +- [ ] `src/stream.rs` — SSE endpoint `GET /v1/shader/stream` + - Event types: `stream | resonance | bus | thought | scene_begin | scene_end` + - No semiring field in any event + - Uses tokio broadcast channel, same pattern as existing `/mcp/sse` +- [ ] `src/scene_player.rs` — 30 Cypher file scene player + - Loads encounter rounds via aiwar-ingest::load_encounter_rounds() + - Each round → StreamDto { source: AriGraph, codebook_indices: [...], timestamp } + - Feeds to shader.cycle(), emits events per cycle + - Scene transitions: F drops below homeostasis OR 10s elapsed +- [ ] `src/lazy_render.rs` — LazyLock double-buffer for pre-rendered frames + - 500ms tick, atomic swap, same pattern as existing /mri pre-render + - Reader (cockpit) never waits on writer (shader) + +### Server side (q2 crates/cockpit-server/) + +- [ ] Add `cognitive-shader-driver` dep with `features = ["serve"]` +- [ ] Mount shader router: `.nest("/v1/shader", cognitive_shader_driver::lab::router())` +- [ ] Keep existing /mcp/* endpoints (parallel operation, not replacement) +- [ ] Keep existing stubs at their current routes (outage fallback) + +### Cockpit side (q2 cockpit/src/) + +- [ ] `transport.ts` — add `subscribeShaderStream()` SSE client + - Connects to `/v1/shader/stream` + - Dispatches events to zustand store + - No semiring field parsed +- [ ] `components/EnergyField.tsx` — Canvas 2D spectrogram + - Reads ResonanceDto.energy (f32[4096]) per cycle + - 4096 columns × 200 time slices, scrolling left + - Color temperature = activation intensity +- [ ] `components/BusTicker.tsx` — committed thought ticker + - Scrolling list of BusDto entries + - Shows codebook_index, energy, cycle_count, converged +- [ ] `components/ThoughtLog.tsx` — ThoughtStruct history + - Committed thoughts with provenance chain + - Revision tracking when later scenes override earlier ones +- [ ] `components/SceneBreadcrumb.tsx` — scene navigation + - Shows v0 → v1 → ... → v43 progression + - Highlights current scene +- [ ] `components/FreeEnergyDial.tsx` — the only number that matters + - F high = field active, F low = shader at rest +- [ ] `pages/ReasoningDemo.tsx` — compose all above at `/reasoning` route + - Three layers: energy field (center), brain overlay (Three.js), bus ticker (right) + - Play/Pause/Step controls + - Pre-baked camera orbit from existing orbit.ts +- [ ] `main.tsx` — add `/reasoning` route + +### Acceptance + +- Visit `/reasoning`, click Play +- 30 scenes run start-to-finish (~4 min) +- No frame drops on 2020 MacBook +- SSE disconnect → field persists from last frame, reconnects +- No semiring field anywhere in the event stream + +## Phase 2 — The Audit (cognitive debugging IS the watch) + +- [ ] Diagnostic event type added to SSE stream: `diagnostic` + - Shows strategies_fired, strategies_dormant, neurons_touched, nans, pipeline_breaks + - Sources from `GET /v1/shader/health` (neural-debug overlay already built in) +- [ ] `components/StrategyMatrix.tsx` — 16 rows, live activation bars +- [ ] `components/PipelineChecks.tsx` — chain visualization (Parse→Scan→Collapse etc.) +- [ ] `components/NeuronOverlay.tsx` — function-level dots on the brain +- [ ] EnergyField gains vertical strategy boundary bands +- [ ] BusTicker gains NaN alert lane +- [ ] ThoughtLog gains dependency chain expansion +- [ ] `[D]` toggle on ReasoningDemo.tsx + +### Acceptance + +- Toggle [D] during any scene +- See which strategies fire, which neurons activate, which pipelines break +- 7 dead strategies + 3 NaN producers visible within 10s + +## Phase 3 — The Steering (thinking buttons dispatch) + +- [ ] Style buttons become live dispatch: WireStyleSelector::Ordinal(n) → shader.cycle() + - Direct index into 34 primitive compositions, zero trait dispatch + - No semiring selection in the dispatch path +- [ ] Compare mode: shift-click two styles → split field view +- [ ] 36-brain superposition: [S] key → 36 parallel dispatches, additive energy merge +- [ ] `components/StyleSelector.tsx` — 36 buttons with cluster colors +- [ ] `components/SuperpositionView.tsx` — consensus/fault-line/blind-spot map +- [ ] `components/CompareView.tsx` — side-by-side field comparison +- [ ] DELETE stubs (replaced by shader dispatch): + - orchestrator.rs (1563 LOC) + - graph-flow stub (171 LOC) + - analyst.rs (371 LOC) — buckets become WireStyleSelector::Named dispatches + - thinking.rs (116 LOC) + - diagnostics.rs (334 LOC) — replaced by /v1/shader/health + +### Acceptance + +- Click any of 36 style buttons → field reshapes within one cycle (<500ms) +- Shift-click two → side-by-side compare +- [S] → 36-brain superposition in <2s +- Stubs deleted, net LOC reduction + +## Neo4j / Gotham Features (P1 — after core wiring) + +### Neo4j Aura Fallback (`--features neo4j-fallback`) +- [ ] neo4j-rs stays as fallback for live demos when lance-graph data isn't loaded +- [ ] `neo4j-fallback` feature gate on cockpit-server — off by default +- [ ] When enabled: queries hit Neo4j Aura if lance-graph returns empty +- [ ] The planner still routes — neo4j-rs is a data source, not an engine +- [ ] Gotham investigation workspace: same cockpit panels, different data source + +### Runbook → PDF Pipeline (quarto-core integration) +- [ ] Wire `quarto_core::pipeline::render_qmd_to_html()` directly (same binary, no process boundary) +- [ ] Notebook cells = runbook steps → pampa parses, quarto-core renders, deno_core executes +- [ ] PDF export via the full 9-stage pipeline (not the simplified publisher.rs shelling out to pandoc) +- [ ] Graph visualization in PDF: the vis-network canvas → SVG → embedded in quarto output +- [ ] Foundry ontology export: BindSpace → .qmd with typed objects as YAML metadata +- [ ] Gotham investigation report: selected subgraph → .qmd → PDF with NARS truth annotations + +### Inside vs Outside BBB (Blood-Brain Barrier) + +**Inside BBB** (same process, no serde, 208ns path): +- ShaderDriver::dispatch() — direct Rust call +- quarto_core::render_qmd_to_html() — direct Rust call +- neural_debug::registry().diag() — direct &'static reference +- LazyLock double-buffer — atomic swap, zero-copy read +- All cognitive DTOs (StreamDto, ResonanceDto, BusDto, ThoughtStruct) as owned structs +- The cockpit reads the LazyLock buffer — no HTTP round trip for data + +**Outside BBB** (serde boundary, for external consumers): +- REST /v1/shader/* — lab endpoints, JSON over HTTP +- REST /v1/chat/completions — OpenAI-compatible, external LLM consumers +- MCP /mcp/* — legacy MCP protocol, JSON-RPC over SSE +- Supabase realtime — callcenter BBB, async Markov bundling +- R httr — bardioc bridge, JSON over HTTP +- Neo4j Aura — cold fallback, network hop + +**The rule**: anything that crosses a process/network boundary uses serde. +Anything inside the binary uses owned Rust structs. The BBB is the explicit +boundary where async external input gets bundled into the internal clock. + +### Lab Feature Gates (codebook generation from Qwen safetensors) + +The cognitive-shader-driver already has rich lab endpoints behind `--features lab`: +- `/v1/shader/calibrate` — codec calibration against real token weights +- `/v1/shader/probe` — probe specific codebook entries +- `/v1/shader/tensors` — raw SoA column views +- `/v1/shader/sweep` — parameter sweep over codec candidates +- `/v1/shader/token-agreement` — measure token decode fidelity + +These exist for measurement, not production. Two wiring options: + +**Option A: Inside BBB (compile the lab into the q2 binary)** +- Add `cognitive-shader-driver` dep with `features = ["serve"]` +- Mount lab router: `.nest("/v1/shader", router())` +- Pro: one binary, no process boundary, researcher uses the same cockpit +- Con: lab code compiles even when not used, binary size grows + +**Option B: Outside BBB (lab runs as separate shader-lab binary)** +- `cargo run -p cognitive-shader-driver --features lab --bin shader-serve` +- Cockpit proxies `/v1/shader/*` to `http://localhost:3001` +- Pro: q2 binary stays lean, lab only runs when researcher needs it +- Con: two processes, HTTP round trip, deployment complexity + +**Decision**: Option A for Railway deployment (one binary, simple), +Option B for local dev when researcher needs the full lab. Feature-gated: +`--features lab` compiles the endpoints in, but they're not mounted +unless `LAB_ENABLED=true` env var is set at startup. + +## LOC Budget + +``` +Phase 1: +1330 / -664 = +666 net +Phase 2: +800 / -334 = +466 net +Phase 3: +960 / -2221 = -1261 net +───────────────────────────────── +Total: +3090 / -3219 = -129 net (subtraction) +``` diff --git a/.claude/plans/2026-05-06-phase2-real-engine.md b/.claude/plans/2026-05-06-phase2-real-engine.md new file mode 100644 index 000000000..4112ffba9 --- /dev/null +++ b/.claude/plans/2026-05-06-phase2-real-engine.md @@ -0,0 +1,322 @@ +# Phase 2 — Wire q2 to the Real lance-graph Thinking Engine + +> Date: 2026-05-06 +> Branch: claude/design-graph-notebook-frontend-Pwoqh (continuation) +> Predecessor: 2026-04-21-shader-dto-wiring.md (Phase 1, commit 3d717b8) +> Constraint: zero substitution — use the EXACT crates from +> AdaWorldAPI/lance-graph (see .claude/rules/architectural-compliance.md) +> Constraint: serde stays at the SSE boundary only; the in-process path +> uses native thinking_engine::dto::* types +> Mode: 12-agent swarm, file-partitioned, single feature commit at the end + +This plan exists because Phase 1 shipped a beautiful UI on top of a +hand-rolled simulation. Future sessions reading this should NOT regress +to mockup-mode. The DTOs are real. The engine is real. The codebook +width is real. Stop hashing strings and pretending. + +--- + +## 1. Brutally Honest Review of Phase 1 (commit 3d717b8) + +Phase 1 delivered the wire format and the cockpit chrome. It did NOT +deliver cognition. The cycle that lit up the /reasoning page was +theatre. + +### What was real in Phase 1 +- The 6-event SSE schema (stream | resonance | bus | thought | + scene_begin | scene_end) +- The cockpit components (EnergyField, BusTicker, ThoughtLog, + SceneBreadcrumb, FreeEnergyDial) and their useShaderStream hook +- The Cypher scene file discovery via CYPHER_PATH +- The /demo-fallback route preserving the seed stubs +- The /api/graph/infer endpoint shape (graph_engine::nars_infer_handler) + +### What was theatre — to be deleted in Phase 2 +- Hand-rolled WireStreamDto / WireResonanceDto / WireBusDto / + WireThoughtStruct declared inline in + crates/cockpit-server/src/shader_stream.rs (commit 3d717b8, approx + lines 22-70). These were #[derive(Serialize)] structs with NO + connection to thinking_engine::dto. They duplicated the field names + and lied about the types — top_k: Vec<(u16, f32)> instead of the real + f32[4096] energy vector with a sparse projection. +- Simulated cognitive cycles: the scene player advanced cycle_count and + made up energy, entropy, active_count, converged, and top_k values + directly in the SSE loop. There was no ThinkingEngine, no perturb, no + think, no commit. The numbers came from per-act confidence and a + sine-ish ramp. +- Hashed codebook indices: there was no extract_cypher_identifiers(). + The loop ran DefaultHasher on whole tokens and modulo'd into 0..4096, + with no attention to whether 4096 was even the right width. The + constant CODEBOOK_SIZE lived nowhere — it was a magic number in two + unrelated places. +- Hand-rolled NARS in graph_engine.rs::run_nars_deduction: the body was + a literal `f = f1 * f2; c = f1 * f2 * c1 * c2` formula in a + triple-nested loop (graph_engine.rs lines ~205-265 in commit 3d717b8). + This is approximately the deduction rule, but it was open-coded + rather than calling causal_edge::TruthValue::deduction(&self, &other). + No revision, no abduction, no NAL-6 syntax variables, no + NarsTables-driven dispatch. A grader checking the truth-value algebra + against the canonical causal-edge crate would find numerical + divergence on any non-trivial chain. +- Bypassed Cypher parser: the scene player read raw .cypher files, + grabbed regex-extracted MATCH previews, and never invoked + lance_graph::parser::parse_cypher_query. The actual CypherQuery AST + (get_node_labels(), get_relationship_types(), ValueExpression:: + {Variable, Property, ScalarFunction, AggregateFunction}) was + untouched. +- Missing AriGraph tissue: the encounter-round ingest path + (aiwar_ingest::load_from_json) still landed in a TripletGraph scratch + buffer, not in lance_graph::graph::arigraph (the real AriGraph homing + mechanism). NARS deduction therefore ran on a free-floating triplet + pile with no homing locality, no BindSpace::write_gated_xor, no + BUNDLE discipline from .claude/rules/borrow-strategy.md. +- f32[4096] field omission: ResonanceDto::energy (the real one) is a + 16 KB tensor. Phase 1 never sent it, never summarised it from a real + source, never even allocated one. The "energy" field on the wire was + a scalar derived from act_index / total_acts. + +### Severity +Per .claude/rules/architectural-compliance.md, substituting a specified +component without asking is P0. Phase 1 did not formally substitute — +but it shipped a parallel implementation that papered over the absence +of thinking-engine. That is functionally equivalent and just as +dangerous: the next session reading the code would naturally extend the +fake DTOs rather than the real ones. Phase 2 deletes the parallel +implementation. + +--- + +## 2. Phase 2 Resolution — 12-Agent Partition Table + +Twelve agents, each owning a disjoint file set. Single commit at the +end. Each agent logs to /tmp/q2-agent-log.jsonl via the shared `tee -a` +contract. Agent #11 is this docs writer. + +| # | Agent | Owns | Outcome | +|---|---|---|---| +| 0 | main | swarm coordinator | dispatches, gates final commit | +| 1 | deps-wirer | Cargo.toml (workspace + cockpit-server) | path deps for lance-graph, thinking-engine, cognitive-shader-driver, lance-graph-contract, causal-edge | +| 2 | dto-bridge | crates/cockpit-server/src/dto_bridge.rs (NEW) | Wire* mirrors with From<&thinking_engine::dto::*>; sparse projection of f32[4096] | +| 3 | shader-stream-rewriter | crates/cockpit-server/src/shader_stream.rs | drives real ThinkingEngine::{perturb, think, commit}; deletes simulated cycle | +| 4 | scene-player | crates/cockpit-server/src/scene_player.rs (NEW) | parses Cypher via lance_graph::parser::parse_cypher_query, walks AST, emits real EngStreamDto | +| 5 | codebook | crates/cockpit-server/src/codebook.rs (NEW) | CODEBOOK_SIZE = 4096 mirror, token_to_index, extract_cypher_identifiers, deterministic | +| 6 | arigraph-nars-merger | crates/cockpit-server/src/graph_engine.rs | swap hand-rolled NARS for causal_edge::TruthValue::{deduction, revision}; route ingest through arigraph | +| 7 | fe-types | cockpit/src/hooks/useShaderStream.ts | sync TS event types to dto_bridge (sensor_contributions, tension_history_len, style_trajectory) | +| 8 | build-fixer | cargo check --workspace | resolves whatever 1-6 leave broken | +| 9 | e2e-runner | runs server + curl SSE | verifies six event types appear in real order with non-fabricated values | +| 10 | fallback-strengthener | cockpit/src/DemoApp.tsx, DataStatusBar.tsx | explicit FALLBACK / LIVE banner when shader is unreachable | +| 11 | docs-updater | .claude/plans/* | this document | +| 12 | lint-pass | cargo xtask lint, cargo fmt, hooks | final polish before commit | + +Dependency order: 1 -> (2, 5) -> (3, 4, 6) -> 7 -> 8 -> 9 -> 10 -> 12 +-> main commit. Agent 11 runs in parallel with anyone (only touches +.claude/plans/). + +--- + +## 3. Architecture Compliance Check + +Per .claude/rules/architectural-compliance.md, the user said +"use lance-graph as hot path". Verifying Phase 2 against that mandate: + +### Crates consumed (path deps to /home/user/lance-graph/crates/*) +- lance-graph — Cypher parser (parse_cypher_query) + AST + (CypherQuery::get_node_labels, ValueExpression::{Variable, Property, + ScalarFunction, AggregateFunction}) + arigraph for homing +- thinking-engine — ThinkingEngine, dto::{StreamDto, ResonanceDto, + BusDto, ThoughtStruct, SourceType, ThinkingScale}, + engine::CODEBOOK_SIZE +- cognitive-shader-driver — feature-gated lab endpoints (Option A from + the Apr 21 plan, deferred mounting to Phase 3 when models load) +- lance-graph-contract — nars::SemiringChoice (documentation value + only; semiring stays OUT of StreamDto/BusDto path per Phase 1 rule) +- causal-edge — CausalEdge64, NarsTables, TruthValue::{deduction, + revision, abduction} — replaces hand-rolled NARS in graph_engine.rs + +These are the EXACT crates wired in +crates/cockpit-server/Cargo.toml (lines 26-37 of the workspace block): + + lance-graph.workspace = true + thinking-engine.workspace = true + cognitive-shader-driver.workspace = true + lance-graph-contract.workspace = true + causal-edge.workspace = true + +### Compliance verdict +- Lance-graph IS the hot path: cockpit-server::shader_stream calls + thinking_engine::ThinkingEngine directly with no shim (see + shader_stream.rs line 26: `use thinking_engine::ThinkingEngine;`). +- No new external dependency was added in lieu of a specified one. +- Neo4j-rs remains feature-gated (neo4j-fallback, off by default) per + the Phase 1 plan. It is a data-source fallback, not an engine + substitute. +- Borrow strategy (.claude/rules/borrow-strategy.md): ThinkingEngine is + held in Arc<Mutex<_>> per SSE connection; perturb/think/commit follow + the readonly-BindSpace + owned-microcopy pattern internally. q2 does + not touch the BindSpace directly — it only goes through the engine's + public API, which already obeys the rule. + +--- + +## 4. What STAYS a Stub After Phase 2 (be honest) + +A full ThinkingEngine cycle that produces meaningful cognition needs +LOADED MODELS: + +- Jina v5 embeddings — populates the 4096x4096 codebook distance table; + without it, ThinkingEngine::new(distance_table) consumes a synthetic + matrix (Phase 2 builds an identity-ish placeholder in + crate::codebook::distance_table()). +- BGE-M3 — sparse + dense + ColBERT vectors for cross-encoder + retrieval; drives SourceType::BgeM3 ingestion in dto::StreamDto. +- Reader-LM — Qwen-finetuned reranker for SourceType::ReaderLm; + required for the sensor_contributions field on ThoughtStruct to + reflect real reranks. +- Qwen safetensors — the lab calibration endpoints + (/v1/shader/calibrate, /probe, /tensors, /sweep, /token-agreement) + all require the safetensors mounted at QWEN_TENSORS_PATH. + +q2 does NOT have these at runtime. Railway deploy and dev clones run +without GPU and without ~30 GB of model weights. So Phase 2 ships a +real engine running on a synthetic distance table with placeholder +SourceType annotations. The cockpit displays the real +ResonanceDto::energy field, computed by real MatVec cycles on the real +engine — but the energies represent diffusion across a placeholder +codebook, not real semantic distances between encoded thoughts. + +This is fine for the visual: the /reasoning page is honest about what +it shows (free-energy minimisation on a known toy field). It is NOT +fine if anyone interprets the BusTicker text as a real model output. +Hence the LIVE / FALLBACK / SYNTHETIC banner that +fallback-strengthener (agent 10) installs. + +### Plan: how models arrive +- Phase 3 introduces crates/cockpit-server/src/model_loader.rs with two + modes: (a) cold-mmap from a configured path, (b) lazy-download from a + signed URL. The synthetic distance table stays as the unit-test + fixture. +- Models live on disk under QUARTO_MODELS_DIR; if absent, Phase 2's + synthetic codebook continues to drive the engine (the binary + degrades, it does not crash). + +--- + +## 5. Phase 3 Preview + +After Phase 2 ships: + +- Real codebook: crate::codebook::distance_table() is replaced by a + function that mmaps jina_v5_distances.bin and validates the 4096x4096 + shape. Synthetic generator becomes the fallback only. +- Model loading: cognitive-shader-driver lab endpoints + (/v1/shader/calibrate, /probe, /tensors, /sweep, /token-agreement) + get mounted behind LAB_ENABLED=true. They consume real Qwen + safetensors. +- Full cognitive cycle: encounter rounds from + aiwar_ingest::load_from_json flow through arigraph::homing_write -> + BindSpace::write_gated_xor -> SSE clients see real ResonanceDto top-k + driven by Jina distances rather than the toy field. +- NAL-6 expansion: causal-edge::NarsTables gains the variable-binding + rules; graph_engine::run_nars_deduction is replaced by a single call + to NarsTables::dispatch_chain. +- 36-brain superposition (Phase 3 of the original Apr 21 plan): + parallel dispatches via WireStyleSelector::Ordinal(n), additive + energy merge in the cockpit. +- Stub deletion: orchestrator.rs (1563 LOC), graph-flow stub (171 LOC), + analyst.rs (371 LOC), thinking.rs (116 LOC), diagnostics.rs (334 LOC) + — see Phase 3 LOC budget in the Apr 21 plan. + +--- + +## 6. Test Plan Checklist + +These are the gates between Phase 2 commit and Phase 2 push. +e2e-runner (agent 9) is the primary executor; lint-pass (agent 12) +confirms formatter/lint pass; docs-updater (agent 11, this file) +records results in /tmp/q2-agent-log.jsonl under phase `done`. + +### Build / typecheck +- [ ] `cargo check -p cockpit-server` clean (no `unused`, no `dead_code`) +- [ ] `cargo check --workspace` clean +- [ ] `cargo nextest run -p cockpit-server` — at minimum the + dto_bridge::tests::* and codebook::tests::* modules pass +- [ ] `cargo xtask lint` clean (no external-sources/ references) +- [ ] `cargo fmt --check` clean + +### E2E SSE +- [ ] `cargo run -p cockpit-server` starts on :8080 without panic +- [ ] `curl -N http://localhost:8080/v1/shader/stream` emits all six + event types within 60 s: scene_begin, stream, resonance, bus, + thought, scene_end +- [ ] resonance.payload.top_k contains entries with 0 <= index < 4096 + and energies that change cycle-to-cycle (NOT a constant ramp) +- [ ] resonance.payload.cycle_count is monotonically increasing within + a scene; converged: true appears at least once across a 30-scene + run +- [ ] bus.payload.codebook_index correlates with the dominant peak in + the preceding resonance.payload.top_k (spot-check 3 acts) +- [ ] thought.payload.sensor_contributions is non-empty when the source + string matches jina|bge_m3|reader_lm|qwen +- [ ] /v1/shader/status returns the current scene name and act index + synchronously (not via the SSE channel) + +### Frontend type sync +- [ ] `cd cockpit && npm run build` succeeds with no TS errors +- [ ] cockpit/src/hooks/useShaderStream.ts imports types whose field + names match dto_bridge.rs exactly (source_type, top_k, + cycle_count, tension_history_len, style_trajectory, + sensor_contributions) +- [ ] /reasoning page renders all five components against a live SSE + stream; FreeEnergyDial shows F dropping below homeostasis at + least once per 30-scene run +- [ ] /demo-fallback page still renders with seed stubs when the SSE + endpoint is unreachable; the LIVE / FALLBACK banner is visible + +### NARS truth-value algebra +- [ ] graph_engine::run_nars_deduction no longer contains a literal + `f1 * f2 * c1 * c2` — the call site is + causal_edge::TruthValue::deduction(&ab, &bc) (or + NarsTables::dispatch) +- [ ] Deterministic test: feed + {(A,is,B,0.9,0.9), (B,is,C,0.8,0.9)}, assert deduction matches + causal_edge::TruthValue::deduction bit-for-bit (Phase 1's + hand-rolled formula will diverge in the third decimal place) +- [ ] Revision rule (TruthValue::revision) is exercised when two + encounter rounds carry the same triplet with different evidence +- [ ] /api/graph/infer?node_id=X returns inferences whose chain + provenance includes the correct (A,B,C) source triplets + +### Architectural compliance +- [ ] `grep -r "neo4j" crates/cockpit-server/src` returns only + feature-gated `#[cfg(feature = "neo4j-fallback")]` blocks +- [ ] `cargo tree -p cockpit-server | grep -E "lance-graph|thinking-engine|causal-edge"` + lists all five required crates as direct deps +- [ ] No WireStreamDto / WireResonanceDto / WireBusDto / + WireThoughtStruct is defined outside dto_bridge.rs +- [ ] No DefaultHasher is used to compute codebook indices in any file + under crates/cockpit-server/src/ +- [ ] Semiring fields do NOT appear in any SSE event payload + (`grep -r "semiring" cockpit/src` returns nothing) + +--- + +## 7. Notes for Future Sessions + +If you are reading this in a future compaction and the cockpit +mysteriously emits beautiful event streams that don't correspond to any +ThinkingEngine call: look first at the imports in +crates/cockpit-server/src/shader_stream.rs. If +`use thinking_engine::ThinkingEngine;` is missing, you are back in +Phase 1 theatre. Restore from this plan. + +If you discover a Phase 2 file that derives Serialize on a struct named +Wire* outside dto_bridge.rs, that's the smell. Either move the struct +into dto_bridge.rs with a From<&thinking_engine::dto::*> impl, or +delete it. + +If a future agent proposes "let's just hash the tokens for now", invoke +.claude/rules/architectural-compliance.md and refuse. The codebook is a +real artefact — synthetic when models aren't loaded, but always backed +by the same constant CODEBOOK_SIZE = 4096 declared in BOTH +crates/cockpit-server/src/codebook.rs AND +thinking_engine::engine::CODEBOOK_SIZE. They drift, the system breaks. diff --git a/.claude/prompts/CINEMATIC_FLYTHROUGH.md b/.claude/prompts/CINEMATIC_FLYTHROUGH.md new file mode 100644 index 000000000..a2d93d669 --- /dev/null +++ b/.claude/prompts/CINEMATIC_FLYTHROUGH.md @@ -0,0 +1,107 @@ +# Cinematic Flythrough — Live VizEngine Camera Paths + +## FIRST: Read .claude/prompts/VIZ_ENGINE_V8.md + +The VizEngine already runs at 30fps server-side, streaming FrameData via SSE. +Cinematics are NOT prerendered. They're scripted camera keyframes fed to the +same VizEngine tick loop. The cockpit Canvas paints live. Same engine, same +SSE, different camera. + +## Camera Keyframe API + +Add to viz_kernel.js: + +```javascript +globalThis.vizKernel.setCamera = function(x, y, zoom, rotation) { + // Transform all node positions relative to camera + // zoom < 1.0 = zoomed out (satellite), zoom > 1.0 = zoomed in (macro) + cameraX = x; + cameraY = y; + cameraZoom = zoom; + cameraRotation = rotation; +}; +``` + +getFrame() applies camera transform before returning node positions. +The cockpit Canvas doesn't know or care that the camera moved. + +## Four Cinematics + +### Satellite Zoom (5 seconds) +```javascript +function satelliteZoom(duration) { + const frames = duration * 30; + for (let i = 0; i < frames; i++) { + const t = i / frames; + vizKernel.setCamera(600, 400, 0.1 + t * 0.9, 0); + // zoom: 0.1 → 1.0 — cloud resolves to cockpit + } +} +``` + +### Drone Follow (10 seconds) +```javascript +function droneFollow(nodePath, duration) { + const framesPerNode = (duration * 30) / nodePath.length; + nodePath.forEach((nodeId, idx) => { + const node = nodes.find(n => n.id === nodeId); + // Smooth bezier interpolation to next node + for (let f = 0; f < framesPerNode; f++) { + const t = f / framesPerNode; + vizKernel.setCamera( + lerp(prevNode.x, node.x, t), + lerp(prevNode.y, node.y, t), + 2.0, 0 // macro zoom on the chain + ); + } + }); +} +``` + +### Orbital Flight (8 seconds) +```javascript +function orbitalFlight(centerX, centerY, radius, duration) { + const frames = duration * 30; + for (let i = 0; i < frames; i++) { + const angle = (i / frames) * 2 * Math.PI; + vizKernel.setCamera( + centerX + radius * Math.cos(angle), + centerY + radius * Math.sin(angle), + 0.8, + angle * (180 / Math.PI) + ); + } +} +``` + +### Temporal Growth (30 seconds, with thinking overlay) +Normal temporal playback via StreamingRunner. Camera stays fixed overhead. +Activation overlays do the visual work — no camera tricks needed. + +## Cockpit Integration + +Add a cinematic mode button to the graph toolbar: + +```typescript +const cinematicModes = ['satellite', 'drone', 'orbital', 'temporal']; + +function startCinematic(mode: string) { + fetch('/mcp/message', { + method: 'POST', + body: JSON.stringify({ + jsonrpc: '2.0', id: Date.now(), + method: 'tools/call', + params: { name: 'cinematic_start', arguments: { mode } } + }) + }); + // VizEngine handles camera path, SSE streams frames as usual +} +``` + +## What NOT to do + +- Do NOT prerender to PNG or MP4 +- Do NOT use ffmpeg or resvg +- Do NOT add build-time prerender to Dockerfile +- Do NOT create a separate rendering pipeline +- Same VizEngine, same SSE, same Canvas. Just camera keyframes. diff --git a/.claude/prompts/HYDRATION_SHOWOFFS.md b/.claude/prompts/HYDRATION_SHOWOFFS.md new file mode 100644 index 000000000..618f106cd --- /dev/null +++ b/.claude/prompts/HYDRATION_SHOWOFFS.md @@ -0,0 +1,167 @@ +# Hydration Showoffs — lance-graph Live Features + +## What's Implemented (295 tests, not stubs) + +### 1. HHTL Cascade Search +`cascade_search()` — 4-stage progressive neighborhood search. + +``` +HEEL: load 1 scent vector, compare 10K entries → 50 survivors (20μs) +HIP: load 50 survivors' scents, 2nd hop → 50 survivors (500μs) +TWIG: 3rd hop → 50 survivors (500μs) +LEAF: load cold fingerprints, exact verification → final results (100μs) + +TOTAL: 1.2MB loaded, 1.1ms, 200K nodes explored, 3 hops +``` + +**Cockpit showoff**: Status bar shows `HHTL: 200K explored · 3 hops · 1.1ms`. +Inspector shows which stage found the selected node (HEEL/HIP/TWIG/LEAF). +Graph colors nodes by discovery stage (bright = HEEL, fading = deeper hops). + +### 2. Semiring Path Algebra (7 variants) +Not just "shortest path" — algebraically composable traversals: + +| Semiring | Multiply | Add | Use Case | +|----------|----------|-----|----------| +| XorBundle | XOR | majority-vote | Path composition | +| BindFirst | XOR | first non-empty | BFS traversal | +| HammingMin | Hamming dist | min | Shortest path | +| SimilarityMax | similarity | max | Best match | +| Resonance | XOR bind | best-density | Query expansion | +| Boolean | AND | OR | Reachability | +| XorField | XOR | XOR | GF(2) algebra | + +**Cockpit showoff**: Graph toolbar gets a semiring selector dropdown next to +FORCE/CIRCULAR/HIERARCHY. Pick "HammingMin" → edges glow by shortest path +distance. Pick "Resonance" → nodes pulse by resonance density. Pick "Boolean" +→ reachable nodes highlight, unreachable dim. + +Neo4j GDS has PageRank, Louvain, betweenness. We have COMPOSABLE ALGEBRA. +You chain semirings. They run canned algorithms. + +### 3. SPO Triple Store + NARS Truth Values + +Every edge carries `TruthValue { frequency, confidence }`: +- `frequency` ∈ [0,1] — how often the relation holds +- `confidence` ∈ [0,1] — how certain we are +- `expectation()` = c * (f - 0.5) + 0.5 — single scalar truth + +Query functions: +- `query_forward(subject)` → all edges from this node +- `query_forward_gated(subject, min_truth)` → only confident edges +- `query_reverse(object)` → all edges TO this node +- `query_relation(predicate)` → all edges of a type +- `walk_chain_forward(start, hops)` → multi-hop traversal + +**Cockpit showoff**: Inspector shows NARS truth on each edge: +``` +→ DEVELOPED_BY Palantir f:0.95 c:0.87 e:0.89 +→ DEPLOYED_BY US DoD f:0.80 c:0.45 e:0.64 +← MONITORS Prometheus f:1.00 c:1.00 e:1.00 +``` +Edge thickness = confidence. Edge opacity = frequency. +A "truth gate" slider filters edges below threshold. + +### 4. Merkle Integrity Verification + +Each node has a `MerkleRoot` — a 48-bit seal over its fingerprint planes. +`verify_lineage()` checks if a node's ancestry is intact. +`verify_integrity()` checks if the node itself hasn't been tampered with. + +```rust +match bind_space.verify_integrity(node_addr) { + VerifyStatus::Valid => "✓ clean", + VerifyStatus::Corrupted => "✗ tampered", + VerifyStatus::NotFound => "? unknown", +} +``` + +**Cockpit showoff**: Inspector shows a green checkmark or red warning. +Graph nodes get a subtle shield icon for verified. During presentations: +"Every node has a cryptographic seal — you can prove this data hasn't been +modified since ingestion." + +### 5. Fingerprint Similarity (rabitQ-compatible) + +`label_fp("Palantir")` → 512-bit fingerprint +`hamming_distance(fp_a, fp_b)` → how different two entities are +`dispatch_hamming()` → SIMD-accelerated on ndarray (AVX2/AVX-512) + +**Cockpit showoff**: Type a label in the query bar → +"Find similar" button → HHTL cascade finds the 10 most similar nodes +by fingerprint distance. Graph highlights them with halos sized by similarity. + +### 6. GraphBLAS-style Sparse Matrix Ops + +`GrBMatrix` with CSR/CSC dual storage. `GrBVector` for sparse vectors. +Element-wise add/multiply with custom semirings. +Matrix-vector multiply for one-hop neighborhood expansion. + +**Cockpit showoff**: "Expand neighborhood" button on selected node. +Internally does `A × v` where A is the adjacency matrix and v is the +selection vector. Shows the algebraic operation in the status bar: +`A ⊗ v → 12 neighbors (SimilarityMax semiring, 0.3ms)` + +--- + +## What Neo4j GDS Has That We Replace + +| Neo4j GDS | lance-graph equivalent | +|-----------|----------------------| +| PageRank | SimilarityMax semiring on A^n × v | +| Louvain community | Resonance semiring clustering | +| Shortest path (Dijkstra) | HammingMin semiring chain walk | +| Node similarity | Fingerprint hamming distance | +| Link prediction | NARS truth value extrapolation | +| Graph projection | Already in-memory (blasgraph columnar) | +| Centrality | GrBMatrix diagonal from A × A^T | + +We don't have canned algorithms. We have the ALGEBRA that composes them. +A presentation slide: "Neo4j runs PageRank. We run any semiring you define." + +--- + +## Implementation in the Cockpit + +### Minimal (3 features, 1 day) + +1. **Truth values on edges**: Inspector shows f/c/e for each connection. + Edge rendering uses opacity=frequency, width=confidence. + +2. **Semiring selector**: Dropdown in graph toolbar. Switches edge + coloring/weighting between HammingMin, SimilarityMax, Resonance. + +3. **HHTL status**: Status bar shows cascade metrics after each query. + +### Medium (5 features, 3 days) + +4. **Merkle verification**: Shield icon on verified nodes. Click to verify. + +5. **Fingerprint similarity search**: "Find similar" button in inspector. + Highlights top-K by hamming distance. + +### Full (all 6, 1 week) + +6. **GraphBLAS expand**: "Expand" button does A × v with selected semiring. + Shows algebraic notation in status bar. + +--- + +## How To Wire + +The aiwar data needs to be ingested into the SPO store with truth values +assigned. For the demo, assign truth values from the enrichment Cypher files: + +- Edges from `aiwar_enrichment_grok_verified.cypher` get c:0.95 +- Edges from base `aiwar_full.cypher` get c:0.80 +- Edges from `aiwar_enrichment_epstein_v39_patch.cypher` get c:0.60 +- Enrichment version number maps to confidence (later = less certain) + +The HHTL cascade needs neighborhood vectors precomputed from the graph. +For 221 nodes this is trivial — precompute at startup, takes <100ms. + +The semiring selector just changes which `HdrSemiring` variant is used +for edge weight computation. The graph data stays the same. + +Merkle seals are computed at ingestion time — one `MerkleRoot::from_fingerprint()` +per node. Stored alongside the node. Verification is O(1) per node. diff --git a/.claude/prompts/NEURAL_CAUSALITY_VIZ.md b/.claude/prompts/NEURAL_CAUSALITY_VIZ.md new file mode 100644 index 000000000..ff3f8ea0a --- /dev/null +++ b/.claude/prompts/NEURAL_CAUSALITY_VIZ.md @@ -0,0 +1,518 @@ +# Neural Causality Graph — The Closer + +## What It Looks Like + +A live animated neural network visualization in the cockpit. +Not a heatmap bar. Not a progress indicator. A BRAIN THINKING. + +``` +┌─────────────────────────────────────────────────────────┐ +│ COGNITION TRACE │ +│ │ +│ ╭──╮ │ +│ ●━━▶│L1│━━━━● │ +│ input╰──╯ │ ╭──╮ ╭──╮ │ +│ ├━━▶│L2│━━━●━━━▶│L3│━━━╮ │ +│ │ ╰──╯ │ ╰──╯ │ │ +│ │ fp │ cascade │ │ +│ │ │ │ │ +│ │ ╭───╯ FOVEAL?│ │ +│ │ │ ╱ ╲ │ │ +│ │ │ ╱ ╲│ │ +│ │ ╭──╮ ╱ ╭──╮│ ╭──╮ │ +│ │ │L5│◀━━━╱ │L6│◀━━━▶│L7│ │ +│ │ ╰──╯ reason ╰──╯ ╰──╯ │ +│ │ ████████ memory plan │ +│ │ ACTIVE ██ │ │ +│ │ │ STAUNEN! │ │ +│ │ │ ★ ★ ★ │ │ +│ │ ╰━━━━━━╮ │ ╭━━━━╯ │ +│ │ ▼ ▼ ▼ │ +│ │ ╭──╮ ╭──╮ ╭──╮ ╭───╮ │ +│ │ │L8│━▶│L9│━▶│10│━▶│out│ │ +│ │ ╰──╯ ╰──╯ ╰──╯ ╰───╯ │ +│ │ action gen meta │ +│ │ │ +│ ● = signal particle (animated along edges) │ +│ ████ = layer activation intensity │ +│ ★ = NARS epiphany (inferred edge pops into existence) │ +│ dendrite growth = new connection appears during Staunen│ +└─────────────────────────────────────────────────────────┘ +``` + +## The Five Visual Primitives + +### 1. Signal Particles (information flow) + +Glowing dots that travel along edges between layers. +Speed = processing time. Brightness = data volume. + +```javascript +// Particle moves from L1 to L2 along the edge +particle = { + edge: [L1, L2], + progress: 0.0 → 1.0, // animated over 200ms + color: '#00bcd4', // teal + radius: 3, + glow: true, + trail: 0.3, // fading trail behind particle +} +``` + +When Layer 1 completes, a particle launches toward Layer 2. +When Layer 2 completes, particles fan out toward Layer 3. +Multiple particles can be in flight simultaneously. + +### 2. Layer Nodes (activation pulses) + +Each layer is a circle that PULSES when active. + +``` +Idle: dim outline, dark fill +Running: expanding ring animation (like sonar), bright fill +Complete: solid fill, intensity = processing time +Skipped: hollow, dashed outline (Foveal skip path) +``` + +Foveal pattern: L1 → L2 → L3 bright. Then L5 goes DASHED (skipped). +Signal particle takes the shortcut edge directly to L6. +The visual difference between "I know this" (skip) and "I need to think" +(full path) is immediately obvious. + +Parafoveal pattern: L1 → L2 → L3 → L5 all bright. L5 burns longest +(semiring reasoning). L6 pulses with amber if Staunen. + +### 3. Staunen Dendrite Growth (surprise = new connections) + +When Layer 6 detects Staunen (new learning), the visualization +GROWS NEW DENDRITES: + +```javascript +// A new edge materializes between two existing nodes +dendrite = { + from: L6, // memory consolidation + to: L7, // triggers replanning + growthDuration: 600, // ms to fully appear + style: { + start: { opacity: 0, width: 0, color: '#ffc107' }, // amber + end: { opacity: 1, width: 2, color: '#ffc107' }, + }, + // The edge literally grows from L6 toward L7 + // like a neural dendrite extending +} +``` + +The animation: a thin amber line GROWS outward from L6, +reaching toward L7. When it connects, L7 pulses (replanning triggered). +This is the "brain making a new connection" cliché — but earned, +because it's showing REAL graph topology change. + +Wisdom (no new learning): no new dendrites. The existing connections +pulse gently. Stability. + +### 4. NARS Epiphanies (inferred edges popping into existence) + +When semiring reasoning (L5) or NARS revision (L6) produces an +inferred edge, it appears as a BURST: + +```javascript +epiphany = { + // In the MAIN graph panel (not the cognition trace) + sourceNode: 'Palantir', + targetNode: 'Gotham', + inferredLabel: 'USES', + truth: { f: 0.86, c: 0.71 }, + + // Animation + appearAnimation: { + // 1. Flash: bright teal circle expands from midpoint + flash: { radius: 0 → 40, opacity: 1 → 0, duration: 300 }, + // 2. Edge materializes as dashed line + edge: { dashOffset: 100 → 0, opacity: 0 → 0.7, duration: 400 }, + // 3. Label fades in + label: { opacity: 0 → 1, duration: 200 }, + // 4. Truth badge appears + badge: { scale: 0 → 1, duration: 150 }, + } +} +``` + +The sequence: FLASH at the midpoint → dashed line grows outward +in both directions → label fades in → small badge shows `f:0.86 c:0.71`. + +Multiple epiphanies during a reasoning burst create a "popcorn" effect +— connections popping into existence across the graph. + +If a later version CONFIRMS the inference (truth gets revised UP), +the dashed line solidifies with a brief glow. +If CONTRADICTED (truth revised DOWN), the line fades with a red flash. + +### 5. PET Scan Heatmap (accumulated trace) + +Below the neural graph, a horizontal heatmap strip accumulates +across versions: + +``` +Version: v00 v01 v31 v32 v33 v34 v35 ... v42 +L1: ██ ██ ██ ██ ██ ██ ██ ██ +L2: ██ ██ ██ ██ ██ ██ ██ ██ +L3: ██ ██ ██ ██ ██ ██ ██ ██ +L5: ·· ██ ████ ████ ██ ·· ·· ·· +L6: ██ ██ ██ ██ ██ ██ ██ ██ +L7: ·· ·· ████ ██ ·· ·· ·· ·· +L8: ██ ██ ██ ██ ██ ██ ██ ██ +L9: ██ ██ ██ ██ ██ ██ ██ ██ +L10: ██ ██ ██ ██ ██ ██ ██ ██ + ───────────────────────────────────────── +Seal: S S S S S W W W +``` + +S = Staunen (amber), W = Wisdom (green), ·· = skipped (dim) +Intensity = processing time at that layer for that version. + +The pattern tells a story: v31-v33 light up Layer 5 and 7 heavily +(Epstein enrichment triggers reasoning and replanning). v35 onward +calms down (Wisdom — the graph stabilized). You can SEE where the +graph "learned the most." + +## Implementation + +### Technology + +Canvas + requestAnimationFrame for particles and animations. +SVG for the layer topology (static structure). +CSS animations for pulses and flashes. +No three.js needed — 2D is more readable for this. + +### Data Source + +StreamingRunner from rs-graph-llm emits StreamChunks: + +```rust +enum StreamChunk { + LayerStarted { layer_id: String, version: usize }, + LayerCompleted { layer_id: String, elapsed_ms: u64, version: usize }, + LayerSkipped { layer_id: String, reason: String }, + InferredEdge { source: String, target: String, truth: TruthValue }, + SealStatus { version: usize, status: GraphSealStatus }, + DendriteGrowth { from_layer: String, to_layer: String }, +} +``` + +The cockpit component subscribes to SSE and dispatches animations: + +```typescript +sse.onmessage = (event) => { + const chunk = JSON.parse(event.data); + switch (chunk.type) { + case 'LayerStarted': + cogGraph.activateNode(chunk.layer_id); + break; + case 'LayerCompleted': + cogGraph.completeNode(chunk.layer_id, chunk.elapsed_ms); + cogGraph.launchParticle(chunk.layer_id, nextLayer(chunk.layer_id)); + break; + case 'LayerSkipped': + cogGraph.skipNode(chunk.layer_id); + cogGraph.launchParticle(prevLayer(chunk.layer_id), skipTarget(chunk.layer_id)); + break; + case 'InferredEdge': + mainGraph.showEpiphany(chunk.source, chunk.target, chunk.truth); + break; + case 'SealStatus': + heatmap.addColumn(chunk.version, chunk.status); + if (chunk.status === 'Staunen') { + cogGraph.growDendrite('memory_consolidate', 'planning'); + } + break; + } +}; +``` + +### Cockpit Layout Change + +The cognition trace replaces the left rail (or shares it as a tab): + +``` +┌──────────┬──────────────────┬──────────┐ +│ COGNITION│ GRAPH │INSPECTOR │ +│ TRACE │ (main data) │ │ +│ │ │ │ +│ [neural │ [force-directed │ [node │ +│ anim] │ with epiphany │ props] │ +│ │ bursts] │ │ +│ │ │ │ +│ [PET │ │ │ +│ heatmap]│ │ │ +├──────────┴──────────────────┴──────────┤ +│ RESULT TABLE │ +├────────────────────────────────────────┤ +│ CELL STRIP │ +└────────────────────────────────────────┘ +``` + +Or as a toggleable overlay on the graph panel itself (press `T` for +trace mode — the neural graph fades in on top of the data graph +with 50% opacity, showing the thinking process overlaid on the data). + +### Component: CognitionTrace.tsx + +```typescript +interface CognitionTraceProps { + // Layer topology (static, from thinking graph definition) + layers: LayerDef[]; + edges: LayerEdge[]; + conditionalEdges: ConditionalEdge[]; + + // Live state (from SSE) + activeLayer: string | null; + completedLayers: Map<string, { elapsed_ms: number }>; + skippedLayers: Set<string>; + particles: Particle[]; + dendrites: Dendrite[]; + epiphanies: Epiphany[]; + sealHistory: SealEntry[]; +} +``` + +### Animation Constants + +```css +:root { + --particle-speed: 200ms; + --pulse-duration: 600ms; + --dendrite-growth: 600ms; + --epiphany-flash: 300ms; + --epiphany-edge: 400ms; + --trail-fade: 150ms; + + --color-foveal: #00bcd4; /* teal — familiar, fast */ + --color-parafoveal: #7c4dff; /* purple — novel, reasoning */ + --color-staunen: #ffc107; /* amber — surprise, growth */ + --color-wisdom: #4caf50; /* green — stable, known */ + --color-epiphany: #00e5ff; /* bright cyan — new inference */ + --color-contradiction: #ff1744; /* red — inference disproven */ +} +``` + +## The 10-Second Demo Script + +``` +0s: Cockpit loads. Cognition trace panel shows 10 idle layer nodes. + Main graph shows base aiwar data (221 nodes). + Play button at bottom: [▶ ⏸] with version timeline. + +1s: Press play. v00 loads. + L1 pulses → particle launches → L2 pulses → L3 pulses. + L3 classifies: "Foveal" (familiar base data). + L5 goes DASHED (skipped). Particle takes shortcut to L6. + L6: Wisdom (green). No new learning. Clean pass. + PET heatmap: first column, all green. + +3s: v01 enrichment arrives. + L1 → L2 → L3: "Parafoveal" (novel data!). + Particle takes the LONG path through L5. + L5 burns bright purple — semiring reasoning running. + Three epiphany bursts in the main graph: + FLASH → dashed line → "CONNECTED_TO" → f:0.78 c:0.65 + FLASH → dashed line → "DEVELOPED_BY" → f:0.85 c:0.72 + FLASH → dashed line → "DEPLOYED_BY" → f:0.90 c:0.80 + L6: STAUNEN! Amber dendrite GROWS from L6 → L7. + L7 pulses (replanning). L8 → L9 → L10. + PET heatmap: second column, L5 bright, L7 bright. + +5s: v31 (Epstein enrichment) arrives. + L3: "Parafoveal" — this is VERY novel. + L5 BURNS — longest activation yet. Multiple inference chains. + SIX epiphany bursts in quick succession (popcorn effect). + The audience watches connections literally pop into existence. + L6: STAUNEN again. Another dendrite grows. + One of the v01 inferred edges gets CONFIRMED — + dashed line solidifies with a glow. truth: c:0.65 → c:0.78. + +7s: v35 arrives. L3: still Parafoveal but calmer. + L5 runs but shorter. Two epiphanies. + One v31 inference gets CONTRADICTED — + dashed line flashes RED and fades. Dead end. + L6: Wisdom. No new dendrites. Stabilizing. + +9s: v42 arrives. L3: "Foveal" — we've seen this pattern. + L5 SKIPPED (dashed). Fast path. + L6: Wisdom. Green column in heatmap. + The graph has learned everything the data has to offer. + Status bar: "42 versions · 23 inferred · 19 confirmed · 4 contradicted" + +10s: Play stops. The neural graph dims to a gentle idle pulse. + The PET heatmap tells the whole story: + early versions = lots of reasoning (purple L5). + middle versions = surprises and replanning (amber L6/L7). + late versions = calm, Foveal, Wisdom (green, L5 skipped). + The graph learned, stabilized, and is now WISE. +``` + +That's the closer. The room doesn't need to understand NARS or +semirings or ZeckF64. They see a brain thinking. They see it +surprised. They see it making connections. They see it calm down. +They see it become wise. + +--- + +## ADDENDUM: The Graph IS the Brain + +Forget the separate cognition trace panel. The aiwar graph itself +IS the neural network. The 221 nodes ARE the neurons. The 356 edges +ARE the dendrites. The thinking layers map onto REGIONS of the graph. + +### How It Works + +When the thinking graph processes a version, the layers don't +light up in a separate diagram. They light up IN the data graph: + +``` +Layer 1 (Sensory Ingest): + → ALL nodes briefly flash (data arriving) + → Intensity = how much new data this version adds + +Layer 2 (Fingerprint): + → Nodes that MATCH the new data's fingerprint glow teal + → The cascade search narrows to a REGION of the graph + +Layer 3 (Cascade Search / Foveal vs Parafoveal): + → Foveal: matched region stays teal (familiar, calm) + → Parafoveal: matched region shifts to PURPLE (novel, needs reasoning) + → The rest of the graph dims to 20% opacity + → Spotlight effect: you see WHERE the thinking is happening + +Layer 5 (Semiring Reasoning): + → Signal particles travel along edges in the ACTIVE region + → Each inference chain = a particle trail through connected nodes + → The path glows behind the particle (like a neon trace) + → Multiple chains = multiple particles = the region BUZZES + +Layer 6 (Memory Consolidation): + → Staunen: the active region PULSES amber. New dendrites grow + (new edges materialize between nodes that weren't connected) + → Wisdom: the active region settles to calm green glow + → The rest of the graph slowly fades back to normal + +NARS Epiphanies: + → Inferred edges don't just pop up — they GROW between nodes + → The two nodes flash, a dashed line extends from both sides + → They meet in the middle with a bright flash + → Like synapses forming in real time +``` + +### The Visual Effect + +The whole graph is a dark cloud. When play starts: + +``` +v00: All nodes briefly illuminate (base data loads). + Then they settle to dim default state. + +v01: A CLUSTER of nodes lights up (enrichment touches these). + The cluster shifts from teal to purple (Parafoveal). + Signal particles run through the cluster. + Three new edges grow outward. Epiphany flashes. + The cluster settles. Rest of graph stays dim. + +v31: A DIFFERENT region lights up (Epstein network). + This region burns BRIGHT — heavy reasoning. + Particles trace paths: Epstein → MIT → Thiel → Palantir. + Six epiphanies pop. The region is buzzing. + Staunen: amber pulse ripples outward from the epicenter. + New dendrites grow from Epstein cluster toward Palantir cluster. + The two regions are now connected where they weren't before. + +v35: The same region activates but CALMER. + Some particles, fewer epiphanies. + One inference gets contradicted — red flash, edge fades. + Layer 6: Wisdom. Green calm. The cluster dims. + +v42: Brief teal flash (Foveal — seen this before). + Almost instant. No purple. No particles. + The graph knows everything now. + Settled. Breathing gently. Wise. +``` + +### Color Language (no legend needed — intuitive) + +``` +DIM GREY: idle / unaffected nodes +TEAL GLOW: Foveal — recognized, familiar, fast path +PURPLE GLOW: Parafoveal — novel, under active reasoning +AMBER PULSE: Staunen — surprise, new learning, dendrite growth +GREEN SETTLE: Wisdom — stable, consolidated, known +BRIGHT CYAN: epiphany flash — new inference born +RED FLASH: contradiction — inference disproven +WHITE: signal particle — information flowing +``` + +### The PET Heatmap Becomes a Timeline Sparkline + +Instead of a grid, show a thin sparkline strip below the graph: + +``` +────────────────────────────────────────────────── +v00 ▁▁ v01 ▃▅ v31 ▇█▇ v32 ▅▃ v35 ▂▁ v42 ▁ +────────────────────────────────────────────────── +``` + +Height = total reasoning intensity for that version. +Color = dominant state (teal/purple/amber/green). +Click any point → graph rewinds to that version's activation state. + +### Implementation: Overlay Mode + +Don't render two graphs. Render ONE graph with an activation overlay: + +```typescript +interface NodeActivation { + nodeId: string; + layer: number; // which thinking layer activated this node + intensity: number; // 0.0 to 1.0 + color: string; // teal / purple / amber / green + particleTarget?: string; // if a signal particle should launch toward this node +} + +interface GraphState { + nodes: Node[]; // static data (label, type, position) + edges: Edge[]; // static connections + activations: Map<string, NodeActivation>; // live overlay + particles: Particle[]; // in-flight signal particles + epiphanies: Epiphany[]; // pending edge births + globalDim: number; // 0.2 when spotlight active, 1.0 when idle +} +``` + +vis-network supports custom node rendering. Each frame: +1. Check if node has an activation → apply glow color + intensity +2. Check if node is outside active region → apply globalDim +3. Draw particles along edges between activated nodes +4. Animate epiphany edge births + +### The Breathing Idle State + +When not playing, the graph doesn't go static. It BREATHES: + +```javascript +// Gentle sine wave on all node opacity +const breath = 0.85 + 0.15 * Math.sin(Date.now() / 2000); +nodes.forEach(n => n.opacity = breath); +``` + +Subtle. Almost subliminal. The graph is alive. It's resting, not dead. +When play starts, the breathing accelerates slightly before the first +activation — like an intake of breath before thinking. + +### Sound (optional, for installations) + +If the presentation has audio: +- Particle movement: soft tick (like a Geiger counter, one per particle) +- Epiphany: crystalline chime +- Staunen: low resonant hum +- Wisdom: silence (the absence of sound IS the signal) +- Breathing: very faint ambient pad, barely perceptible + +Sarah Ciston built the original aiwar as a "tangible interactive installation." +This makes it one again — but the installation is the graph THINKING. diff --git a/.claude/prompts/PREP_DUAL_PATH.md b/.claude/prompts/PREP_DUAL_PATH.md new file mode 100644 index 000000000..7cca6da8e --- /dev/null +++ b/.claude/prompts/PREP_DUAL_PATH.md @@ -0,0 +1,239 @@ +# Dual-Path Prep — Hot (lance-graph) + Cold (Neo4j) + +## The Data + +`aiwar-neo4j-harvest/data/aiwar_graph.json`: +- 221 nodes: 65 Systems, 23 Civic, 7 Historical, 114 Stakeholders, 12 People +- 356 edges: 95 connection, 114 developed, 79 deployed, 21 place, 22 people, 25 hierarchical +- 31-row schema ontology (12 taxonomy axes) +- Plus 30 Cypher enrichment files (~600KB additional graph data) + +## Hot Path: lance-graph DataFusion (primary) + +### Step 1: Convert aiwar JSON → Parquet + +Read `data/aiwar_graph.json`. Produce 5 node tables + 6 edge tables as Parquet files. + +``` +data/parquet/ +├── nodes_systems.parquet # 65 rows, 20 columns +├── nodes_civic.parquet # 23 rows +├── nodes_historical.parquet # 7 rows +├── nodes_stakeholders.parquet # 114 rows +├── nodes_people.parquet # 12 rows +├── edges_connection.parquet # 95 rows (source, target, label, weight, hover, reference) +├── edges_developed.parquet # 114 rows +├── edges_deployed.parquet # 79 rows +├── edges_place.parquet # 21 rows +├── edges_people.parquet # 22 rows +└── edges_hierarchical.parquet # 25 rows (source, target only) +``` + +Write a Rust binary (`crates/aiwar-ingest/src/main.rs`) that does this. +Use `arrow` + `parquet` crates. No Python. + +```rust +// Read JSON, build Arrow RecordBatches, write Parquet +let systems: Vec<System> = serde_json::from_value(graph["N_Systems"].clone())?; +let batch = systems_to_record_batch(&systems)?; +let file = File::create("data/parquet/nodes_systems.parquet")?; +let writer = ArrowWriter::try_new(file, batch.schema(), None)?; +writer.write(&batch)?; +writer.close()?; +``` + +### Step 2: Wire GraphConfig for lance-graph + +lance-graph needs a `GraphConfig` mapping labels to tables: + +```rust +let config = GraphConfig::builder() + // Nodes + .with_node_label("System", "id") // nodes_systems.parquet + .with_node_label("Civic", "id") // nodes_civic.parquet + .with_node_label("Historical", "id") // nodes_historical.parquet + .with_node_label("Stakeholder", "id") // nodes_stakeholders.parquet + .with_node_label("Person", "id") // nodes_people.parquet + // Edges + .with_relationship("CONNECTED_TO", "source", "target") // edges_connection + .with_relationship("DEVELOPED_BY", "source", "target") // edges_developed + .with_relationship("DEPLOYED_BY", "source", "target") // edges_deployed + .with_relationship("USED_IN", "source", "target") // edges_place + .with_relationship("PERSON_LINK", "source", "target") // edges_people + .with_relationship("HIERARCHICAL", "source", "target") // edges_hierarchical + .build()?; +``` + +### Step 3: Register Parquet tables with DataFusion + +```rust +use datafusion::prelude::*; + +let ctx = SessionContext::new(); +ctx.register_parquet("nodes_systems", "data/parquet/nodes_systems.parquet", ParquetReadOptions::default()).await?; +ctx.register_parquet("nodes_stakeholders", "data/parquet/nodes_stakeholders.parquet", ParquetReadOptions::default()).await?; +ctx.register_parquet("edges_developed", "data/parquet/edges_developed.parquet", ParquetReadOptions::default()).await?; +// ... all 11 tables + +// Now Cypher queries work: +let query = CypherQuery::new("MATCH (s:System)-[:DEVELOPED_BY]->(st:Stakeholder) RETURN s.name, st.name")? + .with_config(config); +let batches = query.execute(&ctx).await?; +``` + +### Step 4: blasgraph projection (bgz17/rabitQ) + +After Parquet tables are loaded, project into blasgraph's columnar format +for HHTL (Heel-Hip-Twig-Leaf) compressed storage: + +```rust +use lance_graph::graph::blasgraph::columnar::NodeSchema; +use lance_graph::graph::blasgraph::BlasGraph; + +// Build blasgraph from the DataFusion tables +let blasgraph = BlasGraph::from_datafusion(&ctx, &config).await?; +// Now semiring operations work on compressed columnar data +// Neighborhood queries use rabitQ-compatible distance +``` + +This is the fast path. Queries hit Arrow memory, not a network database. + +### Step 5: Wire into q2 notebook-query stub + +Replace `crates/stubs/notebook-query/` with real lance-graph execution: + +```rust +// notebook-query/src/lib.rs +pub fn execute(code: &str, lang: QueryLanguage) -> Result<QueryResult> { + match lang { + QueryLanguage::Cypher => { + let query = CypherQuery::new(code)? + .with_config(HOT_CONFIG.clone()); + let batches = RUNTIME.block_on(query.execute(&SESSION))?; + Ok(batches_to_query_result(batches)) + } + QueryLanguage::Gremlin => { + // Translate Gremlin to Cypher, then execute + // (or use lance-graph's native planner if it supports Gremlin) + todo!("Gremlin→Cypher transpiler") + } + _ => { /* ... */ } + } +} +``` + +## Cold Path: Neo4j Aura (fallback) + +### Step 1: Load into Neo4j (already works) + +```bash +cd aiwar-neo4j-harvest +NEO4J_URI="neo4j+s://7e137e6e.databases.neo4j.io" \ +NEO4J_USER="neo4j" \ +NEO4J_PASSWORD="O-EXvpDXZBoIIH9SvmCiXobcGcMt81oEgmpS405hs1o" \ +cargo run -- neo4j +``` + +This runs the existing `cmd_cypher()` → `cmd_neo4j()` pipeline. +Loads all 30 Cypher files. Already tested. + +### Step 2: neo4j-rs fallback in notebook-query + +```rust +// If hot path fails, fall back to cold +pub async fn execute_with_fallback(code: &str) -> Result<QueryResult> { + // Try hot path first + match execute_hot(code).await { + Ok(result) => Ok(result), + Err(hot_err) => { + tracing::warn!("Hot path failed: {}, falling back to Neo4j", hot_err); + execute_cold(code).await + } + } +} + +async fn execute_cold(code: &str) -> Result<QueryResult> { + let graph = neo4rs::Graph::new( + "neo4j+s://7e137e6e.databases.neo4j.io", + "neo4j", + &std::env::var("NEO4J_PASSWORD")? + ).await?; + let mut result = graph.execute(neo4rs::query(code)).await?; + // Convert neo4rs rows → QueryResult +} +``` + +### Step 3: Sync job (keep cold current) + +When hot path data changes, push to Neo4j: + +```rust +async fn sync_to_neo4j(hot_batches: &[RecordBatch]) -> Result<()> { + let graph = neo4rs::Graph::new(/* ... */).await?; + for batch in hot_batches { + let cypher = batch_to_merge_cypher(batch); + graph.run(neo4rs::query(&cypher)).await?; + } + Ok(()) +} +``` + +## Railway Deployment + +### Service: q2-notebook + +```toml +# railway.toml +[build] +builder = "dockerfile" + +[deploy] +startCommand = "./target/release/quarto notebook serve --host 0.0.0.0 --port $PORT --frontend-dir cockpit/dist" +healthcheckPath = "/health" +``` + +```dockerfile +FROM rust:1.85 AS builder +WORKDIR /app +COPY . . +RUN cargo build --release -p quarto + +FROM node:20 AS frontend +WORKDIR /app/cockpit +COPY cockpit/ . +RUN npm install && npm run build + +FROM debian:bookworm-slim +COPY --from=builder /app/target/release/quarto /usr/local/bin/ +COPY --from=frontend /app/cockpit/dist /opt/cockpit/dist +COPY data/parquet/ /opt/data/parquet/ +ENV PORT=2718 +CMD ["quarto", "notebook", "serve", "--host", "0.0.0.0", "--port", "2718", "--frontend-dir", "/opt/cockpit/dist"] +``` + +### Environment variables + +``` +NEO4J_URI=neo4j+s://7e137e6e.databases.neo4j.io +NEO4J_USER=neo4j +NEO4J_PASSWORD=*** +AIWAR_DATA_DIR=/opt/data/parquet +``` + +## Execution Order + +1. `aiwar-ingest` — convert JSON → Parquet (run once, commit Parquet files) +2. Wire lance-graph `GraphConfig` + DataFusion session in q2 +3. Replace notebook-query stub with real lance-graph execution +4. Test locally: `q2 notebook serve` → type Cypher → see real aiwar graph +5. Load Neo4j Aura as cold backup +6. Deploy to Railway +7. Present: type `MATCH (s:System)-[:DEVELOPED_BY]->(st:Stakeholder) RETURN s, st` → see graph + +## What This Proves + +A data engineer types Cypher into the cockpit. The query hits lance-graph +DataFusion (Arrow in memory, no network hop). Results render as an interactive +force-directed graph with 221 nodes and 356 edges. If lance-graph fails, +Neo4j Aura takes over transparently. No Grafana needed — the cockpit IS +the dashboard. diff --git a/.claude/prompts/REASONING_PLAYBACK.md b/.claude/prompts/REASONING_PLAYBACK.md new file mode 100644 index 000000000..4b10344ac --- /dev/null +++ b/.claude/prompts/REASONING_PLAYBACK.md @@ -0,0 +1,240 @@ +# Reasoning Playback — 3 Generations Ahead + +## What Already Exists (implemented, tested) + +```rust +// NARS truth revision — combines evidence from multiple sources +truth_a.revision(&truth_b) → TruthValue { frequency, confidence } + +// Chain walk — multi-hop greedy traversal with cumulative distance +spo_store.walk_chain_forward(start, radius, max_hops) → Vec<TraversalHop> + +// Versioned graph — Lance ACID snapshots, time-travel queries +versioned_graph.at_version(n) // read any historical state +graph_seal_check(v1, v2) → Wisdom | Staunen // did learning occur? + +// ZeckF64 progressive encoding — 94% precision in 1 byte +byte 0: scent (7 close-bits) → ρ=0.937, 6144× compression +bytes 0-7: full resolution → ρ=0.982, 862× compression +``` + +## Feature 1: Temporal Play Button (1 day) + +The 30 Cypher enrichment files ARE timestamped versions: +``` +v00: aiwar_full.cypher (base graph, 221 nodes) +v01: aiwar_enriched.cypher (first enrichment) +v31: aiwar_enrichment_epstein_v31_patch (evidence accumulates) +v32: aiwar_enrichment_epstein_v32_patch (more evidence) +... +v42: aiwar_enrichment_v42_bilderberg (latest) +``` + +Each file = one `commit_encounter_round()` in the versioned graph. +Each version gets a Merkle seal. Between versions: `Wisdom` (nothing changed) +or `Staunen` (new learning occurred). + +### The Play Button + +``` +[◀ ⏸ ▶ ⏩] ─────●────────────── v42 + v00 v01 v31 v42 +``` + +Press play: +- v00 loads: 221 nodes, 356 edges appear in cockpit +- v01: 45 new edges fade in (enrichment). Status: `Staunen — 45 new edges` +- v31: Epstein connections appear as dashed lines (c:0.60) + - NARS `revision()` runs: edges that were c:0.60 in v31 get revised + UP to c:0.72 by v35 (more corroborating evidence) +- v42: full graph. Status bar: `Wisdom — stable since v40` + +The graph GROWS in front of you. Truth values STRENGTHEN as evidence +accumulates. The seal check shows WHEN new learning occurred. + +### Proc Macro + +```rust +#[derive(EncounterRound)] +struct EpsteinV31 { + #[source = "cypher/aiwar_enrichment_epstein_v31_patch.cypher"] + #[confidence = 0.60] + edges: Vec<Edge>, +} +``` + +The macro: +1. Parses the Cypher file at compile time +2. Generates an `impl EncounterRound` that loads the edges +3. Assigns truth values from the `#[confidence]` attribute +4. Registers with the versioned graph as a named version + +All 30 files become 30 typed structs. `cargo build` validates them. + +## Feature 2: NARS Abductive Inference (2 days) + +Chain walk + truth revision = INFER edges that don't exist yet. + +``` +Known: Palantir →DEVELOPED_BY→ US_DoD (f:0.95, c:0.87) +Known: US_DoD →DEPLOYED_BY→ Gotham (f:0.90, c:0.82) +Infer: Palantir →USES→ Gotham (f:0.86, c:0.71) ← abducted +``` + +The math: +```rust +// Deduction: if A→B and B→C, then A→C +fn nars_deduction(ab: &TruthValue, bc: &TruthValue) -> TruthValue { + let f = ab.frequency * bc.frequency; + let c = ab.confidence * bc.confidence * ab.frequency * bc.frequency; + TruthValue::new(f, c) +} + +// Abduction: if A→B and C→B, then A→C (weaker) +fn nars_abduction(ab: &TruthValue, cb: &TruthValue) -> TruthValue { + let f = ab.frequency; + let c = ab.confidence * cb.confidence * cb.frequency; + TruthValue::new(f, c) +} +``` + +### In the Cockpit + +Toggle: `[Show inferred edges]` + +Inferred edges render as DASHED lines with lower opacity. +Hover shows the inference chain: +``` +Inferred: Palantir → Gotham + Via: Palantir →(0.95)→ US_DoD →(0.90)→ Gotham + Truth: f:0.86 c:0.71 (deduction) + Hops: 2 +``` + +Click "Verify" → runs `walk_chain_forward()` to show the full path. +Click "Accept" → promotes to a real edge with c:0.71 (new encounter round). +Click "Reject" → adds a negative evidence edge (f:0.0, c:0.71). + +### Proc Macro + +```rust +#[derive(InferenceRule)] +#[rule = "deduction"] // or "abduction", "induction" +#[max_hops = 3] +#[min_confidence = 0.5] +struct TransitiveDeveloper; + +// Generates: +impl InferenceRule for TransitiveDeveloper { + fn apply(store: &SpoStore) -> Vec<InferredEdge> { + // For every A→B→C chain where both edges have c > 0.5, + // infer A→C with deduction truth + } +} +``` + +Register rules. Press play. Inferred edges appear as the temporal +playback progresses. New evidence in v35 might CONFIRM a v31 inference, +strengthening it via `revision()`. Or CONTRADICT it, weakening it. + +## Feature 3: Progressive Hydration Lens (1 day) + +ZeckF64 progressive encoding means you can show the graph at +different "resolution levels" without reloading: + +``` +Level 0 (1 byte/edge): Scent only. Binary: connected or not. + Fast, 94% accurate. Good for overview. + +Level 1 (2 bytes/edge): Scent + SPO distance quantile. + Edge thickness reflects similarity. + 96% accurate. + +Level 7 (8 bytes/edge): Full resolution. All 7 distance quantiles. + 98% accurate. Full detail. +``` + +### In the Cockpit + +A "resolution" slider in the graph toolbar: + +``` +Resolution: [●━━━━━━━━━━━━] 1 byte → nodes: 221, edges: 356, ρ=0.937 +Resolution: [━━━━━●━━━━━━━] 4 bytes → nodes: 221, edges: 289, ρ=0.968 +Resolution: [━━━━━━━━━━━━●] 8 bytes → nodes: 221, edges: 201, ρ=0.982 +``` + +At low resolution: everything is connected (scent says "close enough"). +Slide right: weak connections fade, strong ones sharpen. The graph +CLARIFIES in real time. Like focusing a microscope. + +This is progressive JPEG for graphs. Nobody has this. + +### No Macro Needed + +ZeckF64 already packs the bytes. Just mask: +```rust +fn edge_at_resolution(edge: u64, bytes: usize) -> u64 { + let mask = match bytes { + 1 => 0xFF, + 2 => 0xFFFF, + 4 => 0xFFFF_FFFF, + _ => u64::MAX, + }; + edge & mask +} + +fn edge_passes_threshold(edge: u64, bytes: usize, threshold: u8) -> bool { + let scent = (edge & 0xFF) as u8; + let close_bits = (scent & 0x7F).count_ones(); + close_bits >= threshold as u32 +} +``` + +The slider just changes `bytes` and `threshold`. Graph re-renders instantly +because it's a bitmask, not a re-query. + +--- + +## Composition: The Full Demo + +Press play. This happens: + +``` +0s: Base graph loads (v00). 221 nodes. Resolution: 1 byte (overview). +2s: Enrichment v01 fades in. New edges appear. + NARS revision runs. Some edges get thicker (more confident). +4s: Epstein v31 arrives. Dashed inference lines appear + (abducted connections). Status: "Staunen — 23 inferred edges" +6s: v32-v35 stream in. Inferences either STRENGTHEN (line solidifies) + or WEAKEN (line fades). revision() runs on each. +8s: Slide resolution from 1→4 bytes. Weak connections vanish. + Strong structure emerges. The graph CLARIFIES. +10s: v40-v42. Status: "Wisdom — stable". No new learning. + Final graph: 221 nodes, 180 strong edges, 23 inferred, + 12 verified by Merkle seal check. +``` + +Total demo: 10 seconds. Shows: +1. Temporal graph evolution (versioned + seal check) +2. Live reasoning (NARS revision + abductive inference) +3. Progressive focus (ZeckF64 resolution slider) +4. Integrity verification (Merkle seals) +5. Algebraic path computation (semiring selector) + +What Neo4j shows in a demo: "Here's PageRank. Here's Louvain. Here's centrality." +What we show: "Press play and watch the graph THINK." + +--- + +## Implementation Effort + +| Feature | Existing Code | New Code | Time | +|---------|--------------|----------|------| +| Play button | VersionedGraph, seal_check | Cockpit timeline component, encounter round loader | 1 day | +| NARS inference | revision(), walk_chain_forward() | Deduction/abduction functions (20 lines each), cockpit toggle | 2 days | +| Progressive lens | ZeckF64, edge_at_resolution | Cockpit slider, bitmask filter | 1 day | +| Proc macros | — | #[derive(EncounterRound)], #[derive(InferenceRule)] | 2 days | +| **Total** | **295 tests, all passing** | **~500 lines Rust + cockpit components** | **~1 week** | + +The primitives exist. The composition is new. The macros make it repeatable. diff --git a/.claude/prompts/SHIP.md b/.claude/prompts/SHIP.md new file mode 100644 index 000000000..52be01cc1 --- /dev/null +++ b/.claude/prompts/SHIP.md @@ -0,0 +1,226 @@ +# Ship q2 — The Car + +## What Exists (read before touching) + +```bash +# The backend (DONE — compiles, serves, MCP works) +crates/quarto/src/main.rs # CLI: q2 notebook serve → axum on :2718 +crates/quarto/src/notebook_server.rs # 10 MCP tools, SSE, full CRUD +crates/quarto/src/publisher.rs # HTML export, PDF via pandoc + +# The cockpit design (DONE — 3 static prototypes, not wired) +cockpit-prototype/index.html # vanilla JS, full layout +cockpit-prototype/cockpit-polished.html +cockpit-prototype/cockpit-tailwind.html +cockpit-prototype/cockpit.css +cockpit-prototype/cockpit.js + +# The React infrastructure (DONE — but it's the Quarto Hub editor, not the cockpit) +hub-client/ # Vite + React + TS, builds, has components + +# The blueprint (DONE — architecture for the cockpit React app) +.claude/FRONTEND_BLUEPRINT.md # Zustand state, SSE transport, panel roles + +# The design reference +.claude/design-reference/ # 4 Palantir/Bloomberg screenshots +.claude/PRODUCT_VISION.md # Cockpit energy, dense, professional + +# The stub crates (placeholders for real transcodes) +crates/stubs/notebook-runtime/ # → will be replaced by AdaWorldAPI/marimo transcode +crates/stubs/notebook-query/ # → will be replaced by AdaWorldAPI/graph-notebook transcode +crates/stubs/notebook-kernel/ # → will be replaced by AdaWorldAPI/kernel-protocol transcode +crates/stubs/notebook-render/ # → will be replaced by AdaWorldAPI/aiwar transcode +crates/stubs/lance-graph/ # → will be replaced by real lance-graph +crates/stubs/q2-ndarray/ # → will be replaced by real ndarray +``` + +## What's Missing (the gap between "compiles" and "usable") + +The backend works. The design exists as HTML prototypes. They're not connected. + +A colleague should be able to: + +1. `cargo install q2` (or `cargo build -p quarto`) +2. `q2 notebook serve` +3. Open `localhost:2718` in Chrome +4. See the cockpit (dark theme, graph panel, query bar, table, inspector) +5. Type a Gremlin query → see graph nodes appear +6. Click a node → inspector sidebar updates, table row highlights +7. Type an R cell → see table output +8. Press ⌘P → get a PDF + +Right now step 3 shows a placeholder page with three endpoint URLs. + +## What To Do + +### Step 1: Build the cockpit as a React app + +Create `cockpit/` at the repo root (separate from `hub-client/` which is the Quarto Hub editor). + +``` +cockpit/ +├── package.json # React, Vite, Zustand, TypeScript +├── vite.config.ts +├── tsconfig.json +├── index.html +├── src/ +│ ├── main.tsx +│ ├── App.tsx # Cockpit grid layout +│ ├── store.ts # Zustand: notebook, cells, selection, execution +│ ├── transport.ts # SSE from /mcp/sse, POST to /mcp/message +│ ├── components/ +│ │ ├── QueryBar.tsx # Language auto-detect chip, execute button +│ │ ├── GraphPanel.tsx # vis-network or d3 force graph, click → select +│ │ ├── Inspector.tsx # Selected node properties, connections +│ │ ├── ResultTable.tsx # Dense sortable table, row click → select +│ │ ├── CellStrip.tsx # Notebook cells below, reactive status dots +│ │ └── LeftRail.tsx # Filters, parameters (optional for MVP) +│ └── styles/ +│ └── cockpit.css # Dark theme from cockpit-prototype/cockpit.css +``` + +Use `cockpit-prototype/cockpit.css` and `cockpit-prototype/cockpit.js` as the +design source. The colors, typography, layout, and interaction patterns are +all defined there. Translate them into React components. + +The state model is in `.claude/FRONTEND_BLUEPRINT.md`. Read it. +Selection is global. Every panel derives from the same store. + +### Step 2: Wire transport to MCP + +The backend already serves MCP on `/mcp/sse` (GET) and `/mcp/message` (POST). +Read `notebook_server.rs` to see the exact request/response shapes. + +```typescript +// transport.ts +const sse = new EventSource('/mcp/sse'); +sse.onmessage = (event) => { + const msg = JSON.parse(event.data); + // Update store with notebook state, cell results, etc. +}; + +async function callTool(name: string, args: object) { + const res = await fetch('/mcp/message', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: Date.now(), + method: 'tools/call', + params: { name, arguments: args } + }) + }); + return res.json(); +} + +// Example: execute a cell +const result = await callTool('cell_execute', { + code: "g.V().hasLabel('server').outE().inV().path()", + lang: 'gremlin' +}); +``` + +### Step 3: Graph rendering + +For MVP, use vis-network (npm `vis-network`). It handles force layout, +drag, zoom, click events, and looks professional with minimal config. + +When `notebook-render` (AdaWorldAPI/aiwar) is transcoded, swap to its +output. For now, take the query result JSON and feed it to vis-network. + +```typescript +// GraphPanel.tsx +import { Network } from 'vis-network'; + +// When cell result has nodes/edges, render them +useEffect(() => { + if (result?.outputs?.some(o => o.type === 'graph')) { + const network = new Network(container, { nodes, edges }, options); + network.on('click', (params) => { + if (params.nodes.length > 0) { + store.selectNode(params.nodes[0]); + } + }); + } +}, [result]); +``` + +### Step 4: Embed in the binary + +After `npm run build` in `cockpit/`, the output is `cockpit/dist/`. +Serve it from axum: + +```rust +// notebook_server.rs — replace the placeholder +// Option A: static directory at runtime +app = app.nest_service("/", ServeDir::new("cockpit/dist")); + +// Option B: embed at compile time +// use include_dir::include_dir; +// static FRONTEND: Dir = include_dir!("cockpit/dist"); +``` + +For now, Option A is fine. The colleague runs: +```bash +cd cockpit && npm install && npm run build && cd .. +cargo run -p quarto -- notebook serve --frontend-dir cockpit/dist +``` + +Later, embed with `rust-embed` or `include_dir` for a true single binary. + +### Step 5: Make the stub crates do something useful + +Right now the stubs return placeholder data. Make them return enough +for the cockpit to look alive: + +**notebook-query**: `execute()` should return a fake graph with 10 nodes +and 15 edges when it receives any Gremlin/Cypher query. Later, wire to +real Neo4j via bolt-client or to lance-graph for local execution. + +**notebook-render**: `render_table()` should produce actual HTML with +DataTables.js. The function signature already exists in the stub. + +**notebook-runtime**: `Runtime` already has cell CRUD. Make the DAG +tracking work — when a cell's output changes, mark downstream cells stale. + +### Step 6: PDF export that works + +`publisher.rs` already generates HTML and shells out to pandoc for PDF. +Make the HTML output use the cockpit dark theme with a print media query +that flips to light: + +```css +@media print { + body { background: white; color: black; } + .graph-panel { /* render as static SVG */ } + .table-panel { /* clean print table styles */ } +} +``` + +### Step 7: Verify the full loop + +```bash +# Build +cd cockpit && npm install && npm run build && cd .. +cargo build -p quarto + +# Run +./target/debug/quarto notebook serve --frontend-dir cockpit/dist --open + +# Test +# 1. Browser opens localhost:2718 +# 2. Type a Gremlin query in the query bar +# 3. See graph nodes appear in the center panel +# 4. Click a node → inspector updates +# 5. See the result table below +# 6. Press ⌘P → PDF preview looks professional +``` + +## What NOT To Do + +- Don't touch hub-client/ — that's the Quarto Hub editor, separate product +- Don't rewrite the backend — it works +- Don't wait for real transcodes — use stubs with fake data +- Don't build a settings page, user management, or auth — ship first +- Don't build the LeftRail for MVP — add it after the core loop works +- Don't optimize — make it work, make it right, then make it fast diff --git a/.claude/prompts/TRANSCODE.md b/.claude/prompts/TRANSCODE.md new file mode 100644 index 000000000..05b39371d --- /dev/null +++ b/.claude/prompts/TRANSCODE.md @@ -0,0 +1,86 @@ +# q2 — Build the binary + +This repo is the product. One `cargo build` produces one binary that +is a graph notebook with cockpit UX. + +## Step 1: Create Cargo.toml with these dependencies + +```toml +[dependencies] +notebook-runtime = { git = "https://github.com/AdaWorldAPI/marimo" } +notebook-query = { git = "https://github.com/AdaWorldAPI/graph-notebook" } +notebook-kernel = { git = "https://github.com/AdaWorldAPI/kernel-protocol" } +notebook-render = { git = "https://github.com/AdaWorldAPI/aiwar" } +lance-graph = { git = "https://github.com/AdaWorldAPI/lance-graph" } +ndarray = { git = "https://github.com/AdaWorldAPI/ndarray" } +axum = "0.7" +tokio = { version = "1", features = ["full"] } + +[dependencies.rs-graph-llm] +git = "https://github.com/AdaWorldAPI/rs-graph-llm" +optional = true + +[features] +default = [] +orchestrator = ["rs-graph-llm"] +``` + +These crates may not exist yet as Rust crates. If a dependency doesn't +compile, stub it with a local crate that has the right name and empty +public API. Mark it `// TODO: replace when crate is transcoded`. + +## Step 2: Write main.rs + +Start an axum server on port 2718. Wire: + +- `GET /` → serve frontend static files (placeholder index.html for now) +- `GET /health` → `{ "status": "ok" }` +- `POST /mcp/sse` → MCP server (see rs-graph-llm .claude/prompts/SCOPE_F_mcp_server.md) +- MCP tools: cell_execute, cell_get, cells_list, cell_create, cell_update, + cell_delete, dag_get, notebook_save, notebook_load, notebook_export + +cell_execute takes code + optional lang. If lang is omitted, detect it: +- `g.V()` → gremlin +- `MATCH (` → cypher +- `PREFIX` or `SELECT ?` → sparql +- `%>%` or `<-` → r +- `let` / `fn` → rust +- Everything else → markdown + +Route to the right crate. Render result through notebook-render. + +## Step 3: Write the publisher + +This is the hardest part. No Rust Quarto exists. + +Read quarto-dev/quarto (TS) to understand what it does. Read +.claude/reference/aiwar/quarto/ to see what output looks like. + +For now, implement the minimum: +- `q2 render notebook.nb --format html` → HTML file with embedded results +- `q2 render notebook.nb --format pdf` → shell out to pandoc + wkhtmltopdf + +The HTML renderer takes notebook cells and produces a single HTML file: +- Code cells: syntax highlighted, collapsible +- Graph results: embed vis.js/d3 HTML from notebook-render +- Table results: embed DataTables.js HTML from notebook-render +- Markdown cells: render to HTML +- Dark cockpit theme (see rs-graph-llm .claude/PRODUCT_VISION.md) + +quarto-r must work with this: `q2 render notebook.qmd` as CLI. + +## Step 4: Verify + +```bash +cargo build # must compile +./target/debug/q2 serve # starts on :2718 +curl localhost:2718/health # returns ok +./target/debug/q2 render --help # shows render subcommand +``` + +## What NOT to do + +- Don't rewrite lance-graph or ndarray internals +- Don't implement a full Pandoc in Rust (shell out for now) +- Don't build the frontend (placeholder HTML is fine) +- Don't make lance-graph or ndarray optional — they always ship diff --git a/.claude/prompts/VISION.md b/.claude/prompts/VISION.md new file mode 100644 index 000000000..bc7c77a2b --- /dev/null +++ b/.claude/prompts/VISION.md @@ -0,0 +1,125 @@ +# q2 — Design the Frontend + +## What This Is + +q2 is a graph notebook. One Rust binary. Data engineers open it in a +browser, type Gremlin/Cypher/R/SPARQL, see interactive graphs, export +to PDF. Think: if Palantir Gotham and Neo4j Browser had a baby that +ran locally as a single binary. + +## The Problem + +We have the engine. We don't have the car. Our colleague said: "even +if you have a plasma engine it doesn't help if you don't have a car." + +Right now nobody can use what we built. A data engineer at our partner +company (Bardioc) knows Gremlin and R. They need to type a query, see +their graph, click around, export a report. They don't care about +semiring algebra or SIMD kernels. + +## Design References + +Look at these screenshots in rs-graph-llm .claude/design-reference/: + +### ref_01_palantir_gotham.png +Military C2 interface. Dark theme, teal/cyan accents. Multi-panel: +situation panel left, map center, course of action right, timeline +bottom. Four views of the same data, all live, all linked. Click a +node → every panel updates. + +THIS IS THE ENERGY. Not a chat window. Not a blank page. A cockpit. + +### ref_02_financial_dashboard.png +Bloomberg-level information density. Charts, gauges, metrics, +projections — everything on one screen. No scrolling. No tabs. +Color = meaning (green/red/amber). + +### ref_03_risk_map.png +The scatter plot IS the interface. Select points → table filters → +sidebar updates. Visualization is primary. Data table is secondary. +Selection drives everything. + +### ref_04_metabase.png +Parameters on the left drive views on the right. Histogram, map, +table — all linked. Change a filter, everything reflows. Clean, +non-technical users feel comfortable. + +## What the Frontend Must Do + +A data engineer opens localhost:2718 in their browser. They see: + +1. A query bar at the top. They type. Language auto-detects. + `g.V().hasLabel('server').outE().inV().path()` → Gremlin. + A subtle chip says `gremlin ▾`. One tap to override if wrong. + +2. The main area shows the graph result. Force-directed, interactive. + Drag nodes. Zoom. Hover for tooltips. Click a node → sidebar + updates with properties and connections. + +3. A properties/detail panel on the right. Shows selected node info. + Edges, types, metadata. Updates on every click. + +4. A result table below. Dense, sortable, full-width. Same data as + the graph but tabular. Click a row → node highlights in graph. + +5. Below that, more cells. R code, more queries, markdown notes. + Each cell result renders as the right instrument: graph, table, + chart, or scalar. + +6. Everything is reactive. Change a cell → downstream cells re-execute → + all views update. No "Run All" button. + +7. ⌘P → PDF. The notebook IS the document. Graphs render as SVG, + tables typeset, code syntax-highlighted. + +## The Feel + +- Dark background (#0a0e17 to #1a1f2e) +- Teal/cyan primary accent (#00bcd4 to #4dd0e1) +- Amber warnings, red errors, green healthy +- Clean sans-serif typography (Inter or similar) +- Monospace only inside code cells +- Panels, not a cell stack — CSS grid multi-panel layout +- Graph layout settles like leaves on water (force simulation) +- Panel transitions 200ms ease +- New results fade in +- Loading: subtle pulse on cell border, not a spinner +- Premium. A manager sees this in a demo and says "enterprise." + +## What Already Exists + +The backend is built (5 Rust crates compile). The frontend is the gap. + +| Backend piece | Status | +|---|---| +| Reactive cell runtime | notebook-runtime crate (exists) | +| Gremlin/Cypher/SPARQL executors | notebook-query crate (exists) | +| R kernel protocol (ZMQ) | notebook-kernel crate (exists) | +| Graph/table/chart rendering → HTML | notebook-render crate (exists) | +| Publisher (HTML/PDF) | notebook-publish (in progress) | +| Local graph engine | lance-graph (exists, 121 tests) | +| SIMD kernels | ndarray (exists, 890 tests) | +| MCP server for AI copilot | defined (SCOPE F) | + +## What Needs to Be Designed + +A frontend that: +- Serves from the Rust binary as static files (axum on :2718) +- Talks to the backend via MCP over SSE (/mcp/sse) +- Uses vis.js or d3 for graph rendering (notebook-render produces the JS) +- Uses DataTables.js for tables +- Implements the cockpit layout described above +- Implements the dark theme described above +- Works in Chrome, Firefox, Safari +- Is responsive enough for laptop screens (1280px minimum) + +Technology: React (marimo's frontend is React) or vanilla JS + web components. +Whatever ships fastest and looks best. + +## Deliverable + +Design mockups or working HTML/CSS/JS prototype of the cockpit layout. +Show: query bar, graph panel, properties sidebar, result table, cell stack. +Dark theme. Teal accents. Dense. Professional. Cockpit energy. + +This is the car. Make it look like a Ferrari. diff --git a/.claude/prompts/VIZ_ENGINE_V8.md b/.claude/prompts/VIZ_ENGINE_V8.md new file mode 100644 index 000000000..2b183b825 --- /dev/null +++ b/.claude/prompts/VIZ_ENGINE_V8.md @@ -0,0 +1,725 @@ +# Server-Side V8 JIT Visualization Engine + +## FIRST: Read .claude/rules/architectural-compliance.md +## SECOND: Read .claude/rules/borrow-strategy.md + +## What This Is + +deno_core V8 is already in the q2 binary (`quarto-system-runtime`). +Currently it renders EJS templates. We extend it to JIT-compile +visualization logic: force layout, activation overlays, particle +physics, glow computation. The Rust binary computes every frame. +The cockpit is a thin Canvas that paints pre-computed frame data +received over SSE. + +## Why Server-Side + +1. **Same rendering in cockpit AND PDF export** — server computes frames, + cockpit paints live, publisher renders to SVG. One renderer, two outputs. +2. **Thinking graph writes its own viz rules** — Layer 10 (Meta-Cognition) + outputs JS strings that V8 JIT-compiles. The brain decides how to + display its own thinking. Rules evolve as the graph learns. +3. **Cockpit is dumb** — ~50 lines of Canvas. No vis-network, no d3, + no library. Just `drawImage(frameData)`. Any browser, any device. + +## Architecture + +``` +┌─────────────────────────────────────────────────┐ +│ Rust Binary (q2) │ +│ │ +│ StreamingRunner (rs-graph-llm) │ +│ │ │ +│ ├→ Layer 5: semiring reasoning │ +│ ├→ Layer 6: NARS revision, seal check │ +│ ├→ Layer 10: meta-cognition → viz_rules JS │ +│ │ │ +│ ▼ │ +│ VizEngine (new) │ +│ ├─ V8 JsRuntime (deno_core, already in dep) │ +│ ├─ Force simulation (JS, JIT-compiled) │ +│ ├─ Activation overlay (JS, from Layer 10) │ +│ ├─ Particle physics (JS, JIT-compiled) │ +│ │ │ +│ ▼ │ +│ Frame Producer │ +│ ├─ 60fps tick → FrameData struct │ +│ ├─ SSE stream → cockpit (live) │ +│ └─ SVG render → publisher (export) │ +└─────────────────────────────────────────────────┘ + +┌─────────────────────────────────────────────────┐ +│ Cockpit (browser, thin Canvas) │ +│ │ +│ EventSource('/mcp/sse') │ +│ │ │ +│ ▼ │ +│ requestAnimationFrame loop │ +│ ├─ Read latest FrameData from SSE buffer │ +│ ├─ ctx.clearRect() │ +│ ├─ Draw edges (color, width, opacity) │ +│ ├─ Draw nodes (position, color, glow radius) │ +│ ├─ Draw particles (position, trail) │ +│ ├─ Draw epiphanies (flash, dashed line) │ +│ └─ No physics. No layout. Just paint. │ +└─────────────────────────────────────────────────┘ +``` + +## FrameData — What SSE Streams + +```rust +#[derive(Serialize)] +struct FrameData { + /// Monotonic frame counter + frame: u64, + /// Current temporal version being processed + version: usize, + + /// Node states (position + visual) + nodes: Vec<NodeFrame>, + /// Edge states (visual only, topology from initial load) + edges: Vec<EdgeFrame>, + /// In-flight particles + particles: Vec<ParticleFrame>, + /// Active epiphanies (edge births) + epiphanies: Vec<EpiphanyFrame>, + /// Global state + global_dim: f32, // 0.2 = spotlight, 1.0 = normal + breathing_phase: f32, // sine wave 0.0 → 1.0 + active_version_label: String, + seal_status: String, // "Staunen" | "Wisdom" +} + +#[derive(Serialize)] +struct NodeFrame { + id: String, + x: f32, + y: f32, + color: [u8; 3], // RGB + glow_radius: f32, // 0 = no glow, 40 = max + glow_color: [u8; 3], + opacity: f32, + icon_url: Option<String>, // noun-*.png path + label_visible: bool, +} + +#[derive(Serialize)] +struct EdgeFrame { + source_idx: usize, // index into nodes array + target_idx: usize, + color: [u8; 3], + width: f32, + opacity: f32, + dashed: bool, // inferred edge +} + +#[derive(Serialize)] +struct ParticleFrame { + x: f32, + y: f32, + color: [u8; 3], + radius: f32, + trail_opacity: f32, +} + +#[derive(Serialize)] +struct EpiphanyFrame { + x: f32, + y: f32, + flash_radius: f32, // expanding ring, 0 when done + flash_opacity: f32, + edge_progress: f32, // 0.0 → 1.0 as dashed line grows + label: String, + truth_f: f32, + truth_c: f32, +} +``` + +SSE sends one FrameData per tick. At 30fps that's ~33ms per frame. +For 221 nodes: FrameData ≈ 15KB JSON. At 30fps = 450KB/s. Fine for +localhost. For Railway: drop to 10fps (150KB/s) or send deltas. + +## V8 Visualization Runtime + +### VizEngine + +```rust +// crates/quarto/src/viz_engine.rs + +use deno_core::JsRuntime; +use serde_json; + +pub struct VizEngine { + runtime: JsRuntime, +} + +impl VizEngine { + pub fn new() -> Self { + let mut runtime = JsRuntime::new(deno_core::RuntimeOptions { + ..Default::default() + }); + + // Load the force simulation + rendering kernel + runtime.execute_script( + "viz_kernel.js", + include_str!("viz_kernel.js").into(), + ).expect("viz kernel load"); + + Self { runtime } + } + + /// Load graph data into the V8 simulation + pub fn load_graph(&mut self, nodes_json: &str, edges_json: &str) { + let script = format!( + "globalThis.vizKernel.loadGraph({}, {})", + nodes_json, edges_json + ); + self.runtime.execute_script("load", script.into()).unwrap(); + } + + /// Inject a visualization rule from the thinking graph + pub fn inject_rule(&mut self, rule_js: &str) { + let script = format!( + "globalThis.vizKernel.addRule({})", + serde_json::to_string(rule_js).unwrap() + ); + self.runtime.execute_script("rule", script.into()).unwrap(); + } + + /// Set activation state (from StreamChunk) + pub fn set_activation(&mut self, layer_id: &str, node_ids: &[String], intensity: f32) { + let script = format!( + "globalThis.vizKernel.activate('{}', {}, {})", + layer_id, + serde_json::to_string(node_ids).unwrap(), + intensity + ); + self.runtime.execute_script("activate", script.into()).unwrap(); + } + + /// Spawn particles along edges + pub fn spawn_particles(&mut self, edge_indices: &[usize]) { + let script = format!( + "globalThis.vizKernel.spawnParticles({})", + serde_json::to_string(edge_indices).unwrap() + ); + self.runtime.execute_script("particles", script.into()).unwrap(); + } + + /// Trigger epiphany (inferred edge birth) + pub fn trigger_epiphany(&mut self, source_id: &str, target_id: &str, truth_f: f32, truth_c: f32) { + let script = format!( + "globalThis.vizKernel.epiphany('{}', '{}', {}, {})", + source_id, target_id, truth_f, truth_c + ); + self.runtime.execute_script("epiphany", script.into()).unwrap(); + } + + /// Compute one frame — runs force tick + activation overlay + particles + pub fn tick(&mut self) -> FrameData { + self.runtime.execute_script("tick", "globalThis.vizKernel.tick()".into()).unwrap(); + + let result = self.runtime.execute_script( + "frame", + "JSON.stringify(globalThis.vizKernel.getFrame())".into(), + ).unwrap(); + + let scope = &mut self.runtime.handle_scope(); + let local = v8::Local::new(scope, result); + let json_str = local.to_rust_string_lossy(scope); + + serde_json::from_str(&json_str).unwrap() + } +} +``` + +### viz_kernel.js (JIT-compiled by V8) + +```javascript +// This runs inside V8 on the server, NOT in the browser + +globalThis.vizKernel = (() => { + let nodes = []; + let edges = []; + let particles = []; + let epiphanies = []; + let rules = []; + let activations = new Map(); + let globalDim = 1.0; + let breathPhase = 0; + let frame = 0; + let sealStatus = 'idle'; + let versionLabel = ''; + + // Force simulation state + let alpha = 0; + const REPULSION = -300; + const SPRING_LEN = 120; + const SPRING_K = 0.005; + const DAMPING = 0.6; + const CENTER_GRAVITY = 0.001; + const WIDTH = 1200; + const HEIGHT = 800; + + function loadGraph(nodeData, edgeData) { + nodes = nodeData.map((n, i) => ({ + ...n, + x: WIDTH/2 + 350 * Math.cos(2 * Math.PI * i / nodeData.length), + y: HEIGHT/2 + 250 * Math.sin(2 * Math.PI * i / nodeData.length), + vx: 0, vy: 0, + color: [0x33, 0x41, 0x55], // dim grey default + glow_radius: 0, + glow_color: [0, 0, 0], + opacity: 0.85, + label_visible: false, + })); + edges = edgeData.map(e => ({ + ...e, + source_idx: nodeData.findIndex(n => n.id === e.source), + target_idx: nodeData.findIndex(n => n.id === e.target), + color: [0x1e, 0x2a, 0x3a], // dim border + width: 1, + opacity: 0.4, + dashed: false, + })); + alpha = 1.0; + } + + function activate(layerId, nodeIds, intensity) { + const colorMap = { + 'cascade_search_foveal': [0x00, 0xbc, 0xd4], // teal + 'cascade_search_parafoveal': [0x7c, 0x4d, 0xff], // purple + 'semiring_reason': [0x7c, 0x4d, 0xff], // purple (bright) + 'memory_consolidate_staunen': [0xff, 0xc1, 0x07], // amber + 'memory_consolidate_wisdom': [0x4c, 0xaf, 0x50], // green + }; + const color = colorMap[layerId] || [0x00, 0xbc, 0xd4]; + + const idSet = new Set(nodeIds); + nodes.forEach(n => { + if (idSet.has(n.id)) { + n.color = color; + n.glow_radius = intensity * 40; + n.glow_color = color; + n.opacity = 0.4 + intensity * 0.6; + n.label_visible = true; + } + }); + + // Dim non-active nodes + if (nodeIds.length > 0) { + globalDim = 0.2; + } + + activations.set(layerId, { nodeIds, intensity, color }); + } + + function spawnParticles(edgeIndices) { + edgeIndices.forEach(idx => { + const e = edges[idx]; + if (!e) return; + particles.push({ + edge_idx: idx, + progress: 0, + speed: 0.03 + Math.random() * 0.02, + color: [0xff, 0xff, 0xff], + radius: 3, + }); + }); + } + + function epiphany(sourceId, targetId, truthF, truthC) { + const si = nodes.findIndex(n => n.id === sourceId); + const ti = nodes.findIndex(n => n.id === targetId); + if (si < 0 || ti < 0) return; + + const mx = (nodes[si].x + nodes[ti].x) / 2; + const my = (nodes[si].y + nodes[ti].y) / 2; + + epiphanies.push({ + source_idx: si, + target_idx: ti, + x: mx, y: my, + flash_radius: 0, + flash_opacity: 1, + edge_progress: 0, + label: 'inferred', + truth_f: truthF, + truth_c: truthC, + age: 0, + }); + } + + function addRule(ruleCode) { + try { + const fn = new Function('nodes', 'edges', 'particles', 'frame', ruleCode); + rules.push(fn); + } catch(e) { + // Invalid rule, skip + } + } + + function tick() { + frame++; + breathPhase = (Math.sin(frame / 60) + 1) / 2; + + // Force simulation + if (alpha > 0.001) { + const cx = WIDTH / 2, cy = HEIGHT / 2; + + // Center gravity + nodes.forEach(n => { + n.vx += (cx - n.x) * CENTER_GRAVITY * alpha; + n.vy += (cy - n.y) * CENTER_GRAVITY * alpha; + }); + + // Repulsion + for (let i = 0; i < nodes.length; i++) { + for (let j = i + 1; j < nodes.length; j++) { + let dx = nodes[j].x - nodes[i].x; + let dy = nodes[j].y - nodes[i].y; + let dist = Math.sqrt(dx*dx + dy*dy) || 1; + let f = REPULSION * alpha / (dist * dist); + let fx = (dx/dist) * f, fy = (dy/dist) * f; + nodes[i].vx -= fx; nodes[i].vy -= fy; + nodes[j].vx += fx; nodes[j].vy += fy; + } + } + + // Springs + edges.forEach(e => { + if (e.source_idx < 0 || e.target_idx < 0) return; + const s = nodes[e.source_idx], t = nodes[e.target_idx]; + let dx = t.x - s.x, dy = t.y - s.y; + let dist = Math.sqrt(dx*dx + dy*dy) || 1; + let f = (dist - SPRING_LEN) * SPRING_K * alpha; + let fx = (dx/dist) * f, fy = (dy/dist) * f; + s.vx += fx; s.vy += fy; + t.vx -= fx; t.vy -= fy; + }); + + // Integrate + nodes.forEach(n => { + n.vx *= DAMPING; n.vy *= DAMPING; + n.x += n.vx; n.y += n.vy; + n.x = Math.max(40, Math.min(WIDTH-40, n.x)); + n.y = Math.max(40, Math.min(HEIGHT-40, n.y)); + }); + + alpha *= 0.995; + } + + // Particle physics + particles.forEach(p => { p.progress += p.speed; }); + particles = particles.filter(p => p.progress < 1.0); + + // Epiphany animation + epiphanies.forEach(e => { + e.age++; + if (e.age < 15) { + e.flash_radius = e.age * 3; + e.flash_opacity = 1.0 - (e.age / 15); + } else { + e.flash_radius = 0; + e.flash_opacity = 0; + e.edge_progress = Math.min(1.0, (e.age - 15) / 20); + } + }); + epiphanies = epiphanies.filter(e => e.age < 60); + + // Glow decay + nodes.forEach(n => { + if (n.glow_radius > 0) { + n.glow_radius *= 0.98; + if (n.glow_radius < 0.5) n.glow_radius = 0; + } + }); + + // Global dim recovery + if (globalDim < 1.0) globalDim += 0.005; + + // Apply custom rules (from thinking graph Layer 10) + rules.forEach(fn => { + try { fn(nodes, edges, particles, frame); } catch(e) {} + }); + } + + function getFrame() { + // Compute particle positions from edge geometry + const particleFrames = particles.map(p => { + const e = edges[p.edge_idx]; + if (!e || e.source_idx < 0 || e.target_idx < 0) return null; + const s = nodes[e.source_idx], t = nodes[e.target_idx]; + return { + x: s.x + (t.x - s.x) * p.progress, + y: s.y + (t.y - s.y) * p.progress, + color: p.color, + radius: p.radius, + trail_opacity: 1.0 - p.progress * 0.7, + }; + }).filter(Boolean); + + return { + frame, + version: 0, + nodes: nodes.map(n => ({ + id: n.id, + x: n.x, y: n.y, + color: n.color, + glow_radius: n.glow_radius, + glow_color: n.glow_color, + opacity: n.opacity * (globalDim < 1.0 && n.glow_radius === 0 ? globalDim : 1.0), + icon_url: n.image || null, + label_visible: n.label_visible, + })), + edges: edges.map(e => ({ + source_idx: e.source_idx, + target_idx: e.target_idx, + color: e.color, + width: e.width, + opacity: e.opacity * (globalDim < 1.0 ? 0.3 : 1.0), + dashed: e.dashed, + })), + particles: particleFrames, + epiphanies: epiphanies.map(e => ({ + x: e.x, y: e.y, + flash_radius: e.flash_radius, + flash_opacity: e.flash_opacity, + edge_progress: e.edge_progress, + label: e.label, + truth_f: e.truth_f, + truth_c: e.truth_c, + })), + global_dim: globalDim, + breathing_phase: breathPhase, + active_version_label: versionLabel, + seal_status: sealStatus, + }; + } + + return { loadGraph, activate, spawnParticles, epiphany, addRule, tick, getFrame }; +})(); +``` + +## Cockpit (thin Canvas consumer) + +```typescript +// CognitionCanvas.tsx — ~60 lines of render logic + +const canvas = canvasRef.current; +const ctx = canvas.getContext('2d'); + +// SSE buffer — always read latest frame +let latestFrame: FrameData | null = null; +const sse = new EventSource('/mcp/sse'); +sse.addEventListener('frame', (e) => { + latestFrame = JSON.parse(e.data); +}); + +function paint() { + if (!latestFrame) { requestAnimationFrame(paint); return; } + const f = latestFrame; + ctx.clearRect(0, 0, canvas.width, canvas.height); + + // Edges + f.edges.forEach(e => { + const s = f.nodes[e.source_idx], t = f.nodes[e.target_idx]; + ctx.strokeStyle = `rgba(${e.color[0]},${e.color[1]},${e.color[2]},${e.opacity})`; + ctx.lineWidth = e.width; + if (e.dashed) ctx.setLineDash([4, 4]); + ctx.beginPath(); + ctx.moveTo(s.x, s.y); + ctx.lineTo(t.x, t.y); + ctx.stroke(); + ctx.setLineDash([]); + }); + + // Nodes + f.nodes.forEach(n => { + // Glow + if (n.glow_radius > 0) { + const grad = ctx.createRadialGradient(n.x, n.y, 0, n.x, n.y, n.glow_radius); + grad.addColorStop(0, `rgba(${n.glow_color[0]},${n.glow_color[1]},${n.glow_color[2]},0.4)`); + grad.addColorStop(1, 'transparent'); + ctx.fillStyle = grad; + ctx.beginPath(); + ctx.arc(n.x, n.y, n.glow_radius, 0, Math.PI * 2); + ctx.fill(); + } + // Node circle + ctx.globalAlpha = n.opacity; + ctx.fillStyle = `rgb(${n.color[0]},${n.color[1]},${n.color[2]})`; + ctx.beginPath(); + ctx.arc(n.x, n.y, 8, 0, Math.PI * 2); + ctx.fill(); + ctx.globalAlpha = 1; + }); + + // Particles + f.particles.forEach(p => { + ctx.globalAlpha = p.trail_opacity; + ctx.fillStyle = `rgb(${p.color[0]},${p.color[1]},${p.color[2]})`; + ctx.shadowBlur = 10; + ctx.shadowColor = `rgb(${p.color[0]},${p.color[1]},${p.color[2]})`; + ctx.beginPath(); + ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2); + ctx.fill(); + ctx.shadowBlur = 0; + ctx.globalAlpha = 1; + }); + + // Epiphanies + f.epiphanies.forEach(e => { + if (e.flash_radius > 0) { + ctx.strokeStyle = `rgba(0,229,255,${e.flash_opacity})`; + ctx.lineWidth = 2; + ctx.beginPath(); + ctx.arc(e.x, e.y, e.flash_radius, 0, Math.PI * 2); + ctx.stroke(); + } + }); + + requestAnimationFrame(paint); +} +requestAnimationFrame(paint); +``` + +## SSE Frame Streaming + +```rust +// In notebook_server.rs, add a frame stream endpoint + +async fn viz_frame_stream( + State(state): State<Arc<AppState>>, +) -> Sse<impl Stream<Item = Result<Event, Infallible>>> { + let stream = async_stream::stream! { + let mut interval = tokio::time::interval(Duration::from_millis(33)); // 30fps + loop { + interval.tick().await; + let mut engine = state.viz_engine.lock().await; + engine.tick(); + let frame = engine.get_frame(); + let json = serde_json::to_string(&frame).unwrap(); + yield Ok(Event::default().data(json).event("frame")); + } + }; + Sse::new(stream).keep_alive(KeepAlive::default()) +} + +// Route +app = app.route("/viz/frames", get(viz_frame_stream)); +``` + +## Thinking Graph → Viz Rules Pipeline + +```rust +// When Layer 10 completes, it outputs viz rules as JS strings +// These get injected into V8 at runtime + +async fn handle_layer_10_output( + viz_engine: &mut VizEngine, + pet_scan: &serde_json::Value, +) { + // Example: Layer 10 decides that heavily-reasoned clusters + // should develop persistent glow based on encounter frequency + if let Some(rules) = pet_scan.get("viz_rules") { + for rule in rules.as_array().unwrap_or(&vec![]) { + if let Some(code) = rule.as_str() { + viz_engine.inject_rule(code); + } + } + } +} + +// Layer 10 might output something like: +// "nodes.filter(n => n.encounters > 5).forEach(n => { n.glow_radius = Math.min(30, n.encounters * 3); })" +// +// This gets JIT-compiled by V8 and runs every tick. +// The visualization EVOLVES as the graph learns. +``` + +## PDF Export Path + +Same VizEngine, different consumer: + +```rust +// Instead of streaming frames via SSE, render N frames to SVG + +async fn export_viz_to_svg(engine: &mut VizEngine, frames: usize) -> Vec<String> { + let mut svgs = Vec::new(); + for _ in 0..frames { + engine.tick(); + let frame = engine.get_frame(); + svgs.push(frame_to_svg(&frame)); + } + svgs +} + +fn frame_to_svg(frame: &FrameData) -> String { + // Same data, SVG output instead of Canvas commands + // Used by publisher for PDF export +} +``` + +## Thread Model + +V8's JsRuntime is `!Send + !Sync`. Current q2 creates a fresh engine +per JS operation. For viz, we need a DEDICATED thread: + +```rust +// Spawn viz engine on its own thread with a channel +let (cmd_tx, cmd_rx) = tokio::sync::mpsc::channel(100); +let (frame_tx, frame_rx) = tokio::sync::broadcast::channel(16); + +std::thread::spawn(move || { + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + + rt.block_on(async { + let mut engine = VizEngine::new(); + let mut interval = tokio::time::interval(Duration::from_millis(33)); + + loop { + tokio::select! { + _ = interval.tick() => { + engine.tick(); + let frame = engine.get_frame(); + let _ = frame_tx.send(frame); + } + Some(cmd) = cmd_rx.recv() => { + match cmd { + VizCmd::LoadGraph(nodes, edges) => engine.load_graph(&nodes, &edges), + VizCmd::Activate(layer, ids, intensity) => engine.set_activation(&layer, &ids, intensity), + VizCmd::SpawnParticles(indices) => engine.spawn_particles(&indices), + VizCmd::Epiphany(src, tgt, f, c) => engine.trigger_epiphany(&src, &tgt, f, c), + VizCmd::InjectRule(code) => engine.inject_rule(&code), + } + } + } + } + }); +}); +``` + +SSE endpoint subscribes to `frame_rx`. Multiple cockpit clients can +connect — they all receive the same frame broadcast. + +## Implementation Order + +1. Create `crates/quarto/src/viz_engine.rs` — V8 wrapper +2. Create `crates/quarto/src/viz_kernel.js` — force sim + overlay logic +3. Add `/viz/frames` SSE endpoint to notebook_server.rs +4. Create `cockpit/src/components/CognitionCanvas.tsx` — thin Canvas +5. Wire StreamingRunner → VizCmd channel (activate, particles, epiphanies) +6. Wire Layer 10 → inject_rule (self-evolving visualization) +7. Wire publisher → frame_to_svg (PDF export) + +## What NOT to Do + +- Do NOT run V8 on the main tokio runtime (it's !Send) +- Do NOT put force simulation in the browser (server owns physics) +- Do NOT use vis-network or d3 in the cockpit (thin Canvas only) +- Do NOT send full node data every frame (send positions + visual state only) +- Do NOT copy graph data for SIMD — slices into backing store diff --git a/.claude/prompts/WIRE_LANCE_GRAPH.md b/.claude/prompts/WIRE_LANCE_GRAPH.md new file mode 100644 index 000000000..27b3fde39 --- /dev/null +++ b/.claude/prompts/WIRE_LANCE_GRAPH.md @@ -0,0 +1,168 @@ +# Wire lance-graph Hot Path into notebook-query + +## FIRST: Pull latest — the tree changed + +```bash +git fetch origin main +git reset --hard origin/main +``` + +The lance-graph stub was DELETED. The workspace Cargo.toml was rewritten. +notebook-query/Cargo.toml has new deps. If you're on a stale branch you +will be working on code that no longer exists. + +## MANDATORY: Read .claude/rules/architectural-compliance.md SECOND + +## Context + +The workspace `Cargo.toml` now points lance-graph at the real crate: +```toml +[workspace.dependencies.lance-graph] +git = "https://github.com/AdaWorldAPI/lance-graph" +``` + +This is a full Cypher engine with DataFusion planner. 70+ source files. +NOT a stub. NOT neo4j-rs. NOT a substitute. THIS is the hot path. + +## Step 1: Make it compile + +```bash +cargo check -p quarto 2>&1 +``` + +The real lance-graph depends on `arrow 57`, `datafusion 51`, `lance 2`. +These may conflict with existing deps or need additions to the workspace. +Fix version conflicts. Do NOT remove lance-graph to "fix" the build. + +If lance-graph-catalog has a path dep issue (it references `../lance-graph-catalog` +which doesn't exist in a git dep), you may need to add lance-graph-catalog +as a separate workspace dependency. + +## Step 2: Wire notebook-query to use lance-graph's Cypher parser + +The stub `crates/stubs/notebook-query/src/lib.rs` currently returns fake data. +Replace the Cypher path with the real lance-graph API: + +```rust +// Add to Cargo.toml of notebook-query stub: +// [dependencies] +// lance-graph.workspace = true +// arrow = "57" +// tokio = { version = "1", features = ["rt-multi-thread"] } +// serde_json = "1" + +use lance_graph::{CypherQuery, GraphConfig}; + +pub fn execute(source: &str, language: QueryLanguage) -> Result<QueryResult, String> { + match language { + QueryLanguage::Cypher => execute_cypher(source), + // ... other languages stay as stubs for now + } +} + +fn execute_cypher(source: &str) -> Result<QueryResult, String> { + let rt = tokio::runtime::Runtime::new().map_err(|e| e.to_string())?; + rt.block_on(async { + let config = aiwar_graph_config(); + let ctx = aiwar_session().await?; + let query = CypherQuery::new(source) + .map_err(|e| e.to_string())? + .with_config(config); + let batches = query.execute(&ctx).await.map_err(|e| e.to_string())?; + Ok(batches_to_query_result(batches)) + }) +} +``` + +## Step 3: Load aiwar data into DataFusion + +The data lives in `aiwar-neo4j-harvest/data/aiwar_graph.json` (221 nodes, 356 edges). +Convert to Arrow RecordBatches and register with DataFusion. + +Read the JSON structure (already documented in PREP_DUAL_PATH.md): +- N_Systems: 65 items, 20 columns +- N_Stakeholders: 114 items +- N_Civic: 23 items +- etc. + +Register each as a DataFusion table. Then lance-graph's Cypher planner +queries them via DataFusion SQL under the hood. + +```rust +use datafusion::prelude::*; + +async fn aiwar_session() -> Result<SessionContext, String> { + let ctx = SessionContext::new(); + // Register tables from aiwar JSON (or Parquet if pre-converted) + // ... + Ok(ctx) +} + +fn aiwar_graph_config() -> GraphConfig { + GraphConfig::builder() + .with_node_label("System", "id") + .with_node_label("Stakeholder", "id") + .with_node_label("Civic", "id") + .with_node_label("Historical", "id") + .with_node_label("Person", "id") + .with_relationship("CONNECTED_TO", "source", "target") + .with_relationship("DEVELOPED_BY", "source", "target") + .with_relationship("DEPLOYED_BY", "source", "target") + .with_relationship("USED_IN", "source", "target") + .with_relationship("PERSON_LINK", "source", "target") + .with_relationship("HIERARCHICAL", "source", "target") + .build() + .expect("valid config") +} +``` + +## Step 4: Convert RecordBatches to cockpit JSON + +The cockpit frontend expects `{ "nodes": [...], "edges": [...] }`. +Write a converter from Arrow RecordBatches to this format. + +Look at the existing `demo_network_topology()` in the stub for the +exact JSON shape the frontend expects. + +## Step 5: Cold path (Neo4j Aura fallback) + +Add `neo4rs` as an optional dependency to notebook-query: + +```toml +[dependencies] +neo4rs = { version = "0.8", optional = true } + +[features] +default = [] +neo4j-fallback = ["dep:neo4rs"] +``` + +```rust +#[cfg(feature = "neo4j-fallback")] +async fn execute_cold(source: &str) -> Result<QueryResult, String> { + let graph = neo4rs::Graph::new( + &std::env::var("NEO4J_URI").map_err(|e| e.to_string())?, + "neo4j", + &std::env::var("NEO4J_PASSWORD").map_err(|e| e.to_string())?, + ).await.map_err(|e| e.to_string())?; + let mut result = graph.execute(neo4rs::query(source)).await.map_err(|e| e.to_string())?; + // Convert to QueryResult... +} +``` + +## Step 6: Verify + +```bash +cargo build -p quarto +cargo run -p quarto -- notebook serve +# Open localhost:2718 +# Type: MATCH (s:System) RETURN s.name, s.type +# See real aiwar data in the cockpit +``` + +## What NOT to do + +- Do NOT remove lance-graph and substitute another engine +- Do NOT skip DataFusion — lance-graph's planner IS DataFusion +- Do NOT ignore compilation errors by emptying the lance-graph dep +- If something doesn't compile, FIX IT or ASK — don't replace diff --git a/.claude/prompts/WIRE_ORCHESTRATOR.md b/.claude/prompts/WIRE_ORCHESTRATOR.md new file mode 100644 index 000000000..498ec7b8d --- /dev/null +++ b/.claude/prompts/WIRE_ORCHESTRATOR.md @@ -0,0 +1,212 @@ +# rs-graph-llm — The Thinking Orchestrator (optional, `--features orchestrator`) + +## FIRST: Read .claude/rules/architectural-compliance.md +## SECOND: Read .claude/rules/borrow-strategy.md + +## What rs-graph-llm IS + +It's LangGraph/LangStudio reimplemented in Rust. The `graph-flow` crate +provides typed task graphs with conditional routing, parallel fanout, +subgraph composition, streaming execution, and persistent sessions. + +On top of that sits `thinking.rs` — a 10-layer cognitive processing +pipeline that orchestrates lance-graph features into a reasoning loop. + +``` +graph-flow (framework) + ├── Task, Graph, GraphBuilder, FlowRunner — the execution engine + ├── ReAct agent pattern — reason → decide → act loop + ├── FanOut — parallel child tasks + ├── Subgraph — hierarchical composition + ├── Conditional routing — if/else in the graph + ├── StreamingRunner — SSE-compatible event stream + ├── MCP tool integration (McpToolTask) — call external tools + ├── Agent Card YAML → Graph compiler — declarative agents + ├── Lance session storage + time travel — rewind any session + └── Tiered storage: Lance → Postgres → S3 — hot/warm/cold sessions + +thinking.rs (the 10-layer cognitive stack) + Layer 1: Sensory Ingest → MCP input → raw data + Layer 2: Fingerprint → label_fp() → encounter + Layer 3: Cascade Search → HHTL → attention band (Foveal/Parafoveal) + Layer 5: Semiring Reasoning → walk_chain_forward() + semiring algebra + Layer 6: Memory Consolidate → NARS revision + seal check (Wisdom/Staunen) + Layer 7: Planning → goal decomposition + Layer 8: Action Selection → RL credit assignment + Layer 9: Output Generation → LLM or template + Layer 10: Meta-Cognition → PET scan trace (which layers fired) + + Conditional routing: + Cascade → Foveal? → skip reasoning, go to memory consolidation + Memory → Staunen? → replan. Wisdom? → act directly. +``` + +## What It Does For the Hydration Showoffs + +Without rs-graph-llm: the play button advances versions manually. +Human clicks through enrichment files one by one. + +With rs-graph-llm: the thinking graph IS the play button. +Each enrichment file is a `sensory_ingest`. The graph DECIDES: +- Is this Foveal (familiar)? → skip reasoning, consolidate. +- Is this Parafoveal (novel)? → run semiring inference, then consolidate. +- Did Staunen occur (new learning)? → replan, reassess, iterate. +- Wisdom (stable)? → move to next version. + +The cockpit doesn't just show data evolving. It shows REASONING evolving. +The PET scan trace (Layer 10) shows which layers fired for each version, +visible as a heatmap in the status bar or a dedicated panel. + +## How It Integrates With lance-graph + +rs-graph-llm CALLS lance-graph. It doesn't replace it. + +``` +thinking.rs Layer 2 (Fingerprint) → calls lance_graph::fingerprint::label_fp() +thinking.rs Layer 3 (Cascade Search) → calls lance_graph::graph::blasgraph::cascade_search() +thinking.rs Layer 5 (Semiring Reason) → calls lance_graph::graph::spo::walk_chain_forward() +thinking.rs Layer 6 (Memory Consolidate) → calls lance_graph::graph::versioned::commit_encounter_round() + → calls lance_graph::graph::spo::truth::TruthValue::revision() + → calls lance_graph::graph::versioned::graph_seal_check() +``` + +Currently `thinking.rs` has placeholder implementations for these calls. +The wiring task replaces placeholders with real lance-graph API calls. + +## How It Integrates With q2 + +```toml +# q2/Cargo.toml (already there) +[dependencies.rs-graph-llm] +git = "https://github.com/AdaWorldAPI/rs-graph-llm" +optional = true + +[features] +orchestrator = ["rs-graph-llm"] +``` + +When enabled, notebook-query gains a `%%think` magic command: + +``` +%%think +MATCH (s:System)-[:DEVELOPED_BY]->(st:Stakeholder) RETURN s, st +``` + +Instead of just running the Cypher, this routes through the 10-layer +thinking graph: +1. Sensory ingest: parse the Cypher query +2. Fingerprint: compute query fingerprint +3. Cascade search: is this a familiar query pattern? (Foveal → cached result) +4. Semiring reasoning: run the query + infer additional edges +5. Memory consolidation: update the knowledge graph with encounter +6. Output: return enriched results (original + inferred) + +The cockpit shows the PET scan trace alongside the result: +``` +L1 ████ L2 ████ L3 ███ L5 ████████ L6 ██ L7 · L8 ████ L9 ██████ L10 ███ +Parafoveal · Staunen · 3 inferred edges · 14ms total +``` + +## Borrow Strategy Compliance + +The thinking graph uses the readonly BindSpace pattern: + +```rust +// Layer 5: Semiring Reasoning +async fn run(&self, context: Context) -> Result<TaskResult> { + let spo_store: &SpoStore = context.get_ref("spo_store").await; // &self, readonly + + // Compute on owned microcopies + let hits = spo_store.query_forward(&query_fp); // returns owned Vec<SpoHit> + let mut inferred: Vec<InferredEdge> = Vec::new(); + + for hit in &hits { + let mut truth = hit.record.truth; // Copy, owned + let chain = spo_store.walk_chain_forward(&hit.record.subject, 100, 3); + for hop in &chain { + truth = truth.revision(&hop.truth); // owned computation + } + if truth.confidence > 0.5 { + inferred.push(InferredEdge { /* ... */ }); + } + } + + // Write back through gate + context.set("inferred_edges", inferred).await; // no &mut on spo_store + Ok(TaskResult::new(Some(format!("{} inferred", inferred.len())), NextAction::Continue)) +} +``` + +SIMD stays on slices. Reasoning stays on microcopies. Write-back through context, not through &mut on the store. + +## The Play Button (temporal reasoning orchestration) + +```rust +/// Run the full temporal playback as a graph-flow execution. +async fn run_temporal_playback( + enrichment_files: &[PathBuf], + spo_store: &SpoStore, + versioned_graph: &VersionedGraph, +) -> Vec<StreamChunk> { + let graph = build_thinking_graph(); + let storage = Arc::new(InMemorySessionStorage::new()); + let streaming_runner = StreamingRunner::new(graph.clone(), storage.clone()); + + let (tx, mut rx) = tokio::sync::mpsc::channel(100); + + for (version, file) in enrichment_files.iter().enumerate() { + let cypher = std::fs::read_to_string(file).unwrap(); + + let mut session = Session::new_from_task( + format!("v{}", version), + "sensory_ingest", + ); + session.context.set("raw_input", cypher).await; + session.context.set("version", version).await; + session.context.set("spo_store_ref", spo_store).await; + + // Execute thinking graph — streams chunks to cockpit via SSE + streaming_runner.run_streaming(&mut session, tx.clone()).await.unwrap(); + + // After each version: check seal + let seal_status = versioned_graph.graph_seal_check(version, version + 1); + // Stream seal status to cockpit + } +} +``` + +Each enrichment file triggers a full thinking loop. +The cockpit receives StreamChunks via SSE. +The PET scan trace accumulates across versions. +The temporal slider reflects which version the thinking graph is processing. + +## Implementation Order + +### Phase 1: Wire the calls (2 days) +- Replace `thinking.rs` placeholder implementations with real lance-graph calls +- Add lance-graph as a dependency to graph-flow (behind feature flag) +- Verify the thinking graph runs end-to-end with real fingerprints + cascade + SPO + +### Phase 2: Wire to q2 (1 day) +- Add `%%think` magic command to notebook-query +- StreamingRunner → SSE events on `/mcp/sse` +- PET scan trace in cockpit status bar + +### Phase 3: Temporal playback (2 days) +- Load enrichment files as encounter rounds +- StreamingRunner orchestrates the play button +- Cockpit timeline component receives StreamChunks +- Version slider + play/pause controls + +### Phase 4: Agent cards for custom reasoning (later) +- YAML-defined agent workflows for domain-specific inference +- "Load agent card" in cockpit +- Custom thinking graphs per notebook + +## What NOT to Do + +- Do NOT substitute graph-flow with another orchestration framework +- Do NOT move lance-graph calls into graph-flow — graph-flow CALLS lance-graph +- Do NOT remove the streaming interface — the cockpit needs SSE chunks +- Do NOT use &mut on SpoStore during Layer 5 — use owned microcopies +- Do NOT copy data for SIMD — use slices into the backing store diff --git a/.claude/reference/aiwar/Cargo.toml b/.claude/reference/aiwar/Cargo.toml new file mode 100644 index 000000000..ea0762f27 --- /dev/null +++ b/.claude/reference/aiwar/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "aiwar-neo4j" +version = "0.1.0" +edition = "2021" +description = "AI War Cloud graph ingestor → Neo4j. Harvested from sarahciston/aiwar (GitLab)" +license = "MIT" +repository = "https://github.com/AdaWorldAPI/aiwar-neo4j-harvest" + +[dependencies] +neo4rs = "0.8" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +tokio = { version = "1", features = ["full"] } +anyhow = "1" +clap = { version = "4", features = ["derive", "env"] } +tracing = "0.1" +tracing-subscriber = "0.3" + +# Chess harvest dependencies +reqwest = { version = "0.12", features = ["json", "stream"], optional = true } +csv = { version = "1", optional = true } +shakmaty = { version = "0.27", optional = true } +ruci = { version = "2.1", optional = true } + +[features] +default = [] +embed = [] # Embed graph JSON at compile time +chess = [ # Chess database harvesting + "dep:reqwest", + "dep:csv", + "dep:shakmaty", + "dep:ruci", +] diff --git a/.claude/reference/aiwar/INTEGRATION_PLAN_SCHEMA_CHANGES.md b/.claude/reference/aiwar/INTEGRATION_PLAN_SCHEMA_CHANGES.md new file mode 100644 index 000000000..942ecc2aa --- /dev/null +++ b/.claude/reference/aiwar/INTEGRATION_PLAN_SCHEMA_CHANGES.md @@ -0,0 +1,753 @@ +# Integration Plan — neo4j-rs as Cypher Front-End to BindSpace + +> **Date**: 2026-02-16 (rev 2 — corrected after reading BindSpace source) +> +> **Correction**: Rev 1 proposed duplicating ladybug types in neo4j-rs. +> Wrong. BindSpace IS the universal DTO. LadybugBackend wraps a BindSpace +> instance directly. No translation layer needed — just mapping. +> +> **Vision**: neo4j-rs becomes the Cypher front-end to the entire ladybug +> cognitive architecture. Standard Cypher gives you graph CRUD. CALL +> procedures give you NARS inference, causal reasoning, XOR-fold spine +> queries, consciousness rung classification, and agent orchestration. + +--- + +## 0. The Correction + +Rev 1 got this wrong: +- Proposed `ladybug-contract` as dependency → **Wrong.** Need `ladybug` (main crate) + because `BindSpace`, `PackedDn`, `SpineCache` live there, not in the contract crate. +- Proposed `NodeTranslator`, `VerbTable`, `PropertyFingerprinter` as new types → + **Wrong.** BindSpace already has `verb("CAUSES")`, `label_fingerprint()`, + `dn_path_to_addr()`, `write_dn_path()`. No need to duplicate. +- Proposed `BTreeMap<u64, CogRecord>` as storage → **Wrong.** BindSpace IS the + storage. 65,536 addressable slots at 3-5 cycles per lookup via `Addr(prefix:slot)`. +- Proposed separate edge storage → **Wrong.** BindSpace has `link()`, `edges_out()`, + `edges_in()`, `traverse()`, `traverse_n_hops()`, plus `BitpackedCsr` for zero-copy. + +What BindSpace actually provides (already implemented, 2087 lines): + +``` +BindSpace.write(fingerprint) → Addr // CREATE +BindSpace.read(addr) → &BindNode // MATCH +BindSpace.link(from, verb, to) → usize // CREATE relationship +BindSpace.traverse(from, verb) → Vec<Addr> // MATCH ()-[r:VERB]->() +BindSpace.traverse_n_hops(a, v, n) → Vec<(hop, Addr)> // variable-length path +BindSpace.edges_out(addr) → Iterator<&BindEdge> +BindSpace.edges_in(addr) → Iterator<&BindEdge> +BindSpace.verb("CAUSES") → Option<Addr> // Surface 0x07 lookup +BindSpace.meta(addr) → MetaView // NARS, edges, rung, qualia +BindSpace.content(addr) → Container // search fingerprint +BindSpace.nars_revise(addr, f, c) → () // in-place NARS revision +BindSpace.write_dn_path(path, fp, rung) → Addr // hierarchical create +BindSpace.resolve("bindspace://path") → Option<Addr> +BindSpace.parent(addr) → Option<Addr> // O(1) tree navigation +BindSpace.ancestors(addr) → Iterator<Addr> +BindSpace.siblings(addr) → Iterator<Addr> +BindSpace.children_raw(addr) → &[u16] // zero-copy CSR +BindSpace.rebuild_csr() → () // build BitpackedCsr +BindSpace.dirty_addrs() → Iterator<Addr> +BindSpace.hash_all() → [u64; 256] // XOR-fold integrity +``` + +**BindSpace already has a QueryAdapter trait:** +```rust +pub trait QueryAdapter { + fn execute(&self, space: &mut BindSpace, query: &str) -> QueryResult; +} +``` + +neo4j-rs's Cypher execution engine becomes a `QueryAdapter` implementation. + +--- + +## 1. What LadybugBackend Actually Is + +```rust +// neo4j-rs/src/storage/ladybug/mod.rs + +use ladybug::storage::bind_space::{BindSpace, Addr, BindNode, FINGERPRINT_WORDS}; +use ladybug::container::{Container, MetaView, MetaViewMut}; +use ladybug::container::adjacency::PackedDn; + +pub struct LadybugBackend { + /// THE storage. Not a wrapper, not a cache — this IS where data lives. + space: BindSpace, + + /// NodeId(u64) → Addr mapping (neo4j-rs NodeIds are sequential, + /// BindSpace Addrs are prefix:slot — need a bridge). + id_to_addr: Vec<Option<Addr>>, // indexed by NodeId.0 + addr_to_id: HashMap<Addr, NodeId>, + + /// RelId(u64) → edge index in BindSpace.edges + rel_to_edge: Vec<Option<usize>>, + edge_to_rel: HashMap<usize, RelId>, + + /// Property storage (BindNode has fingerprint + label + payload, + /// but Neo4j nodes need full property maps for RETURN projections). + node_props: HashMap<NodeId, PropertyMap>, + node_labels: HashMap<NodeId, Vec<String>>, + rel_props: HashMap<RelId, PropertyMap>, + rel_types: HashMap<RelId, String>, + rel_endpoints: HashMap<RelId, (NodeId, NodeId)>, + + /// Counters + next_node_id: AtomicU64, + next_rel_id: AtomicU64, + next_tx_id: AtomicU64, + + /// Label index (same as MemoryBackend — needed for nodes_by_label) + label_index: HashMap<String, Vec<NodeId>>, +} +``` + +### Why property storage lives outside BindSpace + +BindSpace stores 256-word fingerprints — the XOR-bound content-addressable +representation. But Neo4j `RETURN n.name` needs the original string "Ada", +not bits. Two options: + +1. **Payload field**: `BindNode.payload: Option<Vec<u8>>` exists but is + unstructured. Could store serialized PropertyMap here. +2. **Side HashMap**: Store PropertyMap alongside. Simpler, proven (MemoryBackend + does this), zero risk of corrupting the fingerprint space. + +We use option 2 for correctness. The fingerprint in BindSpace IS the CAM +representation — it's used for similarity search, spine folding, NARS evidence. +The PropertyMap is the human-readable projection for RETURN clauses. + +--- + +## 2. StorageBackend Implementation — Method by Method + +### 2.1 Node CRUD + +```rust +async fn create_node(&self, tx: &mut Tx, labels: &[&str], props: PropertyMap) -> Result<NodeId> { + let id = NodeId(self.next_node_id.fetch_add(1, Ordering::Relaxed)); + + // 1. Fingerprint properties into 256-word vector + let fp = fingerprint_properties(&props); + + // 2. Write to BindSpace (allocates in node zone 0x80-0xFF) + let label_str = labels.join(":"); + let addr = self.space.write_labeled(fp, &label_str); + + // 3. Set NARS initial truth in metadata + // New node: freq=0.5, conf=0.01 (uncertain, no evidence yet) + self.space.nars_revise(addr, 0.5, 0.01); + + // 4. Register bidirectional ID ↔ Addr mapping + self.id_to_addr[id.0 as usize] = Some(addr); + self.addr_to_id.insert(addr, id); + + // 5. Store properties and labels (for RETURN projections) + self.node_props.insert(id, props); + self.node_labels.insert(id, labels.iter().map(|l| l.to_string()).collect()); + + // 6. Update label index + for label in labels { + self.label_index.entry(label.to_string()).or_default().push(id); + } + + Ok(id) +} + +async fn get_node(&self, tx: &Tx, id: NodeId) -> Result<Option<Node>> { + let addr = self.id_to_addr[id.0 as usize].ok_or(NotFound)?; + + // Read BindNode (O(1) array lookup, 3-5 cycles) + let _bind_node = self.space.read(addr).ok_or(NotFound)?; + + // Reconstruct Neo4j Node from stored properties + Ok(Some(Node { + id, + element_id: None, + labels: self.node_labels.get(&id).cloned().unwrap_or_default(), + properties: self.node_props.get(&id).cloned().unwrap_or_default(), + })) +} +``` + +### 2.2 Relationship CRUD + +```rust +async fn create_relationship( + &self, tx: &mut Tx, src: NodeId, dst: NodeId, + rel_type: &str, props: PropertyMap, +) -> Result<RelId> { + let id = RelId(self.next_rel_id.fetch_add(1, Ordering::Relaxed)); + + let src_addr = self.id_to_addr[src.0 as usize].ok_or(NotFound)?; + let dst_addr = self.id_to_addr[dst.0 as usize].ok_or(NotFound)?; + + // 1. Resolve verb from Surface 0x07 + // CAUSES → Addr(0x07, 0x00), BECOMES → Addr(0x07, 0x01), etc. + // For unknown verbs: register dynamically in the verb surface. + let verb_addr = self.resolve_verb(rel_type); + + // 2. Link in BindSpace (creates BindEdge with XOR-bound fingerprint: + // edge.fp = src.fp ⊕ verb.fp ⊕ dst.fp) + let edge_idx = self.space.link(src_addr, verb_addr, dst_addr); + + // 3. Register mapping + self.rel_to_edge[id.0 as usize] = Some(edge_idx); + self.edge_to_rel.insert(edge_idx, id); + + // 4. Store properties, type, endpoints + self.rel_props.insert(id, props); + self.rel_types.insert(id, rel_type.to_string()); + self.rel_endpoints.insert(id, (src, dst)); + + // 5. NARS: this relationship is evidence. + // Revise source node's truth value toward higher confidence. + self.space.nars_revise(src_addr, 0.7, 0.3); + + Ok(id) +} + +fn resolve_verb(&mut self, rel_type: &str) -> Addr { + // 1. Try exact match in Surface 0x07 (CAUSES, BECOMES, KNOWS, etc.) + if let Some(addr) = self.space.verb(rel_type) { + return addr; + } + + // 2. Try normalized (lowercase "invests in" → "INVESTS_IN") + let normalized = rel_type.to_uppercase().replace(' ', "_").replace('-', "_"); + if let Some(addr) = self.space.verb(&normalized) { + return addr; + } + + // 3. Register new verb in Surface 0x07 (dynamic extension) + let fp = label_fingerprint(rel_type); + let addr = self.space.surface_op_or_register(PREFIX_VERBS, rel_type, fp); + addr +} +``` + +### 2.3 Traversal + +```rust +async fn get_relationships( + &self, tx: &Tx, node: NodeId, dir: Direction, rel_type: Option<&str>, +) -> Result<Vec<Relationship>> { + let addr = self.id_to_addr[node.0 as usize].ok_or(NotFound)?; + + let edges: Vec<&BindEdge> = match dir { + Direction::Outgoing => self.space.edges_out(addr).collect(), + Direction::Incoming => self.space.edges_in(addr).collect(), + Direction::Both => { + let mut v: Vec<_> = self.space.edges_out(addr).collect(); + v.extend(self.space.edges_in(addr)); + v + } + }; + + // Filter by type and reconstruct Neo4j Relationship objects + let mut results = Vec::new(); + for edge in edges { + let edge_idx = /* look up index */; + if let Some(&rel_id) = self.edge_to_rel.get(&edge_idx) { + if let Some(rt) = rel_type { + if self.rel_types.get(&rel_id).map(|s| s.as_str()) != Some(rt) { + continue; + } + } + results.push(self.reconstruct_relationship(rel_id)); + } + } + Ok(results) +} + +async fn expand( + &self, tx: &Tx, node: NodeId, dir: Direction, + rel_types: &[&str], depth: ExpandDepth, +) -> Result<Vec<Path>> { + let addr = self.id_to_addr[node.0 as usize].ok_or(NotFound)?; + let max_hops = match depth { + ExpandDepth::Exact(d) => d, + ExpandDepth::Range { max, .. } => max, + ExpandDepth::Unbounded => 100, + }; + + // Use BindSpace.traverse_n_hops for BFS expansion + // This uses the CSR index — zero-copy, no allocation per hop + if rel_types.len() == 1 { + if let Some(verb) = self.space.verb(rel_types[0]) { + let hops = self.space.traverse_n_hops(addr, verb, max_hops); + return self.hops_to_paths(node, &hops); + } + } + + // Multi-type: fall back to per-hop filtering (still uses edges_out) + self.expand_bfs(addr, node, dir, rel_types, depth).await +} +``` + +### 2.4 CALL Procedures — The Extension Point + +This is where neo4j-rs goes far beyond standard Cypher: + +```rust +async fn call_procedure(&self, name: &str, args: &[Value]) -> Result<ProcedureResult> { + match name { + // === SEARCH === + "ladybug.search" => { + // Resonance search: fingerprint a query string, find nearest + // nodes by Hamming distance over the content container. + // Uses HDR cascade: L0 scent → L1 popcount → L2 sketch → L3 Hamming + let query = args[0].as_str()?; + let k = args.get(1).and_then(|v| v.as_int()).unwrap_or(10); + self.resonance_search(query, k) + } + + // === VSA OPERATIONS === + "ladybug.bind" => { + // XOR-bind two fingerprints. Returns the bound result. + // CALL ladybug.bind("concept_A", "concept_B") YIELD fingerprint + } + "ladybug.unbind" => { + // Same as bind (XOR is self-inverse). + // Given edge ⊕ known ⊕ verb → recovers unknown. + } + "ladybug.similarity" => { + // Hamming similarity between two nodes or strings. + // CALL ladybug.similarity("Ada", "OpenAI") YIELD score + } + + // === NARS INFERENCE === + "ladybug.truth" => { + // Read NARS truth value <freq, conf> from a node's metadata. + // CALL ladybug.truth(nodeId) YIELD frequency, confidence, expectation + let addr = self.node_addr(args[0].as_int()?)?; + let (f, c) = self.space.read(addr).unwrap().nars(); + // Return as procedure result + } + "ladybug.revise" => { + // NARS truth revision: accumulate evidence on a node. + // CALL ladybug.revise(nodeId, 0.8, 0.6) YIELD frequency, confidence + let addr = self.node_addr(args[0].as_int()?)?; + self.space.nars_revise(addr, args[1].as_float()?, args[2].as_float()?); + } + "ladybug.deduction" => { + // NARS deduction: A→B, B→C ⊢ A→C with truth propagation. + // CALL ladybug.deduction(nodeA, nodeB, nodeC) YIELD frequency, confidence + } + "ladybug.abduction" => { + // NARS abduction: A→B, C→B ⊢ C→A (inference to best explanation). + } + + // === CAUSAL REASONING (Pearl's Ladder) === + "ladybug.rung" => { + // Classify a node's causal rung: SEE(0), DO(1), IMAGINE(2). + // CALL ladybug.rung(nodeId) YIELD rung, label + let addr = self.node_addr(args[0].as_int()?)?; + let rung = self.space.rung(addr); + } + "ladybug.counterfactual" => { + // Pearl's rung 3: "What if X had been different?" + // Creates a counterfactual world by cloning subgraph, + // applying intervention, and propagating consequences. + } + + // === SPINE / XOR-FOLD === + "ladybug.spine" => { + // XOR-fold all nodes with a given label into a single + // 256-word digest. Useful for cluster fingerprinting. + // CALL ladybug.spine("Person") YIELD spine, count, popcount + } + + // === DN TREE === + "ladybug.dn.navigate" => { + // Navigate the DN tree by path. + // CALL ladybug.dn.navigate("Ada:A:soul:identity") YIELD addr, depth, rung + let path = args[0].as_str()?; + let addr = self.space.write_dn_path(path, ...); + } + "ladybug.dn.ancestors" => { + // Walk up the DN tree from a node. + // Returns all ancestors as rows. + } + "ladybug.dn.children" => { + // List children of a DN node. + } + + // === CRYSTALLIZATION === + "ladybug.crystallize" => { + // Mark a belief as frozen (high confidence, won't decay). + // Sets confidence to 0.99 and TTL to 0 (permanent). + } + + // === META === + "ladybug.capabilities" => { + // Report what this backend can do. + } + + _ => Err(Error::ExecutionError(format!("Unknown procedure: {name}"))) + } +} +``` + +--- + +## 3. Beyond Standard Cypher — What This Enables + +### 3.1 NARS-Augmented Queries + +Standard Cypher: +```cypher +MATCH (a:Company)-[:INVESTS_IN]->(b:Company) RETURN a, b +``` + +Ladybug-augmented: +```cypher +// Find investment relationships with high confidence +MATCH (a:Company)-[r:INVESTS_IN]->(b:Company) +CALL ladybug.truth(a) YIELD confidence AS a_conf +CALL ladybug.truth(b) YIELD confidence AS b_conf +WHERE a_conf > 0.7 AND b_conf > 0.7 +RETURN a.name, b.name, a_conf, b_conf +ORDER BY a_conf * b_conf DESC +``` + +### 3.2 Resonance Search (Semantic Nearest Neighbors) + +```cypher +// Find nodes similar to "artificial intelligence regulation" +CALL ladybug.search("artificial intelligence regulation", 10) YIELD nodeId, score +MATCH (n) WHERE id(n) = nodeId +RETURN n.name, score +ORDER BY score DESC +``` + +### 3.3 Causal Inference + +```cypher +// Given: A invests_in B, B develops C +// Infer: A indirectly_supports C (NARS deduction) +MATCH (a)-[:INVESTS_IN]->(b)-[:DEVELOPS]->(c) +CALL ladybug.deduction(a, b, c) YIELD frequency, confidence +WHERE confidence > 0.5 +RETURN a.name AS investor, c.name AS technology, frequency, confidence +``` + +### 3.4 Spine Queries (Cluster Fingerprinting) + +```cypher +// XOR-fold all TechCompany nodes into a cluster fingerprint +CALL ladybug.spine("TechCompany") YIELD spine, count, popcount +// Then find nodes similar to the cluster centroid +CALL ladybug.search(spine, 5) YIELD nodeId, score +RETURN nodeId, score +``` + +### 3.5 Counterfactual Reasoning + +```cypher +// Pearl's rung 3: "What if Google hadn't acquired DeepMind?" +MATCH (google:Company {name: "Google"})-[r:ACQUIRES]->(dm:Company {name: "DeepMind"}) +CALL ladybug.counterfactual(r) YIELD affected_nodes, belief_delta +RETURN affected_nodes, belief_delta +``` + +### 3.6 DN Tree Navigation + +```cypher +// Navigate the cognitive hierarchy +CALL ladybug.dn.navigate("Ada:A:soul:identity") YIELD addr, depth, rung +// Walk up +CALL ladybug.dn.ancestors(addr) YIELD ancestor_addr, ancestor_depth +MATCH (n) WHERE ladybug.addr(n) = ancestor_addr +RETURN n, ancestor_depth +``` + +--- + +## 4. Implementation Sequence + +### Phase 1: BindSpace Backend Scaffold + +Create `src/storage/ladybug/mod.rs` with: +- `LadybugBackend` struct wrapping `BindSpace` +- Bidirectional `NodeId ↔ Addr` mapping +- Bidirectional `RelId ↔ edge_index` mapping +- Property/label side storage for RETURN projections +- `impl StorageBackend for LadybugBackend` — all CRUD methods + +All standard Cypher operations MUST produce identical results to +MemoryBackend. This is the correctness baseline. + +### Phase 2: Verb Resolution + +Map Neo4j relationship types to BindSpace Surface 0x07 verbs: +- 28 pre-initialized verbs (CAUSES through PREV_SIBLING) +- Dynamic registration for unknown verbs +- Aiwar pattern: `CONNECTED_TO` + `r.label` property → verb lookup + +### Phase 3: Property Fingerprinting + +When a node is created: +1. Sort property keys alphabetically +2. XOR-bind each (key, value) pair into a 256-word fingerprint +3. Write fingerprint to BindSpace via `space.write(fp)` +4. Meta container (words 0-127): NARS truth, label_hash, inline edges +5. Content container (words 128-255): semantic fingerprint for search + +### Phase 4: CALL Procedures + +Register 15+ procedures: +- 4 VSA: search, bind, unbind, similarity +- 4 NARS: truth, revise, deduction, abduction +- 3 DN: navigate, ancestors, children +- 2 Causal: rung, counterfactual +- 1 Spine: xor-fold +- 1 Crystal: crystallize + +### Phase 5: Acceptance Test with aiwar_full.cypher + +- 221 nodes create with correct fingerprints +- 356 relationships create with correct verb bindings +- All standard Cypher queries match MemoryBackend results +- NARS truth values accumulate from relationship evidence +- `ladybug.search()` returns resonance-ranked results +- Spine queries produce correct XOR-folds per label + +### Phase 6: NARS Calibration Pipeline + +After loading aiwar data: +1. For each verb type, count evidence (pos/neg) +2. Initialize `TruthValue::from_evidence(pos, neg)` per verb +3. Run `TruthValue::revision()` to merge multiple evidence sources +4. Run `TruthValue::deduction()` for transitive inferences +5. Crystallize high-confidence beliefs + +--- + +## 5. Dependency Graph (Corrected) + +``` +neo4j-rs + └── ladybug (main crate, optional, feature = "ladybug") + ├── BindSpace (THE storage — 65K addressable slots) + │ ├── Addr(prefix:slot) (O(1) array indexing, 3-5 cycles) + │ ├── BindNode (256 u64 fingerprint + label + parent + rung) + │ ├── BindEdge (from ⊕ verb ⊕ to, XOR-bound) + │ ├── BitpackedCsr (zero-copy edge traversal) + │ ├── DnIndex (PackedDn ↔ Addr bidirectional) + │ └── DirtyBits (65536-bit change tracking) + ├── Container (8192-bit, 128 × u64) + ├── MetaView / MetaViewMut (zero-copy metadata, 50+ accessors) + ├── PackedDn (7-level hierarchy, u64) + ├── SpineCache (XOR-fold, lazy recompute) + └── TruthValue (NARS, full NAL truth functions) +``` + +**neo4j-rs depends on ladybug main crate, NOT just ladybug-contract.** +BindSpace, PackedDn, SpineCache are in the main crate. + +--- + +## 6. File-Level Change Map (Corrected) + +### In neo4j-rs (NEW files): + +| File | Contents | Est. Lines | +|------|----------|:----------:| +| `src/storage/ladybug/mod.rs` | LadybugBackend + StorageBackend impl | ~600 | +| `src/storage/ladybug/procedures.rs` | 15+ CALL procedure handlers | ~400 | +| `src/storage/ladybug/fingerprint.rs` | Property → 256-word fingerprint | ~100 | +| `tests/ladybug_backend.rs` | Acceptance tests (aiwar + NARS) | ~300 | + +### Files to REMOVE (premature scaffold from rev 1): + +| File | Why | +|------|-----| +| `src/storage/ladybug/translator.rs` | Duplicates PackedDn + DnIndex in BindSpace | +| `src/storage/ladybug/verbs.rs` | Duplicates Surface 0x07 verb table in BindSpace | + +### In neo4j-rs (MODIFIED): + +| File | Change | +|------|--------| +| `Cargo.toml` | Change dep from `ladybug-contract` to `ladybug` | +| `src/storage/mod.rs` | `pub mod ladybug;` (feature-gated) | + +### In ladybug-rs: + +| File | Change | +|------|--------| +| **NONE** | **NO CHANGES. Period.** | + +--- + +## 7. What NOT to Duplicate + +Now that I've read the code, these are the types I was about to duplicate +and shouldn't have: + +| Type I Almost Duplicated | Where It Already Lives | Method | +|--------------------------|----------------------|--------| +| PackedDn | `container/adjacency.rs` | `from_path()`, `parent()`, `child()` | +| VerbTable (144 verbs) | BindSpace Surface 0x07 | `space.verb("CAUSES")` | +| NodeTranslator | BindSpace.DnIndex | `dn_index.register()`, `addr_for()` | +| PropertyFingerprinter | BindSpace | `label_fingerprint()` | +| ContainerDto | `Container` in ladybug-contract | Exact same struct | +| Edge storage | BindSpace.edges + BitpackedCsr | `link()`, `edges_out()` | +| Dirty tracking | BindSpace.DirtyBits | `mark_dirty()`, `dirty_addrs()` | +| NARS revision | BindSpace | `nars_revise(addr, f, c)` | + +The only thing neo4j-rs needs to add is the **NodeId ↔ Addr mapping** +(because Neo4j uses sequential u64 IDs while BindSpace uses prefix:slot +addressing) and **property side storage** (because BindSpace stores +fingerprints, not original strings). + +--- + +## 8. Success Criteria + +1. `cargo build --features ladybug` compiles +2. All existing MemoryBackend tests pass with LadybugBackend +3. `aiwar_full.cypher` loads: 221 nodes, 356 relationships +4. `CALL ladybug.search("AI regulation", 10)` returns ranked results +5. `CALL ladybug.truth(nodeId)` returns NARS freq/conf +6. `CALL ladybug.spine("TechCompany")` returns XOR-fold +7. Zero changes to ladybug-rs +8. BindSpace.stats() shows correct surface/fluid/node counts + +--- + +--- + +## 9. SPO/XYZ Holographic Geometry (Rev 3) + +> Added after reading `extensions/spo/spo.rs` (1571 lines), +> `container/traversal.rs` (440 lines), `container/search.rs` (247 lines), +> `qualia/felt_traversal.rs` (180+ lines), and the blasgraph lineage +> (ARCHITECTURE.md Section 26). + +### The Insight + +The DN-Tree IS the sparse adjacency already. Each CogRecord's W16-31 +(64 inline edges) + W96-111 (CSR overflow) is the RedisGraph CSR layout +transcoded to cognitive verb IDs + Container target hints: + +```text +RedisGraph (CSR integer IDs) + → Holograph (DnNodeStore + DnCsr, fingerprint IDs) + → BlasGraph (sparse adjacent vectors, BLAS-style ops) + → ContainerGraph (pure Container-native, everything 8192 bits) +``` + +### SPO Triple Encoding + +Every relationship in LadybugBackend now carries a **holographic SPO trace**: + +```text +S = Subject container (8192 bits) — node fingerprint +P = Predicate container (8192 bits) — verb fingerprint (e.g., "CAUSES") +O = Object container (8192 bits) — node fingerprint + +trace = permute(S,1) ⊕ ROLE_S ⊕ permute(P,43) ⊕ ROLE_P ⊕ permute(O,89) ⊕ ROLE_O +``` + +**Permutation** (word-level circular shift) breaks XOR commutativity: +`A→B` and `B→A` produce different traces because `permute(A,1) ≠ permute(A,89)`. +This is the standard VSA approach — ladybug's SPO Crystal uses orthogonal +codebooks for the same purpose; we use permutation since we don't maintain +a codebook in the bridge layer. + +### Holographic Recovery + +Given any 2 components + trace, recover the 3rd via pure XOR: + +```text +MATCH (s)-[:CAUSES]->(?) → missing_O = recover_object(trace, S, P) +MATCH (?)-[:CAUSES]->(o) → missing_S = recover_subject(trace, P, O) +MATCH (s)-[?]->(o) → missing_P = recover_predicate(trace, S, O) +``` + +No index lookup needed. ~256 XOR + rotate operations (128 words × 2 ops). + +### Belichtungsmesser HDR Cascade + +Similarity search now uses the 3-level cascade from `container/search.rs`: + +| Level | Operation | Cycles | Purpose | +|-------|-----------|--------|---------| +| L0 | Belichtungsmesser (7 samples) | ~14 | Rejects ~90% of candidates | +| L1 | Exact Hamming with early exit | ~128 | Prunes distant survivors | +| L2 | Full ranking | ~256 | Final top-k | + +This replaces the previous O(n × 8192-bit) linear scan with O(n × 448-bit) +pre-filter + O(0.1n × 8192-bit) exact pass. + +### Semiring Traversal + +Five concrete semirings mirror `container/traversal.rs`: + +| Semiring | Value | Use Case | +|----------|-------|----------| +| BooleanBfs | `bool` | Reachability queries (MATCH path exists) | +| HammingMinPlus | `u32` | Shortest semantic path | +| HdrPathBind | `Option<ContainerDto>` | XOR-compose path fingerprints | +| ResonanceSearch | `u32` | Find paths resonating with query | +| CascadedHamming | `u32` | Belichtungsmesser-accelerated shortest path | + +All operate on `ContainerDto` (neo4j-rs local type) and will bridge to +ladybug's `DnSemiring` over `Container` when compiled together. + +### New Procedures + +| Procedure | Args | Operation | +|-----------|------|-----------| +| `ladybug.spo.trace(s, p, o)` | 3 strings | Compute holographic trace + verify recovery | +| `ladybug.spo.recover(k1, k2, trace, role)` | 3 strings + role | Recover missing SPO component | +| `ladybug.abduction(f1, c1, f2, c2)` | NARS truth values | A→B, B ⊢ A (weak inference) | +| `ladybug.induction(f1, c1, f2, c2)` | NARS truth values | A, A→B ⊢ generalise | + +### Integration Chain + +```text +Cypher: MATCH (a)-[:CAUSES]->(b) + → neo4j-rs parses, plans expand() + → LadybugBackend dispatches via SPO trace + → For known-subject queries: recover_object(trace, S, P) + → Belichtungsmesser cascade finds closest node to recovered fingerprint + → ~14 cycles per candidate, 90% rejection at L0 + → For multi-hop: semiring MxV over adjacency (container_mxv) + → Each hop reads InlineEdges from CogRecord W16-31 + → DnSemiring multiply + add per edge +``` + +### File Map (Rev 3) + +| File | Lines | Purpose | +|------|-------|---------| +| `src/storage/ladybug/mod.rs` | ~500 | LadybugBackend + StorageBackend impl + SPO recovery | +| `src/storage/ladybug/fingerprint.rs` | ~360 | ContainerDto + permute/unpermute + PropertyFingerprinter | +| `src/storage/ladybug/spo.rs` | ~350 | SpoTrace + Belichtungsmesser + cascade + semirings | +| `src/storage/ladybug/procedures.rs` | ~350 | 14 CALL procedure handlers | + +### What's Left + +1. **Bridge to real BindSpace** — Replace RwLock<HashMap> internal storage + with `BindSpace` instance when `#[cfg(feature = "ladybug")]` is active. + The `SpoTrace` already uses the same role vector seeds as ladybug's + SPO Crystal (0xDEADBEEF_CAFEBABE, etc.). + +2. **Felt traversal dispatch** — Wire `CALL ladybug.felt_traverse(dn)` to + ladybug's `FeltPath` with surprise/free-energy reporting. + +3. **GrBMatrix facade** — The `GRAPH.QUERY` command interface wrapping + `container_mxv()` with XOR semirings. The GrBMatrix rows ARE the + CogRecord inline edges viewed as sparse matrix format. + +4. **Quorum field procedures** — `CALL ladybug.quorum.evolve()` for + 5×5×5 lattice dynamics. + +--- + +*Rev 3: Added SPO/XYZ holographic geometry, Belichtungsmesser cascade, +permutation-based role binding, 5 semiring implementations, and blasgraph +lineage documentation. All tests pass. Zero changes to ladybug-rs.* diff --git a/.claude/reference/aiwar/WHAT_THIS_IS.md b/.claude/reference/aiwar/WHAT_THIS_IS.md new file mode 100644 index 000000000..5aa68e7f8 --- /dev/null +++ b/.claude/reference/aiwar/WHAT_THIS_IS.md @@ -0,0 +1,47 @@ +# aiwar-neo4j-harvest — Full Reference + +Source: AdaWorldAPI/aiwar-neo4j-harvest (cloned at full depth) + +## It's Not Just a Quarto Site + +It's a Rust-native graph knowledge system with 5 layers: + +### Layer 1: Rust Crate (aiwar-neo4j) +- Cargo.toml, src/main.rs, src/model.rs, src/ingest.rs +- Reads JSON graph data + schema ontology +- Generates Cypher programmatically from typed Rust structs +- Ingests directly into Neo4j via neo4rs crate +- CLI: cypher | neo4j | analyze | chess-openings | chess-evals | chess-bridge | live-games + +### Layer 2: Schema-as-Data Ontology +- data/schema.json — 12 taxonomy axes defined as DATA, not code +- AIRO (AI Risk Ontology) + VAIR framework +- Schema nodes are first-class graph citizens +- Hierarchical meta-edges: edge-tables are nodes in a meta-graph + +### Layer 3: Cypher Enrichment Pipeline +- 30+ .cypher files, ~600KB of graph enrichment +- Palantir surveillance, geopolitical networks, chess knowledge +- Incremental patches (v31→v42) — like git for graph data +- Behavioral science schema on edges (receptor, mcclelland, rubicon) + +### Layer 4: Chess Cross-Domain Bridge +- chess_model.rs — openings, positions, evaluations as graph nodes +- Lichess evaluation database ingestion +- ladybug-rs fingerprint bridging: chess ↔ AI war via VSA RESONATE +- Elo testing via Lichess Bot API + +### Layer 5: Quarto Publishing +- aiwar-main/ — the visible web site +- Interactive force-directed graph (d3 + three.js via gravis) +- Interactive filterable tables (itables + DataTables.js) +- quarto-rust extension for executable Rust code blocks + +## What q2 Should Learn From This + +1. Graph data → programmatic Cypher generation (Layer 1) = notebook-query pattern +2. Schema-as-data (Layer 2) = the notebook's graph schema should be self-describing +3. Incremental enrichment (Layer 3) = notebook cells as enrichment patches +4. Cross-domain bridging (Layer 4) = query results connecting different knowledge domains +5. Interactive graph + tables as primary content (Layer 5) = the cockpit instruments +6. The quarto-rust extension pattern = execute code at view time, not just render time diff --git a/.claude/reference/aiwar/example_enrichment.cypher b/.claude/reference/aiwar/example_enrichment.cypher new file mode 100644 index 000000000..ca2d85859 --- /dev/null +++ b/.claude/reference/aiwar/example_enrichment.cypher @@ -0,0 +1,50 @@ +// ═══════════════════════════════════════════════════════════════ +// AIWAR ENRICHMENT: Palantir × Surveillance-Industrial Complex +// v1 — 2026-03-02 +// Sources: +// netzpolitik.org (2025) — Palantir policing/military +// Tagesspiegel (2025) — German police Palantir adoption +// Euronews (2025) — Baden-Württemberg Gotham contract +// business-humanrights.org — Egypt surveillance exports +// DW (2020) — Egyptian spy in Merkel's BPA +// Stanford Daily (2026) — Thiel-Epstein DOJ files +// NBC News (2026) — Epstein tech ties +// NPR (2025) — Palantir in Trump era +// Democracy Now (2025) — DOGE master database +// Fortune (2025) — DOGE era stocks +// Reuters (2025) — Golden Dome bid +// Novact (2024) — Mass surveillance Maghreb/Mashreq +// Dandc.eu — European spyware to Egypt +// EgyptWatch (2021) — French spyware to Sisi +// ═══════════════════════════════════════════════════════════════ +// Extends: aiwar_full.cypher (base graph), aiwar_enrichment_epstein.cypher (behavioral schema) +// Uses same behavioral science schema: receptor, mcclelland, rubicon, node_function, edge properties +// ═══════════════════════════════════════════════════════════════ + +// ════════════════════════════════════════════ +// §1 NEW SYSTEM NODES +// ════════════════════════════════════════════ + +// ── Palantir Products ── +MERGE (n:System:Operation:MLTask_Sort {id: 'ICM'}) +SET n.name = 'Investigative Case Management', + n.year = 2022, + n.current_status = 'Operation', + n.system_type = 'DataManagement, Profiling', + n.ml_task = 'Sort', + n.military_use = 'nan', + n.civic_use = 'Policing, BehaviorEvaluation', + n.purpose = 'AssessingRiskOfOffending, InformationRetrieval', + n.capacity = 'Profiling, SensitiveAttributeInference, Geolocation, BiometricCategorisation', + n.output = 'Decision', + n.impact = 'PsychologicalHarm, DistortionInHumanBehavior', + n.image = './assets/noun-software-industry-198331.png', + n.noun_key = 'surveillance', + n.note = 'ICE database. 5yr/$95.9M contract 2022. Searches birthplace, visa, race, criminal affiliation, license plate data. Tax data sharing added 2025.'; + +MERGE (n:System:Operation:MLTask_Predict {id: 'MavenSmartSystem'}) +SET n.name = 'Maven Smart System (MSS)', + n.year = 2025, + n.current_status = 'Operation', + n.system_type = 'IntelligentControlSystem, DataManagement', + n.ml_task = 'Predict', diff --git a/.claude/reference/aiwar/ingest.rs b/.claude/reference/aiwar/ingest.rs new file mode 100644 index 000000000..034bcb278 --- /dev/null +++ b/.claude/reference/aiwar/ingest.rs @@ -0,0 +1,209 @@ +// aiwar-neo4j-harvest/src/ingest.rs +// +// Neo4j Cypher generation for the AI War Cloud graph. +// +// NOVEL PATTERNS harvested for Neo4j succession (→ Ada Sigma Graph): +// +// Pattern 1: FACETED MULTI-LABEL NODES +// Nodes get multiple Neo4j labels based on their taxonomy axes. +// A System node might be (:System:GenerativeAI:Predict:Intelligence:Operation) +// This enables O(1) label-indexed queries across any axis. +// +// Pattern 2: SCHEMA ONTOLOGY AS CONSTRAINT GRAPH +// The Schema rows become (:SchemaValue) nodes with (:VALID_FOR) edges +// to (:SchemaAxis) nodes. This makes the ontology queryable and evolvable. +// +// Pattern 3: ICON-ADDRESSED VISUAL TOPOLOGY +// NounKey links create a visual namespace — nodes addressed by their +// icon/glyph rather than just by ID. Parallel to QHDR.sigma addressing. +// +// Pattern 4: TEMPORAL LAYERING +// year + currentStatus create a natural temporal partition. +// Nodes flow through Development → Deployment → Operation → Retirement. + +use crate::model::*; + +/// Generate CREATE CONSTRAINT statements +pub fn constraints() -> Vec<String> { + vec![ + "CREATE CONSTRAINT IF NOT EXISTS FOR (s:System) REQUIRE s.id IS UNIQUE".into(), + "CREATE CONSTRAINT IF NOT EXISTS FOR (s:Stakeholder) REQUIRE s.id IS UNIQUE".into(), + "CREATE CONSTRAINT IF NOT EXISTS FOR (c:CivicSystem) REQUIRE c.id IS UNIQUE".into(), + "CREATE CONSTRAINT IF NOT EXISTS FOR (h:HistoricalSystem) REQUIRE h.id IS UNIQUE".into(), + "CREATE CONSTRAINT IF NOT EXISTS FOR (p:Person) REQUIRE p.id IS UNIQUE".into(), + "CREATE CONSTRAINT IF NOT EXISTS FOR (sv:SchemaValue) REQUIRE sv.value IS UNIQUE".into(), + "CREATE INDEX IF NOT EXISTS FOR (s:System) ON (s.year)".into(), + "CREATE INDEX IF NOT EXISTS FOR (s:System) ON (s.current_status)".into(), + "CREATE INDEX IF NOT EXISTS FOR (s:System) ON (s.noun_key)".into(), + "CREATE INDEX IF NOT EXISTS FOR (s:Stakeholder) ON (s.stakeholder_type)".into(), + ] +} + +/// Generate MERGE for a System node with multi-label faceting +pub fn system_cypher(sys: &serde_json::Value) -> String { + let id = sys["id"].as_str().unwrap_or("unknown"); + let name = escape(sys["name"].as_str().unwrap_or(id)); + let year = sys["year"].as_i64().map(|y| y.to_string()).unwrap_or("null".into()); + let status = sys["currentStatus"].as_str().unwrap_or(""); + let sys_type = sys["type"].as_str().unwrap_or(""); + let ml_task = sys["MLTask"].as_str().unwrap_or(""); + let mil_use = sys["militaryUse"].as_str().unwrap_or(""); + let civ_use = sys["civicUse"].as_str().unwrap_or(""); + let purpose = escape(sys["purpose"].as_str().unwrap_or("")); + let capacity = escape(sys["capacity"].as_str().unwrap_or("")); + let technique = escape(sys["vair:technique"].as_str().unwrap_or("")); + let output = sys["output"].as_str().unwrap_or(""); + let risks = escape(sys["vair:riskSources"].as_str().unwrap_or("")); + let impact = escape(sys["impact"].as_str().unwrap_or("")); + let hover = escape(sys["hover"].as_str().unwrap_or("")); + let image = sys["image"].as_str().unwrap_or(""); + let noun_key = sys["nounKey"].as_str().unwrap_or(""); + + // Build dynamic labels from taxonomy axes + let mut labels = vec!["System".to_string()]; + if !status.is_empty() { labels.push(status.to_string()); } + if !ml_task.is_empty() { labels.push(format!("MLTask_{}", ml_task)); } + + let label_str = labels.join(":"); + + format!( + r#"MERGE (n:{label_str} {{id: '{id}'}}) +SET n.name = '{name}', + n.year = {year}, + n.current_status = '{status}', + n.system_type = '{sys_type}', + n.ml_task = '{ml_task}', + n.military_use = '{mil_use}', + n.civic_use = '{civ_use}', + n.purpose = '{purpose}', + n.capacity = '{capacity}', + n.technique = '{technique}', + n.output = '{output}', + n.risk_sources = '{risks}', + n.impact = '{impact}', + n.hover = '{hover}', + n.image = '{image}', + n.noun_key = '{noun_key}';"#, + ) +} + +/// Generate MERGE for a Stakeholder node +pub fn stakeholder_cypher(sh: &serde_json::Value) -> String { + let id = sh["id"].as_str().unwrap_or("unknown"); + let name = escape(sh["name"].as_str().unwrap_or(id)); + let sh_type = sh["type"].as_str().unwrap_or(""); + let airo = sh["airo:type"].as_str().unwrap_or(""); + let hover = escape(sh["hover"].as_str().unwrap_or("")); + let image = sh["image"].as_str().unwrap_or(""); + + let mut labels = vec!["Stakeholder".to_string()]; + if !sh_type.is_empty() { labels.push(sh_type.replace(' ', "").to_string()); } + if !airo.is_empty() { labels.push(airo.to_string()); } + + let label_str = labels.join(":"); + + format!( + r#"MERGE (n:{label_str} {{id: '{id}'}}) +SET n.name = '{name}', + n.stakeholder_type = '{sh_type}', + n.airo_type = '{airo}', + n.hover = '{hover}', + n.image = '{image}';"#, + ) +} + +/// Generate MERGE for a CivicSystem node +pub fn civic_cypher(c: &serde_json::Value) -> String { + let id = c["id"].as_str().unwrap_or("unknown"); + let name = escape(c["name"].as_str().unwrap_or(id)); + let year = c["year"].as_i64().map(|y| y.to_string()).unwrap_or("null".into()); + let status = c["currentStatus"].as_str().unwrap_or(""); + let ctype = c["type"].as_str().unwrap_or(""); + let hover = escape(c["hover"].as_str().unwrap_or("")); + let image = c["image"].as_str().unwrap_or(""); + let noun_key = c["nounKey"].as_str().unwrap_or(""); + + format!( + r#"MERGE (n:CivicSystem {{id: '{id}'}}) +SET n.name = '{name}', + n.year = {year}, + n.current_status = '{status}', + n.system_type = '{ctype}', + n.hover = '{hover}', + n.image = '{image}', + n.noun_key = '{noun_key}';"#, + ) +} + +/// Generate MERGE for edges +pub fn edge_cypher(edge: &serde_json::Value, rel_type: &str) -> String { + let source = edge["source"].as_str().unwrap_or("unknown"); + let target = edge["target"].as_str().unwrap_or("unknown"); + let label = escape(edge["label"].as_str().unwrap_or(rel_type)); + let weight = edge["weight"].as_f64().unwrap_or(1.0); + + // Use generic Node match since source/target can be any node type + format!( + r#"MATCH (a {{id: '{source}'}}) +MATCH (b {{id: '{target}'}}) +MERGE (a)-[r:{rel_type}]->(b) +SET r.label = '{label}', + r.weight = {weight};"#, + ) +} + +/// Generate the schema ontology as nodes + edges +/// This is the NOVEL pattern: schema-as-queryable-graph +pub fn schema_ontology_cypher(schema: &[serde_json::Value]) -> Vec<String> { + let mut stmts = Vec::new(); + + // Create axis nodes + let axes = [ + "currentStatus", "type", "militaryUse", "civicUse", + "MLTask", "MLType", "purpose", "capacity", "output", + "impact", "stakeholder", "airo_type", + ]; + for axis in &axes { + stmts.push(format!( + "MERGE (:SchemaAxis {{name: '{axis}'}});" + )); + } + + // For each schema row, create value nodes and link to axes + let field_map = [ + ("currentStatus:airo", "currentStatus"), + ("type", "type"), + ("militaryUse", "militaryUse"), + ("civicUse", "civicUse"), + ("MLTask", "MLTask"), + ("MLType", "MLType"), + ("purpose:vair", "purpose"), + ("capacity:airo", "capacity"), + ("output:airo", "output"), + ("impact:vair", "impact"), + ("stakeholder", "stakeholder"), + ("airo:type", "airo_type"), + ]; + + for row in schema { + for (json_key, axis_name) in &field_map { + if let Some(val) = row[json_key].as_str() { + if !val.is_empty() { + let escaped = escape(val); + stmts.push(format!( + r#"MERGE (v:SchemaValue {{value: '{escaped}'}}) +WITH v +MATCH (a:SchemaAxis {{name: '{axis_name}'}}) +MERGE (v)-[:VALID_FOR]->(a);"#, + )); + } + } + } + } + + stmts +} + +fn escape(s: &str) -> String { + s.replace('\'', "\\'").replace('\\', "\\\\") +} diff --git a/.claude/reference/aiwar/main.rs b/.claude/reference/aiwar/main.rs new file mode 100644 index 000000000..5a9cecaa9 --- /dev/null +++ b/.claude/reference/aiwar/main.rs @@ -0,0 +1,590 @@ +// aiwar-neo4j-harvest/src/main.rs +// +// AI War Cloud + Chess Knowledge → Neo4j Harvester +// Sources: +// - AI War Cloud: https://gitlab.com/sarahciston/aiwar +// - Chess openings: https://github.com/lichess-org/chess-openings +// - Chess variations: https://github.com/hayatbiralem/eco.json +// - Chess evaluations: https://database.lichess.org/#evals +// Target: Neo4j / neo4j-rs (Ada Sigma Graph successor patterns) +// +// Usage: +// cargo run -- cypher # Generate AI War .cypher files +// cargo run -- neo4j # Direct AI War ingest +// cargo run -- analyze # Print graph statistics +// cargo run --features chess -- chess-openings # Harvest ECO openings +// cargo run --features chess -- chess-evals # Harvest Lichess evaluations +// cargo run --features chess -- chess-bridge # Generate cross-domain bridge + +pub mod error; +mod model; +mod ingest; +#[cfg(feature = "chess")] +mod chess_model; +#[cfg(feature = "chess")] +mod chess_ingest; + +use anyhow::Result; +use clap::{Parser, Subcommand}; +use std::fs; + +#[derive(Parser)] +#[command(name = "aiwar-neo4j")] +#[command(about = "AI War Cloud + Chess Knowledge → Neo4j ingestor")] +struct Cli { + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + /// Generate Cypher scripts for offline AI War ingestion + Cypher { + /// Output directory for .cypher files + #[arg(short, long, default_value = "cypher")] + output: String, + }, + /// Direct ingestion into Neo4j + Neo4j { + /// Neo4j URI + #[arg(long, env = "NEO4J_URI")] + uri: String, + /// Neo4j user + #[arg(long, env = "NEO4J_USER", default_value = "neo4j")] + user: String, + /// Neo4j password + #[arg(long, env = "NEO4J_PASSWORD")] + password: String, + }, + /// Analyze graph patterns + Analyze, + + // ── Chess Harvest Commands (--features chess) ──────────────── + /// Harvest ECO openings + eco.json into graph + #[cfg(feature = "chess")] + ChessOpenings { + /// Output directory for .cypher files + #[arg(short, long, default_value = "cypher")] + output: String, + /// Cache directory for downloaded data + #[arg(long, default_value = "data/chess")] + cache_dir: String, + }, + /// Harvest Lichess evaluation database + #[cfg(feature = "chess")] + ChessEvals { + /// Path to Lichess eval JSONL file (download from database.lichess.org) + #[arg(long)] + eval_file: String, + /// Minimum Stockfish depth to include + #[arg(long, default_value = "40")] + depth_min: u32, + /// Maximum number of positions to ingest + #[arg(long, default_value = "100000")] + limit: usize, + /// Output directory for .cypher files + #[arg(short, long, default_value = "cypher")] + output: String, + }, + /// Generate AI War ↔ Chess cross-domain bridge + #[cfg(feature = "chess")] + ChessBridge { + /// Output directory for .cypher files + #[arg(short, long, default_value = "cypher")] + output: String, + /// Bot name for Lichess Elo testing + #[arg(long, default_value = "AdaChessBot")] + bot_name: String, + }, + + /// Ingest live game data from stonksfish-ada harvester + LiveGames { + /// Directory containing .cypher files from stonksfish-ada + #[arg(short, long, default_value = "harvest/cypher")] + input: String, + /// Also read JSONL files from the JSON harvester + #[arg(long)] + jsonl: Option<String>, + /// Direct Neo4j ingestion (requires NEO4J_URI, NEO4J_USER, NEO4J_PASSWORD) + #[arg(long)] + neo4j: bool, + /// Output directory for merged .cypher files + #[arg(short, long, default_value = "cypher")] + output: String, + }, +} + +fn load_graph() -> Result<serde_json::Value> { + let data = fs::read_to_string("data/aiwar_graph.json")?; + Ok(serde_json::from_str(&data)?) +} + +fn load_schema() -> Result<Vec<serde_json::Value>> { + let data = fs::read_to_string("data/schema.json")?; + Ok(serde_json::from_str(&data)?) +} + +fn cmd_cypher(output: &str) -> Result<()> { + let graph = load_graph()?; + let schema = load_schema()?; + fs::create_dir_all(output)?; + + let mut all_stmts: Vec<String> = Vec::new(); + + // 1. Constraints & indexes + all_stmts.extend(ingest::constraints()); + all_stmts.push("// ── Schema Ontology ──".into()); + + // 2. Schema ontology (novel: schema-as-data) + all_stmts.extend(ingest::schema_ontology_cypher(&schema)); + + // 3. Nodes + all_stmts.push("// ── Systems ──".into()); + if let Some(systems) = graph["N_Systems"].as_array() { + for sys in systems { + all_stmts.push(ingest::system_cypher(sys)); + } + } + + all_stmts.push("// ── Stakeholders ──".into()); + if let Some(stakeholders) = graph["N_Stakeholders"].as_array() { + for sh in stakeholders { + all_stmts.push(ingest::stakeholder_cypher(sh)); + } + } + + all_stmts.push("// ── Civic Systems ──".into()); + if let Some(civic) = graph["N_Civic"].as_array() { + for c in civic { + all_stmts.push(ingest::civic_cypher(c)); + } + } + + // 4. Edges + let edge_tables = [ + ("E_isDevelopedBy", "DEVELOPED_BY"), + ("E_isDeployedBy", "DEPLOYED_BY"), + ("E_connection", "CONNECTED_TO"), + ("E_place", "USED_IN"), + ("E_people", "PERSON_LINK"), + ]; + + for (table, rel_type) in &edge_tables { + all_stmts.push(format!("// ── {table} ──")); + if let Some(edges) = graph[table].as_array() { + for edge in edges { + all_stmts.push(ingest::edge_cypher(edge, rel_type)); + } + } + } + + // Write single combined file + let combined = all_stmts.join("\n\n"); + fs::write(format!("{output}/aiwar_full.cypher"), &combined)?; + + // Also write split files for incremental loading + let constraint_stmts: Vec<_> = ingest::constraints(); + fs::write(format!("{output}/00_constraints.cypher"), constraint_stmts.join("\n"))?; + + println!("Generated {} statements → {output}/", all_stmts.len()); + println!(" aiwar_full.cypher (combined)"); + println!(" 00_constraints.cypher (constraints only)"); + + Ok(()) +} + +fn cmd_analyze() -> Result<()> { + let graph = load_graph()?; + let schema = load_schema()?; + + println!("╔══════════════════════════════════════════════════════╗"); + println!("║ AI War Cloud — Graph Analysis & Novel Patterns ║"); + println!("║ Source: gitlab.com/sarahciston/aiwar ║"); + println!("╚══════════════════════════════════════════════════════╝\n"); + + // Node counts + let n_sys = graph["N_Systems"].as_array().map(|a| a.len()).unwrap_or(0); + let n_stake = graph["N_Stakeholders"].as_array().map(|a| a.len()).unwrap_or(0); + let n_civic = graph["N_Civic"].as_array().map(|a| a.len()).unwrap_or(0); + let n_hist = graph["N_Historical"].as_array().map(|a| a.len()).unwrap_or(0); + let n_people = graph["N_People"].as_array().map(|a| a.len()).unwrap_or(0); + let total_nodes = n_sys + n_stake + n_civic + n_hist + n_people; + + println!("NODES ({total_nodes} total):"); + println!(" Systems: {n_sys}"); + println!(" Stakeholders: {n_stake}"); + println!(" Civic: {n_civic}"); + println!(" Historical: {n_hist}"); + println!(" People: {n_people}"); + + // Edge counts + let edge_tables = ["E_connection", "E_isDevelopedBy", "E_isDeployedBy", "E_place", "E_people", "E_hierarchical"]; + let mut total_edges = 0; + println!("\nEDGES:"); + for table in &edge_tables { + let count = graph[table].as_array().map(|a| a.len()).unwrap_or(0); + total_edges += count; + println!(" {table}: {count}"); + } + println!(" Total: {total_edges}"); + + // Schema axes + println!("\nSCHEMA ONTOLOGY ({} taxonomy axes):", schema[0].as_object().map(|o| o.len()).unwrap_or(0)); + println!(" currentStatus: Development → Deployment → Operation → Retirement"); + println!(" type: {} distinct values", count_distinct(&schema, "type")); + println!(" MLTask: {} distinct values", count_distinct(&schema, "MLTask")); + println!(" militaryUse: {} distinct values", count_distinct(&schema, "militaryUse")); + println!(" purpose: {} distinct values", count_distinct(&schema, "purpose:vair")); + println!(" capacity: {} distinct values", count_distinct(&schema, "capacity:airo")); + println!(" impact: {} distinct values", count_distinct(&schema, "impact:vair")); + println!(" airo:type: {} distinct values (AISubject|AIDeployer|AIDeveloper|AIProvider)", count_distinct(&schema, "airo:type")); + + // Novel patterns report + println!("\n╔══════════════════════════════════════════════════════╗"); + println!("║ NOVEL PATTERNS for Neo4j Succession ║"); + println!("╚══════════════════════════════════════════════════════╝\n"); + + println!("1. FACETED MULTI-LABEL NODES"); + println!(" Each System carries 12+ taxonomy axes simultaneously."); + println!(" Neo4j succession: Use as multi-label (:System:Predict:Intelligence)"); + println!(" → Ada pattern: Maps to QHDR.sigma glyph coordinates\n"); + + println!("2. SCHEMA-AS-DATA ONTOLOGY"); + println!(" The Schema sheet defines valid values as rows, not code."); + println!(" 31 rows × 12 axes = self-describing graph."); + println!(" → Ada pattern: Schema nodes enable runtime ontology evolution\n"); + + println!("3. DUAL-ROLE BIPARTITE COLLAPSE"); + println!(" Stakeholders appear as both edge-source (develops) AND"); + println!(" edge-target (connection/part-of). Creates multigraph."); + println!(" → Ada pattern: Entity plays multiple roles in different contexts\n"); + + println!("4. ICON-ADDRESSED VISUAL TOPOLOGY (noun_key)"); + println!(" 72 visual nouns with unicode glyphs form a spatial index."); + println!(" Nodes addressed by icon, not just by relational ID."); + println!(" → Ada pattern: Memory-as-place, QHDR coordinate addressing\n"); + + println!("5. HIERARCHICAL META-EDGES"); + println!(" E_hierarchical encodes which edge-tables connect to which"); + println!(" node-tables. The schema is itself a graph."); + println!(" → Ada pattern: Sigma graph self-description layer\n"); + + println!("6. TEMPORAL STATUS FLOW"); + println!(" Systems have year + currentStatus creating a lifecycle."); + println!(" Development → Deployment → Operation → Retirement"); + println!(" Enables temporal queries: 'systems deployed since 2020'"); + println!(" → Ada pattern: Temporal sigma node versioning\n"); + + println!("7. AIRO ONTOLOGY ALIGNMENT"); + println!(" Uses AI Risk Ontology (AIRO) + VAIR framework natively."); + println!(" purpose:vair, capacity:airo, impact:vair fields."); + println!(" → Ada pattern: Standardized risk/impact assessment on graph nodes\n"); + + Ok(()) +} + +fn count_distinct(schema: &[serde_json::Value], key: &str) -> usize { + let mut vals: Vec<String> = schema.iter() + .filter_map(|row| row[key].as_str().map(|s| s.to_string())) + .collect(); + vals.sort(); + vals.dedup(); + vals.len() +} + +#[tokio::main] +async fn main() -> Result<()> { + tracing_subscriber::fmt::init(); + let cli = Cli::parse(); + + match cli.command { + Commands::Cypher { output } => cmd_cypher(&output), + Commands::Neo4j { uri, user, password } => { + println!("Direct Neo4j ingestion → {uri}"); + println!("(generating cypher first, then executing)"); + cmd_cypher("cypher")?; + + let graph = neo4rs::Graph::new(&uri, &user, &password).await?; + let stmts = fs::read_to_string("cypher/aiwar_full.cypher")?; + + let mut count = 0; + for stmt in stmts.split(";\n") { + let trimmed = stmt.trim(); + if trimmed.is_empty() || trimmed.starts_with("//") { + continue; + } + match graph.run(neo4rs::query(trimmed)).await { + Ok(_) => count += 1, + Err(e) => eprintln!(" WARN: {e} | stmt: {}", &trimmed[..trimmed.len().min(80)]), + } + } + println!("Executed {count} statements against Neo4j"); + Ok(()) + } + Commands::Analyze => cmd_analyze(), + + // ── Chess Harvest Commands ────────────────────────────── + #[cfg(feature = "chess")] + Commands::ChessOpenings { output, cache_dir } => { + cmd_chess_openings(&output, &cache_dir).await + } + #[cfg(feature = "chess")] + Commands::ChessEvals { eval_file, depth_min, limit, output } => { + cmd_chess_evals(&output, &eval_file, depth_min, limit) + } + #[cfg(feature = "chess")] + Commands::ChessBridge { output, bot_name } => { + cmd_chess_bridge(&output, &bot_name) + } + + Commands::LiveGames { input, jsonl, neo4j, output } => { + cmd_live_games(&input, jsonl.as_deref(), neo4j, &output).await + } + } +} + +// ── Live Game Ingestion (from stonksfish-ada) ──────────────────── + +async fn cmd_live_games(input: &str, jsonl: Option<&str>, direct_neo4j: bool, output: &str) -> Result<()> { + use std::path::Path; + + println!("╔══════════════════════════════════════════════════════╗"); + println!("║ Live Game Harvester (stonksfish-ada → Neo4j) ║"); + println!("║ Ingests .cypher and .jsonl from live Lichess games ║"); + println!("╚══════════════════════════════════════════════════════╝\n"); + + let input_path = Path::new(input); + if !input_path.exists() { + println!("Input directory '{}' not found.", input); + println!("Run stonksfish-ada first to generate harvest data:"); + println!(" HARVEST_DIR=./harvest cargo run --bin stonksfish-ada --release"); + return Ok(()); + } + + // Collect all .cypher files from the input directory + let mut cypher_files: Vec<_> = fs::read_dir(input_path)? + .filter_map(|e| e.ok()) + .filter(|e| e.path().extension().map(|ext| ext == "cypher").unwrap_or(false)) + .collect(); + cypher_files.sort_by_key(|e| e.file_name()); + + println!("Found {} .cypher files in {}", cypher_files.len(), input); + + // Merge all cypher statements + let mut all_stmts: Vec<String> = Vec::new(); + let mut total_lines = 0; + + for entry in &cypher_files { + let content = fs::read_to_string(entry.path())?; + let lines: Vec<&str> = content.lines() + .filter(|l| !l.trim().is_empty() && !l.trim().starts_with("//")) + .collect(); + total_lines += lines.len(); + println!(" {} ({} statements)", entry.file_name().to_string_lossy(), lines.len()); + all_stmts.push(content); + } + + // Read JSONL if provided (for statistics/analysis) + let mut game_count = 0; + let mut total_moves = 0; + if let Some(jsonl_path) = jsonl { + let jsonl_file = Path::new(jsonl_path); + if jsonl_file.exists() { + let content = fs::read_to_string(jsonl_file)?; + for line in content.lines() { + if let Ok(record) = serde_json::from_str::<serde_json::Value>(line) { + if record["type"] == "game" { + game_count += 1; + total_moves += record["total_moves"].as_u64().unwrap_or(0); + } + } + } + println!("\nJSONL summary: {} games, {} total moves", game_count, total_moves); + } + } + + // Write merged output + fs::create_dir_all(output)?; + let out_path = format!("{output}/live_games_merged.cypher"); + let combined = all_stmts.join("\n"); + fs::write(&out_path, &combined)?; + println!("\nMerged {} statements → {out_path}", total_lines); + + // Direct Neo4j ingestion if requested + if direct_neo4j { + let uri = std::env::var("NEO4J_URI").expect("NEO4J_URI required for --neo4j"); + let user = std::env::var("NEO4J_USER").unwrap_or_else(|_| "neo4j".to_string()); + let password = std::env::var("NEO4J_PASSWORD").expect("NEO4J_PASSWORD required for --neo4j"); + + println!("\nIngesting into Neo4j at {uri}..."); + let graph = neo4rs::Graph::new(&uri, &user, &password).await?; + + let mut count = 0; + let mut errors = 0; + for stmt_block in &all_stmts { + for stmt in stmt_block.split(";\n") { + let trimmed = stmt.trim(); + if trimmed.is_empty() || trimmed.starts_with("//") { + continue; + } + match graph.run(neo4rs::query(trimmed)).await { + Ok(_) => count += 1, + Err(e) => { + errors += 1; + if errors <= 5 { + eprintln!(" WARN: {e} | stmt: {}", &trimmed[..trimmed.len().min(80)]); + } + } + } + } + } + println!("Executed {} statements ({} errors)", count, errors); + } + + println!("\nHarvest pipeline:"); + println!(" stonksfish-ada (live games) → harvest/cypher/*.cypher"); + println!(" aiwar-neo4j live-games → {out_path}"); + println!(" Compatible with chess-openings, chess-evals, chess-bridge data"); + + Ok(()) +} + +// ── Chess Command Implementations ──────────────────────────────── + +#[cfg(feature = "chess")] +async fn cmd_chess_openings(output: &str, cache_dir: &str) -> Result<()> { + use std::path::Path; + + println!("╔══════════════════════════════════════════════════════╗"); + println!("║ Chess Opening Harvester ║"); + println!("║ Sources: lichess-org/chess-openings + eco.json ║"); + println!("╚══════════════════════════════════════════════════════╝\n"); + + let cache = Path::new(cache_dir); + fs::create_dir_all(cache)?; + fs::create_dir_all(output)?; + + let mut all_stmts: Vec<String> = Vec::new(); + + // 1. Chess constraints + println!("Generating chess constraints..."); + all_stmts.extend(chess_ingest::chess_constraints()); + + // 2. Chess schema ontology (parallels AIRO pattern) + println!("Generating chess schema ontology..."); + all_stmts.push("// ── Chess Schema Ontology ──".into()); + all_stmts.extend(chess_ingest::chess_schema_cypher()); + + // 3. Download + parse Lichess openings (TSV) + println!("Downloading Lichess chess-openings..."); + let openings = chess_ingest::download_openings(cache).await?; + all_stmts.push("// ── ECO Openings ──".into()); + let opening_stmts = chess_ingest::openings_cypher(&openings); + println!(" Generated {} opening statements", opening_stmts.len()); + all_stmts.extend(opening_stmts); + + // 4. Download + parse eco.json (12K+ variations) + println!("Downloading eco.json variations..."); + let eco_entries = chess_ingest::download_eco_json(cache).await?; + all_stmts.push("// ── eco.json Variations ──".into()); + let eco_stmts = chess_ingest::eco_json_cypher(&eco_entries); + println!(" Generated {} eco.json statements", eco_stmts.len()); + all_stmts.extend(eco_stmts); + + // Write combined file + let combined = all_stmts.join("\n\n"); + let out_path = format!("{output}/chess_openings.cypher"); + fs::write(&out_path, &combined)?; + + println!("\n Generated {} total statements → {out_path}", all_stmts.len()); + println!(" Openings: {}", openings.len()); + println!(" eco.json: {} variations", eco_entries.len()); + println!("\nReady for neo4j-rs Graph<MemoryBackend> or Neo4j server ingestion."); + + Ok(()) +} + +#[cfg(feature = "chess")] +fn cmd_chess_evals(output: &str, eval_file: &str, depth_min: u32, limit: usize) -> Result<()> { + use std::path::Path; + + println!("╔══════════════════════════════════════════════════════╗"); + println!("║ Chess Evaluation Harvester ║"); + println!("║ Source: Lichess evaluation database (JSONL) ║"); + println!("╚══════════════════════════════════════════════════════╝\n"); + + fs::create_dir_all(output)?; + + println!("Parsing {eval_file} (depth >= {depth_min}, limit {limit})..."); + let positions = chess_ingest::parse_lichess_evals( + Path::new(eval_file), + depth_min, + limit, + )?; + + let mut all_stmts: Vec<String> = Vec::new(); + all_stmts.extend(chess_ingest::chess_constraints()); + all_stmts.push("// ── Evaluated Positions ──".into()); + let eval_stmts = chess_ingest::eval_positions_cypher(&positions); + println!(" Generated {} evaluation statements", eval_stmts.len()); + all_stmts.extend(eval_stmts); + + let combined = all_stmts.join("\n\n"); + let out_path = format!("{output}/chess_evals.cypher"); + fs::write(&out_path, &combined)?; + + println!("\n Generated {} total statements → {out_path}", all_stmts.len()); + println!(" Positions: {}", positions.len()); + + Ok(()) +} + +#[cfg(feature = "chess")] +fn cmd_chess_bridge(output: &str, bot_name: &str) -> Result<()> { + println!("╔══════════════════════════════════════════════════════╗"); + println!("║ Chess ↔ AI War Cross-Domain Bridge ║"); + println!("║ + Lichess Bot / Elo Testing Configuration ║"); + println!("╚══════════════════════════════════════════════════════╝\n"); + + fs::create_dir_all(output)?; + + let mut all_stmts: Vec<String> = Vec::new(); + + // Bridge concepts + all_stmts.push("// ── Cross-Domain Bridge (Chess ↔ AI War) ──".into()); + let bridge_stmts = chess_ingest::aiwar_bridge_cypher(); + println!(" Generated {} bridge statements", bridge_stmts.len()); + all_stmts.extend(bridge_stmts); + + // Elo testing bot config + all_stmts.push("// ── Elo Testing Bot Configuration ──".into()); + let elo_stmts = chess_ingest::elo_testing_cypher(bot_name); + all_stmts.extend(elo_stmts); + + // Print Elo testing API info + println!("\n Elo Testing APIs:"); + println!(" ├── Lichess Bot API: https://lichess.org/api#tag/Bot"); + println!(" │ • Create bot account, play rated games via UCI"); + println!(" │ • Uses Glicko2 rating system (starts at 1500)"); + println!(" │ • Protocol: ruci crate (Rust UCI implementation)"); + println!(" │ • Guide: https://anmols.bearblog.dev/how-to-determine-chess-bot-elo-lichess/"); + println!(" ├── CCRL: https://www.computerchess.org.uk/ccrl/404/"); + println!(" │ • Submit engine for official CCRL Blitz/40/15 rating"); + println!(" │ • Current top: Stockfish 3650 Elo (Feb 2026)"); + println!(" ├── Chess-API: https://chess-api.com/"); + println!(" │ • Free Stockfish 17 REST API for strength calibration"); + println!(" │ • Use to benchmark our engine at fixed depth levels"); + println!(" └── Self-play rating estimation:"); + println!(" • Play 100+ games against Stockfish at fixed depths"); + println!(" • Depth 1 ≈ 1100 Elo, Depth 5 ≈ 2000, Depth 20 ≈ 3000+"); + println!(" • Compute Elo from win/draw/loss ratio"); + + let combined = all_stmts.join("\n\n"); + let out_path = format!("{output}/chess_bridge.cypher"); + fs::write(&out_path, &combined)?; + + println!("\n Generated {} total statements → {out_path}", all_stmts.len()); + println!(" Bot name: {bot_name}"); + + Ok(()) +} diff --git a/.claude/reference/aiwar/model.rs b/.claude/reference/aiwar/model.rs new file mode 100644 index 000000000..e024a6a40 --- /dev/null +++ b/.claude/reference/aiwar/model.rs @@ -0,0 +1,168 @@ +// aiwar-neo4j-harvest/src/model.rs +// +// Graph Schema Harvested from sarahciston/aiwar (GitLab) +// Novel patterns for Neo4j succession: +// +// 1. MULTI-TAXONOMY NODES: Each node carries parallel classification axes +// (AIRO ontology: type, purpose, capacity, impact) + domain-specific +// enums (MLTask, militaryUse, civicUse). This is a "faceted graph" — +// nodes belong to multiple overlapping taxonomies simultaneously. +// +// 2. DUAL-ROLE EDGES: The same entity appears as both source AND target +// across different edge tables (Stakeholder→develops→System, +// System→deployed_by→Stakeholder). This creates a bipartite-like +// structure that collapses into a multigraph. +// +// 3. SCHEMA-AS-DATA: The Schema sheet IS the ontology — it defines +// valid enum values as rows, not as code. The graph is self-describing. +// +// 4. HIERARCHICAL META-EDGES: E_hierarchical encodes the *schema itself* +// as edges (E_isDeployedBy → N_Systems), creating a meta-graph where +// the relationship types are first-class nodes. +// +// 5. ICON-ADDRESSED NODES: Nodes carry `nounKey` and `image` that map +// to visual nouns — the graph is designed for spatial/visual traversal, +// not just relational queries. This is the "memory as place" pattern. + +use serde::{Deserialize, Serialize}; + +// ── Node Types ────────────────────────────────────────────────────── + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct System { + pub id: String, + pub name: String, + pub year: Option<i32>, + pub current_status: Option<String>, // Development | Deployment | Operation | Retirement + #[serde(rename = "type")] + pub system_type: Option<String>, // CSV of: GenerativeAI, RecommendationSystem, ComputerVision, IoT... + pub ml_task: Option<String>, // Generate | Predict | Recognize | Capture | Store | Sort + pub military_use: Option<String>, // Intelligence | Command | Robot | Weapon + pub civic_use: Option<String>, // RecommenderSystem, AR, Policing, BehaviorEvaluation... + pub ml_tasks: Option<String>, // Detailed: Ranking, Recommendation, SignalAnalysis... + pub purpose: Option<String>, // AIRO: PredictiveMapping, ProducingRecommendation... + pub capacity: Option<String>, // AIRO: Profiling, FaceRecognition, BehaviourAnalysis... + pub vair_technique: Option<String>, // DeepLearning, LanguageModels, StatisticalTechnique... + pub output: Option<String>, // Action | Content | Decision | Recommendation + pub vair_risk_sources: Option<String>, // InaccuratePrediction, BiasedTrainingData... + pub impact: Option<String>, // PhysicalInjury, WellbeingImpact, PsychologicalHarm + pub hover: Option<String>, // Tooltip text + pub image: Option<String>, // Icon path + pub noun_key: Option<String>, // Visual noun address +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Stakeholder { + pub id: String, + pub name: String, + #[serde(rename = "type")] + pub stakeholder_type: String, // Nation | TechCompany | DefenseCompany | Military | Institution | Investor + pub airo_type: Option<String>, // AISubject | AIDeployer | AIDeveloper | AIProvider + pub hover: Option<String>, + pub image: Option<String>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CivicSystem { + pub id: String, + pub name: String, + pub year: Option<i32>, + pub current_status: Option<String>, + #[serde(rename = "type")] + pub system_type: Option<String>, + pub hover: Option<String>, + pub image: Option<String>, + pub noun_key: Option<String>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct HistoricalSystem { + pub id: String, + pub name: String, + pub year: Option<i32>, + pub current_status: Option<String>, + #[serde(rename = "type")] + pub system_type: Option<String>, + pub military_use: Option<String>, + pub civic_use: Option<String>, + pub hover: Option<String>, + pub image: Option<String>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Person { + pub id: String, + pub name: String, + #[serde(rename = "type")] + pub person_type: Option<String>, // Owner, Investor, Founder... + pub airo_type: Option<String>, + pub hover: Option<String>, + pub image: Option<String>, +} + +// ── Edge Types ────────────────────────────────────────────────────── + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Edge { + pub source: String, + pub target: String, + pub label: Option<String>, + pub weight: Option<f64>, + pub hover: Option<String>, + pub reference: Option<String>, +} + +// ── Schema Ontology (the novel part: schema-as-data) ──────────────── + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SchemaRow { + #[serde(rename = "currentStatus:airo")] + pub current_status: Option<String>, + #[serde(rename = "type")] + pub node_type: Option<String>, + #[serde(rename = "militaryUse")] + pub military_use: Option<String>, + #[serde(rename = "civicUse")] + pub civic_use: Option<String>, + #[serde(rename = "MLTask")] + pub ml_task: Option<String>, + #[serde(rename = "MLType")] + pub ml_type: Option<String>, + #[serde(rename = "purpose:vair")] + pub purpose: Option<String>, + #[serde(rename = "capacity:airo")] + pub capacity: Option<String>, + #[serde(rename = "output:airo")] + pub output: Option<String>, + #[serde(rename = "impact:vair")] + pub impact: Option<String>, + pub stakeholder: Option<String>, + #[serde(rename = "airo:type")] + pub airo_type: Option<String>, +} + +// ── Meta-Edges (hierarchical schema graph) ────────────────────────── + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MetaEdge { + pub source: String, + pub target: String, +} + +// ── Full Graph Container ──────────────────────────────────────────── + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AiWarGraph { + pub schema: Vec<SchemaRow>, + pub systems: Vec<System>, + pub civic: Vec<CivicSystem>, + pub historical: Vec<HistoricalSystem>, + pub stakeholders: Vec<Stakeholder>, + pub people: Vec<Person>, + pub edges_connection: Vec<Edge>, + pub edges_developed: Vec<Edge>, + pub edges_deployed: Vec<Edge>, + pub edges_place: Vec<Edge>, + pub edges_people: Vec<Edge>, + pub meta_edges: Vec<MetaEdge>, +} diff --git a/.claude/reference/aiwar/quarto/_extensions/wurli/quarto-rust/_extension.yml b/.claude/reference/aiwar/quarto/_extensions/wurli/quarto-rust/_extension.yml new file mode 100644 index 000000000..c6d271d97 --- /dev/null +++ b/.claude/reference/aiwar/quarto/_extensions/wurli/quarto-rust/_extension.yml @@ -0,0 +1,9 @@ +name: quarto-rust +title: Use the Rust programming language with quarto +author: Jacob Scott +version: 0.1.0 +quarto-required: ">=1.3.450" +contributes: + filters: + - quarto-rust.lua + diff --git a/.claude/reference/aiwar/quarto/_extensions/wurli/quarto-rust/quarto-rust.lua b/.claude/reference/aiwar/quarto/_extensions/wurli/quarto-rust/quarto-rust.lua new file mode 100644 index 000000000..e4ba23ee4 --- /dev/null +++ b/.claude/reference/aiwar/quarto/_extensions/wurli/quarto-rust/quarto-rust.lua @@ -0,0 +1,161 @@ +local QuartoRustVersion = "0.1.0" +local hasDoneRustSetup = false +local counter = 0 + +-- quarto.doc.include_file("after-body", "highlight.js") +-- quarto.doc.include_file("after-body", "rust-playground.js") + +local function ensureRustSetup() + if hasDoneRustSetup then + return + end + + hasDoneRustSetup = true + + + quarto.doc.add_html_dependency({ + name = "rust-playground", + version = QuartoRustVersion, + stylesheets = { + "run-rust-code-button.css", + }, + scripts = { + { path = "rust-playground.js", afterBody = true } + }, + }) + +end + + +-- Initialize a table that contains the default cell-level options +local qwebRDefaultCellOptions = { + ["context"] = "interactive" +} + +-- Copy the top level value and its direct children +-- Details: http://lua-users.org/wiki/CopyTable +local function shallowcopy(original) + -- Determine if its a table + if type(original) == 'table' then + -- Copy the top level to remove references + local copy = {} + for key, value in pairs(original) do + copy[key] = value + end + -- Return the copy + return copy + else + -- If original is not a table, return it directly since it's already a copy + return original + end +end + +-- Custom method for cloning a table with a shallow copy. +function table.clone(original) + return shallowcopy(original) +end + +local function mergeCellOptions(localOptions) + -- Copy default options to the mergedOptions table + local mergedOptions = table.clone(qwebRDefaultCellOptions) + + -- Override default options with local options + for key, value in pairs(localOptions) do + mergedOptions[key] = value + end + + -- Return the customized options + return mergedOptions +end + + + +-- Extract Quarto code cell options from the block's text +local function extractCodeBlockOptions(block) + + -- Access the text aspect of the code block + local code = block.text + + -- Define two local tables: + -- the block's attributes + -- the block's code lines + local cellOptions = {} + local newCodeLines = {} + + -- Iterate over each line in the code block + for line in code:gmatch("([^\r\n]*)[\r\n]?") do + -- Check if the line starts with "#|" and extract the key-value pairing + -- e.g. #| key: value goes to cellOptions[key] -> value + local key, value = line:match("^//|%s*(.-):%s*(.-)%s*$") + + -- If a special comment is found, then add the key-value pairing to the cellOptions table + if key and value then + cellOptions[key] = value + else + -- Otherwise, it's not a special comment, keep the code line + table.insert(newCodeLines, line) + end + end + + -- Merge cell options with default options + cellOptions = mergeCellOptions(cellOptions) + + -- Set the codeblock text to exclude the special comments. + cellCode = table.concat(newCodeLines, '\n') + + -- Return the code alongside options + return cellCode, cellOptions +end + + +local function isVariableEmpty(s) + return s == nil or s == '' +end + + +-- Remove lines with only whitespace until the first non-whitespace character is detected. +local function removeEmptyLinesUntilContent(codeText) + -- Iterate through each line in the codeText table + for _, value in ipairs(codeText) do + local detectedWhitespace = string.match(value, "^%s*$") + if isVariableEmpty(detectedWhitespace) then + table.remove(codeText, 1) + else + break + end + end + return codeText +end + + +function CodeBlock(el) + + ensureRustSetup() + + local no_attrs = not el.attr + local not_html = not quarto.doc.is_format("html") + local not_rust = not el.attr.classes:includes("{playground-rust}") + + if no_attrs or not_html or not_rust then + return el + end + + counter = counter + 1 + + cellCode, cellOpts = extractCodeBlockOptions(el) + + el["text"] = removeEmptyLinesUntilContent(cellCode) + + -- It seems the 'r' class is what causes nice formatting (including a copy + -- button) to be applied; not the 'cell-code' class >:( + el["attr"]["classes"] = { + "rust", + "cell-code", + "playground", + "language-rust", + "code-with-copy", + } + + return el + +end diff --git a/.claude/reference/aiwar/quarto/_extensions/wurli/quarto-rust/run-rust-code-button.css b/.claude/reference/aiwar/quarto/_extensions/wurli/quarto-rust/run-rust-code-button.css new file mode 100644 index 000000000..ec83c5d05 --- /dev/null +++ b/.claude/reference/aiwar/quarto/_extensions/wurli/quarto-rust/run-rust-code-button.css @@ -0,0 +1,35 @@ +.run-rust-code-button { + position: absolute; + top: 0; + right: 0; + border: 0; + margin-top: 5px; + margin-right: 30px; + background-color: transparent; + z-index: 3; +} + + .run-rust-code-button:before { + display: inline-block; + height: 1rem; + width: 1rem; + content: ""; + vertical-align: -0.125em; + background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(94, 94, 94)" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg>'); + background-repeat: no-repeat; + background-size: 1rem 1rem; +} + + + .run-rust-code-button:hover:before { + background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(13, 110, 253)" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg>'); +} + +.result { + border-radius: 0px; + margin-top: 15px; + background-color: white ; + border-left: solid; + border-color: darkgrey; +} + diff --git a/.claude/reference/aiwar/quarto/_extensions/wurli/quarto-rust/rust-playground.js b/.claude/reference/aiwar/quarto/_extensions/wurli/quarto-rust/rust-playground.js new file mode 100644 index 000000000..e5816f56d --- /dev/null +++ b/.claude/reference/aiwar/quarto/_extensions/wurli/quarto-rust/rust-playground.js @@ -0,0 +1,151 @@ +"use strict"; + +// Adapted from mdBook: https://github.com/rust-lang/mdBook/blob/master/src/theme/book.js + +// Global variable, shared between modules +function playground_text(playground, hidden = true) { + return playground.querySelector("code").innerText; +} + +function fetch_with_timeout(url, options, timeout = 6000) { + return Promise.race([ + fetch(url, options), + new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout)) + ]); +} + +var playgrounds = Array.from(document.querySelectorAll(".playground")); +if (playgrounds.length > 0) { + fetch_with_timeout("https://play.rust-lang.org/meta/crates", { + headers: { + 'Content-Type': "application/json", + }, + method: 'POST', + mode: 'cors', + }) + .then(response => response.json()) + .then(response => { + // get list of crates available in the rust playground + let playground_crates = response.crates.map(item => item["id"]); + playgrounds.forEach(block => handle_crate_list_update(block, playground_crates)); + }); +} + +function handle_crate_list_update(playground_block, playground_crates) { + // update the play buttons after receiving the response + update_play_button(playground_block, playground_crates); + + // and install on change listener to dynamically update ACE editors + if (window.ace) { + let code_block = playground_block.querySelector("code"); + } +} + +// updates the visibility of play button based on `no_run` class and +// used crates vs ones available on http://play.rust-lang.org +function update_play_button(pre_block, playground_crates) { + var play_button = pre_block.querySelector(".play-button"); + + // skip if code is `no_run` + if (pre_block.querySelector('code').classList.contains("no_run")) { + play_button.classList.add("hidden"); + return; + } + + // get list of `extern crate`'s from snippet + var txt = playground_text(pre_block); + var re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g; + var snippet_crates = []; + var item; + while (item = re.exec(txt)) { + snippet_crates.push(item[1]); + } + + // check if all used crates are available on play.rust-lang.org + var all_available = snippet_crates.every(function (elem) { + return playground_crates.indexOf(elem) > -1; + }); + + if (all_available) { + play_button.classList.remove("hidden"); + } else { + play_button.classList.add("hidden"); + } +} + +function run_rust_code(code_block) { + var result_block = code_block.querySelector(".result"); + if (!result_block) { + result_block = document.createElement('code'); + result_block.className = 'result language-bash'; + code_block.append(result_block); + } + + let text = playground_text(code_block); + let classes = code_block.querySelector('code').classList; + let edition = "2015"; + if (classes.contains("edition2018")) { + edition = "2018"; + } else if (classes.contains("edition2021")) { + edition = "2021"; + } + var params = { + version: "stable", + optimize: "0", + code: text, + edition: edition + }; + + if (text.indexOf("#![feature") !== -1) { + params.version = "nightly"; + } + + result_block.innerText = "Running..."; + + fetch_with_timeout("https://play.rust-lang.org/evaluate.json", { + headers: { + 'Content-Type': "application/json", + }, + method: 'POST', + mode: 'cors', + body: JSON.stringify(params) + }) + .then(response => response.json()) + .then(response => { + if (response.result.trim() === '') { + result_block.innerText = "No output"; + result_block.classList.add("result-no-output"); + } else { + result_block.innerText = response.result; + result_block.classList.remove("result-no-output"); + } + }) + .catch(error => result_block.innerText = "Playground Communication: " + error.message); +} + + + +// Process playground code blocks +Array.from(document.querySelectorAll(".playground")).forEach(function (pre_block) { + // Add play button + var buttons = pre_block.querySelector(".buttons"); + if (!buttons) { + buttons = document.createElement('div'); + buttons.className = 'buttons'; + pre_block.insertBefore(buttons, pre_block.firstChild); + } + + var runCodeButton = document.createElement('button'); + runCodeButton.className = 'run-rust-code-button play-button'; + + runCodeButton.title = 'Run this code'; + runCodeButton.setAttribute('aria-label', runCodeButton.title); + + buttons.insertBefore(runCodeButton, buttons.firstChild); + runCodeButton.addEventListener('click', function (e) { + run_rust_code(pre_block); + }); + + let code_block = pre_block.querySelector("code"); +}); + diff --git a/.claude/reference/aiwar/quarto/_quarto.yml b/.claude/reference/aiwar/quarto/_quarto.yml new file mode 100644 index 000000000..5bea32a35 --- /dev/null +++ b/.claude/reference/aiwar/quarto/_quarto.yml @@ -0,0 +1,35 @@ +jupyter: python3 +project: + type: default + output-dir: public + +site-url: https://sarahciston.gitlab.com/aiwarcloud + +author: + - name: Sarah Ciston + degrees: PhD + orcid: 0000-0001-9456-9537 + corresponding: true + email: sarah@sarahciston.com + +bibliography: src/bibliography.json + +format: + html: + theme: + - cosmo + # - brand + - src/style.scss + toc: true + toc-title: "Contents" + code-fold: true + code-annotations: hover + css: + - src/style.css + number-sections: false + reference-location: margin + toc-location: left + +# execute: + # freeze: auto +# debug: true \ No newline at end of file diff --git a/.claude/reference/aiwar/quarto/index.qmd b/.claude/reference/aiwar/quarto/index.qmd new file mode 100644 index 000000000..cbeebbf37 --- /dev/null +++ b/.claude/reference/aiwar/quarto/index.qmd @@ -0,0 +1,228 @@ +--- +title: AI War Cloud +subtitle: AI decision making from battlefield to desktop +# date: Aug 9 2025 +keywords: artificial intelligence, artistic research, automated decision making, autonomous weapons, critical AI, defense, generative AI, international security, machine learning, military, surveillance, technoimperialism, tech industry, warfare +format: + html: + toc: false +--- +**AI War Cloud is an interactive database and tangible interactive installation connecting and explaining the current techno-imperial boomerang that is perpetuated by machine learning.** + +```{python} +# | echo: false +# | column: page +# | label: fig-graph + +import pandas as pd +from pandas import Series, DataFrame +import networkx as nx +import gravis as gv +from pprint import pprint + +Sheets = pd.ExcelFile("./data/aiwc.ods") + +# create graph with edges from csv import +Edges_Deployed = pd.read_excel(Sheets, sheet_name = "E_isDeployedBy") +Edges_Developed = pd.read_excel(Sheets, sheet_name = "E_isDevelopedBy") +Edges_Place = pd.read_excel(Sheets, sheet_name = "E_place") +Edges_Connection = pd.read_excel(Sheets, sheet_name = "E_connection") +Edges_People = pd.read_excel(Sheets, sheet_name = "E_people") +all_edges = [Edges_Deployed, Edges_Developed, Edges_Place, Edges_Connection, Edges_People] +Edges = pd.concat(all_edges) + +g = nx.from_pandas_edgelist(Edges, + source='source', + target='target', + edge_attr=['label'], + create_using=nx.DiGraph(), #DiGraph for directed arrows or Graph for none, or MultiDiGraph for self-reference and multi reference + edge_key=False) + +# print(g.edges()) + + +# assign data to nodes (stakeholders) +Stakeholders = pd.read_excel(Sheets, sheet_name = "N_Stakeholders") #, header=0, index_col=0 +Stakeholders = Stakeholders.T # transforms from long to wide table +Stakeholders.index_col = 'id' + +StakeDict = Stakeholders.to_dict() +# pprint((StakeDict)) + +for d in StakeDict: + g.nodes[StakeDict[d]['id']].update(StakeDict[d]) + +# assign data to nodes (systems) +Systems = pd.read_excel(Sheets, sheet_name = "N_Systems") +Systems = Systems.T # transforms from long to wide table +Systems.index_col = 'id' + +SysDict = Systems.to_dict() + +for d in SysDict: + g.nodes[SysDict[d]['id']].update(SysDict[d]) + +# assign data to nodes (civic) +Civic = pd.read_excel(Sheets, sheet_name = "N_Civic") +Civic = Civic.T # transforms from long to wide table +Civic.index_col = 'id' + +CivDict = Civic.to_dict() + +for d in CivDict: + g.nodes[CivDict[d]['id']].update(CivDict[d]) + +# assign data to nodes (history) +Hist = pd.read_excel(Sheets, sheet_name = "N_Historical") +Hist = Hist.T # transforms from long to wide table +Hist.index_col = 'id' + +HistDict = Hist.to_dict() + +for d in HistDict: + g.nodes[HistDict[d]['id']].update(HistDict[d]) + +# assign data to nodes (people) +People = pd.read_excel(Sheets, sheet_name = "N_People") +Peep = People.T # transforms from long to wide table +Peep.index_col = 'id' + +PeepDict = Peep.to_dict() + +for d in Peep: + g.nodes[PeepDict[d]['id']].update(PeepDict[d]) + +### test nodes +# print(g.nodes.data()) +# print(g.nodes['Lavender']['id']) + +# visual settings +gg = g.graph +gg['edge_opacity'] = 0.25 +gg['node_opacity'] = 0 #.75 +# gg['node_shape'] = 'rectangle' +# gg['node_border_size'] = 0 +gg['edge_label_size'] = 5 +gg['node_label_size'] = 8 +# gg['node_color'] = 'gray' +# gg['border_size'] = 0 +gg['arrow_size'] = 6 + +## not working +# gg['node_click'] = 'anchor' #"<a id='id'</a>"#'Details: $hover' +# gg['nodes']['node id']['label'] = 'id' +# gg['nodes']['node id']['metadata'] = 'id' + +# centrality = nx.algorithms.degree_centrality(g) +# nx.set_node_attributes(g, centrality, 'size') + +# communities = nx.algorithms.community.louvain_communities(g) +# communities = nx.algorithms.community.greedy_modularity_communities(g) +# colors = ['#51DBD9', '#5186DB', '#51B2DB', '#51DBAB', '#515ADB', '#009ADB'] +# for community, color in zip(communities, colors): +# for node in community: +# g.nodes[node]['color'] = color #add edges to this too + +gv.d3(g, + graph_height=800, + zoom_factor=0.8, + show_details=False, + show_details_toggle_button=False, + show_node_label=True, + node_label_data_source='name', + # node_size_data_source='year', + node_size_factor = 2, + # use_node_size_normalization=True, + # node_size_normalization_max=20, + show_edge_label=True, + # edge_size_data_source='size', + # edge_size_normalization_max=3, + # edge_size_normalization_min=0.5, + edge_label_data_source='label', + edge_curvature=0, + node_hover_neighborhood=True, + node_hover_tooltip=True, + edge_hover_tooltip=True, + use_collision_force=True, + many_body_force_strength=- 400.0, + many_body_force_theta=0.9, + node_drag_fix=True, + show_node_image=True, + node_image_size_factor=2, + show_node_label_border=False, + show_edge_label_border=False, + # node_label_rotation=0 + node_label_font='Arial', # 'IBM Plex Mono', + # edge_label_font='IBM Plex Mono', + use_x_positioning_force = True, + x_positioning_force_strength = 0.11, + use_y_positioning_force = True, + y_positioning_force_strength = 0.11, + # attr(node_id = 'id'), + # use_centering_force = False, +) +``` + +**When the bots**, recommender systems, and automated agents many people use daily are the same technologies used to wage war, how should we understand and hold these systems to account? Ultimately, what responsibilities do tech makers and users have in choosing AI tools, when their development also leads to deadly outcomes at massive scales? With the spotlight now on systems like Ukraine's Palantir MetaConstellation and Israel's Lavender, the stakes for machine learning tasks are increasingly urgent and personal. This project examines the specific machine learning tasks used in military "AI Decision Support Systems" (AI-DSS). These combine massive amounts of data and processing to help make choices about who lives or dies, speeding up the process exponentially. The research presents a database that details how the training datasets, models, and inferences military tools rely on are the very same types used by consumers. It shows how these are also deployed by, or even upon, citizens of the countries that first developed them, after they are tested on vulnerable foreign populations in conflict zones. + +```{python} +# | echo: false +# | column: page +# | label: tbl-aiwartable +# | tbl-cap: "AI War Cloud Database: A collection of techno-military-industrial projects that use machine learning tasks." +## | tbl-colwidths: [3,1,3,3,3,3,1,5] + + +from IPython.display import display, HTML, Markdown +from tabulate import tabulate +import pandas as pd +from itables import show, options as opt, init_notebook_mode + +init_notebook_mode() + +df = pd.read_csv('data/aiwarcloud-table.csv', sep=',') + +df = df.drop(['Source', 'URL', 'Reference', 'Link'], axis=1) + +data = df.head(43) +# systems = df.count + +# options.buttons = [ 'copy', 'excel', 'pdf'] +opt.paging = False +opt.scrollY="800px" +opt.scrollCollapse=True +opt.columnDefs=[{"width": "20%", "targets": [3,4,5]}] +# opt.width='10%' +opt.autoWidth = True +# opt.classes = "cell" +opt.layout = { 'topEnd': 'search', + 'topStart': 'paging', + 'bottomStart': 'info', + 'bottomEnd': 'pageLength' } +# opt.lengthMenu = [20,50,100] +# opt.column_filters = 'header' + +show(data, classes="display wrap compact") + +``` + + + +<!-- ![ML Decision Tasks: A chart of categories of AI decision-making tasks, grouped by military objectives and corresponding commercial/civilian goals.](data/aiwarcloud-tasks.png){#fig-mltasks fig-alt="A chart of categories of AI decision-making tasks, grouped by military objectives and corresponding commercial/civilian goals." .lightbox .column-page } --> +<!-- .full-width --> + +## [About](about.html) { .no_toc } + +[Credits and Acknowledgments](about.html#credits) + +[Icon Legend](about.html#icon-legend) + +[Bibliography](about.html#full-bibliography) + +[GitLab Code](https://gitlab.com/sarahciston/aiwar) + +<br> + +[Winner of the 2025 STARTS Grand Prize – Artistic Exploration](https://starts-prize.aec.at/en/ai-war-cloud-database/) + +[![](public/assets/startsprize25logo.png)](https://starts-prize.aec.at/en/ai-war-cloud-database/) diff --git a/.claude/reference/aiwar/quarto/requirements.txt b/.claude/reference/aiwar/quarto/requirements.txt new file mode 100644 index 000000000..b13bab7cb --- /dev/null +++ b/.claude/reference/aiwar/quarto/requirements.txt @@ -0,0 +1,6 @@ +gravis +numpy +networkx +odf +odfpy +pandas \ No newline at end of file diff --git a/.claude/reference/aiwar/quarto/table.qmd b/.claude/reference/aiwar/quarto/table.qmd new file mode 100644 index 000000000..b4addde3b --- /dev/null +++ b/.claude/reference/aiwar/quarto/table.qmd @@ -0,0 +1,125 @@ +--- +title: AI War Cloud +subtitle: Battlefield to Desktop +date: Mar 20 2025 +--- + +```{python} +# | echo: false +# | column: page +# | label: tbl-aiwartable +# | tbl-cap: "AI War Cloud Database: A collection of techno-military-industrial projects that use machine learning tasks." +## | tbl-colwidths: [3,1,3,3,3,3,1,5] + + +from IPython.display import display, HTML, Markdown +from tabulate import tabulate +import pandas as pd +from itables import show, options as opt, init_notebook_mode + +init_notebook_mode() + +df = pd.read_csv('data/aiwarcloud-table.csv', sep=',') + +df = df.drop(['Source', 'URL', 'Reference', 'Link'], axis=1) + +data = df.head(43) +# systems = df.count + +# options.buttons = [ 'copy', 'excel', 'pdf'] +opt.paging = False +opt.scrollY="800px" +opt.scrollCollapse=True +opt.columnDefs=[{"width": "20%", "targets": [3,4,5]}, + {"className": "dt-body-left", "targets": [0,1,2,3,4,5,6]}] + #cell classes: https://datatables.net/manual/styling/classes#Cell-classes +opt.textAlign='left' +# opt.width='10%' +opt.autoWidth = True +# opt.classes = "cell" +opt.layout = { 'topEnd': 'search', + 'topStart': 'paging', + 'bottomStart': 'info', + 'bottomEnd': 'pageLength' } +# opt.lengthMenu = [20,50,100] +# opt.column_filters = 'header' + +show(data, classes="display wrap compact") + +``` + + +<!-- ```{python} +#| content: valuebox +#| title: "Systems" +#| icon: pencil +#| color: primary + +dict( + value = systems +) + +``` --> + +<!-- MARKDOWN TABLE VERSION --> +<!-- ```{python} +#| echo: false +#| column: page +#| label: tbl-aiwar +#| tbl-cap-location: top +#| tbl-cap-align: left +#| tbl-cap: "AI War Cloud Database: A collection of techno-military-industrial projects that use machine learning tasks." +#| tbl-colwidths: [30,10,30,125,125,125,125,75] +#| class: cell + +from IPython.display import display, HTML, Markdown +# from itables import show +from tabulate import tabulate +import pandas as pd + +df = pd.read_csv('data/aiwarcloud-table.csv', sep=',') + +dfDisp = df.drop(['Source', 'URL', 'Reference', 'Link'], axis=1) + +md_table = dfDisp.head(43).to_markdown( + index=False, + headers="keys", + ) + +# display(Markdown(md_table)) +display(dfDisp.head(43)) +``` --> + + + + +<!--{.cell}--> +<!-- ::: {.column-page} --> + +<!-- ```{python} +#| echo: false +#| column: page +#| label: tbl-aiwar +#| tbl-cap-location: top +#| tbl-cap-align: left +#| tbl-cap: "AI War Cloud Database: A collection of techno-military-industrial projects that use machine learning tasks." +#| tbl-colwidths: [30,10,30,125,125,125,125,75] +#| class: cell + +from IPython.display import display, HTML, Markdown +# from itables import show +from tabulate import tabulate +import pandas as pd + +df = pd.read_csv('data/aiwarcloud-table.csv', sep=',') + +dfDisp = df.drop(['Source', 'URL', 'Reference', 'Link'], axis=1) + +md_table = dfDisp.head(43).to_markdown( + index=False, + headers="keys", + ) + +# display(Markdown(md_table)) +display(dfDisp.head(43)) +``` --> \ No newline at end of file diff --git a/.claude/reference/aiwar/quarto/three.qmd b/.claude/reference/aiwar/quarto/three.qmd new file mode 100644 index 000000000..f42feaec1 --- /dev/null +++ b/.claude/reference/aiwar/quarto/three.qmd @@ -0,0 +1,170 @@ +--- +title: AI War Cloud +subtitle: AI decision making from battlefield to desktop +# date: Aug 1 2025 +keywords: artificial intelligence, artistic research, automated decision making, autonomous weapons, critical AI, defense, generative AI, international security, machine learning, military, surveillance, technoimperialism, tech industry, warfare +--- +**AI War Cloud is an interactive database and tangible interactive installation connecting and explaining the current techno-imperial boomerang that is perpetuated by machine learning.** + +```{python} +# | echo: false +# | column: page +# | label: fig-graph +## | fig-cap: "AI War Cloud Database connects AI decision support systems and machine learning tasks as they are used across military and commercial industries." +## | scroll: 800px +## | classes: cell + +import pandas as pd +from pandas import Series, DataFrame +import networkx as nx +import gravis as gv +from pprint import pprint + +Sheets = pd.ExcelFile("./data/aiwc.ods") + +# create graph with edges from csv import +Edges_Deployed = pd.read_excel(Sheets, sheet_name = "E_isDeployedBy") +Edges_Developed = pd.read_excel(Sheets, sheet_name = "E_isDevelopedBy") +Edges_Place = pd.read_excel(Sheets, sheet_name = "E_place") +Edges_Connection = pd.read_excel(Sheets, sheet_name = "E_connection") +Edges_People = pd.read_excel(Sheets, sheet_name = "E_people") +all_edges = [Edges_Deployed, Edges_Developed, Edges_Place, Edges_Connection, Edges_People] +Edges = pd.concat(all_edges) + +g = nx.from_pandas_edgelist(Edges, + source='source', + target='target', + edge_attr=['label'], + create_using=nx.Graph(), #DiGraph + edge_key=False) + +# print(g.edges()) + + +# assign data to nodes (stakeholders) +Stakeholders = pd.read_excel(Sheets, sheet_name = "N_Stakeholders") #, header=0, index_col=0 +Stakeholders = Stakeholders.T # transforms from long to wide table +Stakeholders.index_col = 'id' + +StakeDict = Stakeholders.to_dict() +# pprint((StakeDict)) + +for d in StakeDict: + g.nodes[StakeDict[d]['id']].update(StakeDict[d]) + +# assign data to nodes (systems) +Systems = pd.read_excel(Sheets, sheet_name = "N_Systems") +Systems = Systems.T # transforms from long to wide table +Systems.index_col = 'id' + +SysDict = Systems.to_dict() + +for d in SysDict: + g.nodes[SysDict[d]['id']].update(SysDict[d]) + +# assign data to nodes (civic) +Civic = pd.read_excel(Sheets, sheet_name = "N_Civic") +Civic = Civic.T # transforms from long to wide table +Civic.index_col = 'id' + +CivDict = Civic.to_dict() + +for d in CivDict: + g.nodes[CivDict[d]['id']].update(CivDict[d]) + +# assign data to nodes (history) +Hist = pd.read_excel(Sheets, sheet_name = "N_Historical") +Hist = Hist.T # transforms from long to wide table +Hist.index_col = 'id' + +HistDict = Hist.to_dict() + +for d in HistDict: + g.nodes[HistDict[d]['id']].update(HistDict[d]) + +# assign data to nodes (people) +People = pd.read_excel(Sheets, sheet_name = "N_People") +Peep = People.T # transforms from long to wide table +Peep.index_col = 'id' + +PeepDict = Peep.to_dict() + +for d in Peep: + g.nodes[PeepDict[d]['id']].update(PeepDict[d]) + +### test nodes +# print(g.nodes.data()) +# print(g.nodes['Lavender']['nounKey']) + +# visual settings +gg = g.graph +gg['edge_opacity'] = 0.25 +gg['node_opacity'] = 0 #.75 +# gg['node_shape'] = 'rectangle' +# gg['node_border_size'] = 0 +# gg['edge_label_size'] = 5 +gg['node_label_size'] = 9 +# gg['node_color'] = 'gray' +# gg['border_size'] = 0 +# gg['node_hover'] = '$name' +gg['node_click'] = 'Details: $hover' + +# centrality = nx.algorithms.degree_centrality(g) +# nx.set_node_attributes(g, centrality, 'size') + +# communities = nx.algorithms.community.louvain_communities(g) +# communities = nx.algorithms.community.greedy_modularity_communities(g) +# colors = ['#51DBD9', '#5186DB', '#51B2DB', '#51DBAB', '#515ADB', '#009ADB'] +# for community, color in zip(communities, colors): +# for node in community: +# g.nodes[node]['color'] = color #add edges to this too + +gv.three(g, + graph_height=800, + zoom_factor=-1, + show_details=False, + show_details_toggle_button=True, + show_node_label=True, + node_label_data_source='name', + # node_size_data_source='year', + node_size_factor = 2, + # node_click='details', + # use_node_size_normalization=True, + # node_size_normalization_max=20, + # show_edge_label=False, + # edge_size_data_source='size', + # edge_size_normalization_max=3, + # edge_size_normalization_min=0.5, + # edge_label_data_source='label', + edge_curvature=0, + node_hover_neighborhood=True, + node_hover_tooltip=True, + edge_hover_tooltip=True, + # use_collision_force=True, + many_body_force_strength=-1100, + many_body_force_theta=0.5, + node_drag_fix=True, + show_node_image=True, + node_image_size_factor=1.75, + show_node_label_border=False, + show_edge_label_border=False, + # node_label_rotation=0, + node_label_font='IBM Plex Mono', + use_x_positioning_force = True, + x_positioning_force_strength = 0.04, + use_y_positioning_force = True, + y_positioning_force_strength = 0.07, + use_z_positioning_force = True, + z_positioning_force_strength = 0.11, + # use_centering_force = False, +) + + +``` + + +Bibliography: [References](about.html#full-bibliography) + +Code: [GitLab](https://gitlab.com/sarahciston/aiwar) + +[Credits and Acknowledgments](about.html#credits) diff --git a/.claude/reference/aiwar/schema.json b/.claude/reference/aiwar/schema.json new file mode 100644 index 000000000..3df5522a0 --- /dev/null +++ b/.claude/reference/aiwar/schema.json @@ -0,0 +1,436 @@ +[ + { + "currentStatus:airo": "Development", + "type": "IntelligentControlSystem", + "militaryUse": "Robot", + "civicUse": "Policing", + "MLTask": "Capture", + "MLType": "ObjectRecognition", + "purpose:vair": "AssessingRiskOfOffending", + "capacity:airo": "BiometricsBasedEmotionRecognition", + "output:airo": "Action", + "impact:vair": "PsychologicalHarm", + "stakeholder": "Nation", + "airo:type": "AISubject" + }, + { + "currentStatus:airo": "Deployment", + "type": "GenerativeModel", + "militaryUse": "Intel", + "civicUse": "AR", + "MLTask": "Store", + "MLType": "ObjectDetection", + "purpose:vair": "PredictiveMapping", + "capacity:airo": "AudioProcessing", + "output:airo": "Content", + "impact:vair": "PhysicalInjury", + "stakeholder": "TechCompany", + "airo:type": "AIDeployer" + }, + { + "currentStatus:airo": "Operation", + "type": "NarrowAI", + "militaryUse": "Command", + "civicUse": "BehaviorEvaluation", + "MLTask": "Sort", + "MLType": "FaceRecognition", + "purpose:vair": "ProducingRecommendation", + "capacity:airo": "BehaviourAnalysis", + "output:airo": "Decision", + "impact:vair": "WellbeingImpact", + "stakeholder": "DefenseCompany", + "airo:type": "AIDeveloper" + }, + { + "currentStatus:airo": "Retirement", + "type": "TrainingDatabase", + "militaryUse": "Logistics", + "civicUse": "Logistics", + "MLTask": "Recognize", + "MLType": "PatternRecognition", + "purpose:vair": "DetectingCriminalOffences", + "capacity:airo": "BiometricIdentification", + "output:airo": "Prediction", + "impact:vair": "DistortionInHumanBehavior", + "stakeholder": "Institution", + "airo:type": "AIProvider" + }, + { + "currentStatus:airo": NaN, + "type": "ExpertSystem", + "militaryUse": "Prediction", + "civicUse": "RecommenderSystems", + "MLTask": "Predict", + "MLType": "Ranking", + "purpose:vair": "Monitoring", + "capacity:airo": "BiometricCategorisation", + "output:airo": "Recommendation", + "impact:vair": "Overreliance", + "stakeholder": "Military", + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": "ServiceRobot", + "militaryUse": "Mapping", + "civicUse": "ConsumerTracking", + "MLTask": "Assign", + "MLType": "SortingAlgorithm", + "purpose:vair": "DetectingIndividuals", + "capacity:airo": "ComputerVision", + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": "Police", + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": "MultiAgentSystem", + "militaryUse": "Personnel", + "civicUse": "Games", + "MLTask": "Generate", + "MLType": "Classification", + "purpose:vair": "DetectingLies", + "capacity:airo": "DialectRecognition", + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": "Company", + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": "Dashboard", + "militaryUse": "Intelligence", + "civicUse": "SocialWelfareSystems", + "MLTask": "Automate", + "MLType": "SignalAnalysis", + "purpose:vair": "PerformingBackgroundChecks", + "capacity:airo": "EmotionRecognition", + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": "Investor", + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": "Nation", + "militaryUse": "Operations", + "civicUse": "Security", + "MLTask": NaN, + "MLType": "DecisionTree", + "purpose:vair": "IdentifyingIndividuals", + "capacity:airo": "FaceRecognition", + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": "Untility", + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": "TechCompany", + "militaryUse": "Logistics", + "civicUse": "Marketing", + "MLTask": NaN, + "MLType": "ComputerVision", + "purpose:vair": "RecognizingIndividuals", + "capacity:airo": NaN, + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": "Owner", + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": "DefenseCompany", + "militaryUse": "Planning", + "civicUse": "Advertising", + "MLTask": NaN, + "MLType": "Recommendation", + "purpose:vair": "RemoteIdentification", + "capacity:airo": "Geolocation", + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": "CEO", + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": "Military", + "militaryUse": "Communications", + "civicUse": "Robot", + "MLTask": NaN, + "MLType": "SignalAnalysis", + "purpose:vair": "EvaluatingJobCandidates", + "capacity:airo": "GestureRecognition", + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": "Politician", + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": "Investor", + "militaryUse": "Command", + "civicUse": "Delivery", + "MLTask": NaN, + "MLType": "DecisionTree", + "purpose:vair": "EvaluatingEmployeePerformance", + "capacity:airo": "ImageGeneration", + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": "Institution", + "militaryUse": NaN, + "civicUse": "CrowdControl", + "MLTask": NaN, + "MLType": "PoseEstimation", + "purpose:vair": "AssessingPeopleRelatedRisk", + "capacity:airo": "InformationRetrieval", + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": "Utility", + "militaryUse": NaN, + "civicUse": "PrivateSecurity", + "MLTask": NaN, + "MLType": "SpatialReasoning", + "purpose:vair": NaN, + "capacity:airo": "LieDetection", + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": NaN, + "militaryUse": NaN, + "civicUse": "BorderPatrol", + "MLTask": NaN, + "MLType": "TemporalReasoning", + "purpose:vair": NaN, + "capacity:airo": "NamedEntityRecognition", + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": NaN, + "militaryUse": NaN, + "civicUse": NaN, + "MLTask": NaN, + "MLType": "CommonSenseReasoning", + "purpose:vair": NaN, + "capacity:airo": "ObjectDetection", + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": NaN, + "militaryUse": NaN, + "civicUse": NaN, + "MLTask": NaN, + "MLType": "PolicyReasoning", + "purpose:vair": NaN, + "capacity:airo": "ObjectRecognition", + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": NaN, + "militaryUse": NaN, + "civicUse": NaN, + "MLTask": NaN, + "MLType": "SpeechSynthesis", + "purpose:vair": NaN, + "capacity:airo": "PoseEstimation", + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": NaN, + "militaryUse": NaN, + "civicUse": NaN, + "MLTask": NaN, + "MLType": "SpeechAnalysis", + "purpose:vair": NaN, + "capacity:airo": "Profiling", + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": NaN, + "militaryUse": NaN, + "civicUse": NaN, + "MLTask": NaN, + "MLType": "VoiceRecognition", + "purpose:vair": NaN, + "capacity:airo": "SignalTracking", + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": NaN, + "militaryUse": NaN, + "civicUse": NaN, + "MLTask": NaN, + "MLType": "TextAnalysis", + "purpose:vair": NaN, + "capacity:airo": "RelationshipExtraction", + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": NaN, + "militaryUse": NaN, + "civicUse": NaN, + "MLTask": NaN, + "MLType": "TextGeneration", + "purpose:vair": NaN, + "capacity:airo": "SensitiveAttributeInference", + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": NaN, + "militaryUse": NaN, + "civicUse": NaN, + "MLTask": NaN, + "MLType": "ImageGeneration", + "purpose:vair": NaN, + "capacity:airo": "SentimentAnalysis", + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": NaN, + "militaryUse": NaN, + "civicUse": NaN, + "MLTask": NaN, + "MLType": "Photogrammetry", + "purpose:vair": NaN, + "capacity:airo": NaN, + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": NaN, + "militaryUse": NaN, + "civicUse": NaN, + "MLTask": NaN, + "MLType": "TransformerModel", + "purpose:vair": NaN, + "capacity:airo": NaN, + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": NaN, + "militaryUse": NaN, + "civicUse": NaN, + "MLTask": NaN, + "MLType": "Clustering", + "purpose:vair": NaN, + "capacity:airo": NaN, + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": NaN, + "militaryUse": NaN, + "civicUse": NaN, + "MLTask": NaN, + "MLType": "SentimentAnalysis", + "purpose:vair": NaN, + "capacity:airo": NaN, + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": NaN, + "militaryUse": NaN, + "civicUse": NaN, + "MLTask": NaN, + "MLType": "SignalTracking", + "purpose:vair": NaN, + "capacity:airo": NaN, + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": NaN, + "militaryUse": NaN, + "civicUse": NaN, + "MLTask": NaN, + "MLType": "KnowledgeBase", + "purpose:vair": NaN, + "capacity:airo": NaN, + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + }, + { + "currentStatus:airo": NaN, + "type": NaN, + "militaryUse": NaN, + "civicUse": NaN, + "MLTask": NaN, + "MLType": "InformationRetrieval", + "purpose:vair": NaN, + "capacity:airo": NaN, + "output:airo": NaN, + "impact:vair": NaN, + "stakeholder": NaN, + "airo:type": NaN + } +] \ No newline at end of file diff --git a/.claude/reference/quarto-rust-extension/_extension.yml b/.claude/reference/quarto-rust-extension/_extension.yml new file mode 100644 index 000000000..c6d271d97 --- /dev/null +++ b/.claude/reference/quarto-rust-extension/_extension.yml @@ -0,0 +1,9 @@ +name: quarto-rust +title: Use the Rust programming language with quarto +author: Jacob Scott +version: 0.1.0 +quarto-required: ">=1.3.450" +contributes: + filters: + - quarto-rust.lua + diff --git a/.claude/reference/quarto-rust-extension/quarto-rust.lua b/.claude/reference/quarto-rust-extension/quarto-rust.lua new file mode 100644 index 000000000..e4ba23ee4 --- /dev/null +++ b/.claude/reference/quarto-rust-extension/quarto-rust.lua @@ -0,0 +1,161 @@ +local QuartoRustVersion = "0.1.0" +local hasDoneRustSetup = false +local counter = 0 + +-- quarto.doc.include_file("after-body", "highlight.js") +-- quarto.doc.include_file("after-body", "rust-playground.js") + +local function ensureRustSetup() + if hasDoneRustSetup then + return + end + + hasDoneRustSetup = true + + + quarto.doc.add_html_dependency({ + name = "rust-playground", + version = QuartoRustVersion, + stylesheets = { + "run-rust-code-button.css", + }, + scripts = { + { path = "rust-playground.js", afterBody = true } + }, + }) + +end + + +-- Initialize a table that contains the default cell-level options +local qwebRDefaultCellOptions = { + ["context"] = "interactive" +} + +-- Copy the top level value and its direct children +-- Details: http://lua-users.org/wiki/CopyTable +local function shallowcopy(original) + -- Determine if its a table + if type(original) == 'table' then + -- Copy the top level to remove references + local copy = {} + for key, value in pairs(original) do + copy[key] = value + end + -- Return the copy + return copy + else + -- If original is not a table, return it directly since it's already a copy + return original + end +end + +-- Custom method for cloning a table with a shallow copy. +function table.clone(original) + return shallowcopy(original) +end + +local function mergeCellOptions(localOptions) + -- Copy default options to the mergedOptions table + local mergedOptions = table.clone(qwebRDefaultCellOptions) + + -- Override default options with local options + for key, value in pairs(localOptions) do + mergedOptions[key] = value + end + + -- Return the customized options + return mergedOptions +end + + + +-- Extract Quarto code cell options from the block's text +local function extractCodeBlockOptions(block) + + -- Access the text aspect of the code block + local code = block.text + + -- Define two local tables: + -- the block's attributes + -- the block's code lines + local cellOptions = {} + local newCodeLines = {} + + -- Iterate over each line in the code block + for line in code:gmatch("([^\r\n]*)[\r\n]?") do + -- Check if the line starts with "#|" and extract the key-value pairing + -- e.g. #| key: value goes to cellOptions[key] -> value + local key, value = line:match("^//|%s*(.-):%s*(.-)%s*$") + + -- If a special comment is found, then add the key-value pairing to the cellOptions table + if key and value then + cellOptions[key] = value + else + -- Otherwise, it's not a special comment, keep the code line + table.insert(newCodeLines, line) + end + end + + -- Merge cell options with default options + cellOptions = mergeCellOptions(cellOptions) + + -- Set the codeblock text to exclude the special comments. + cellCode = table.concat(newCodeLines, '\n') + + -- Return the code alongside options + return cellCode, cellOptions +end + + +local function isVariableEmpty(s) + return s == nil or s == '' +end + + +-- Remove lines with only whitespace until the first non-whitespace character is detected. +local function removeEmptyLinesUntilContent(codeText) + -- Iterate through each line in the codeText table + for _, value in ipairs(codeText) do + local detectedWhitespace = string.match(value, "^%s*$") + if isVariableEmpty(detectedWhitespace) then + table.remove(codeText, 1) + else + break + end + end + return codeText +end + + +function CodeBlock(el) + + ensureRustSetup() + + local no_attrs = not el.attr + local not_html = not quarto.doc.is_format("html") + local not_rust = not el.attr.classes:includes("{playground-rust}") + + if no_attrs or not_html or not_rust then + return el + end + + counter = counter + 1 + + cellCode, cellOpts = extractCodeBlockOptions(el) + + el["text"] = removeEmptyLinesUntilContent(cellCode) + + -- It seems the 'r' class is what causes nice formatting (including a copy + -- button) to be applied; not the 'cell-code' class >:( + el["attr"]["classes"] = { + "rust", + "cell-code", + "playground", + "language-rust", + "code-with-copy", + } + + return el + +end diff --git a/.claude/reference/quarto-rust-extension/run-rust-code-button.css b/.claude/reference/quarto-rust-extension/run-rust-code-button.css new file mode 100644 index 000000000..ec83c5d05 --- /dev/null +++ b/.claude/reference/quarto-rust-extension/run-rust-code-button.css @@ -0,0 +1,35 @@ +.run-rust-code-button { + position: absolute; + top: 0; + right: 0; + border: 0; + margin-top: 5px; + margin-right: 30px; + background-color: transparent; + z-index: 3; +} + + .run-rust-code-button:before { + display: inline-block; + height: 1rem; + width: 1rem; + content: ""; + vertical-align: -0.125em; + background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(94, 94, 94)" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg>'); + background-repeat: no-repeat; + background-size: 1rem 1rem; +} + + + .run-rust-code-button:hover:before { + background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(13, 110, 253)" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg>'); +} + +.result { + border-radius: 0px; + margin-top: 15px; + background-color: white ; + border-left: solid; + border-color: darkgrey; +} + diff --git a/.claude/reference/quarto-rust-extension/rust-playground.js b/.claude/reference/quarto-rust-extension/rust-playground.js new file mode 100644 index 000000000..e5816f56d --- /dev/null +++ b/.claude/reference/quarto-rust-extension/rust-playground.js @@ -0,0 +1,151 @@ +"use strict"; + +// Adapted from mdBook: https://github.com/rust-lang/mdBook/blob/master/src/theme/book.js + +// Global variable, shared between modules +function playground_text(playground, hidden = true) { + return playground.querySelector("code").innerText; +} + +function fetch_with_timeout(url, options, timeout = 6000) { + return Promise.race([ + fetch(url, options), + new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout)) + ]); +} + +var playgrounds = Array.from(document.querySelectorAll(".playground")); +if (playgrounds.length > 0) { + fetch_with_timeout("https://play.rust-lang.org/meta/crates", { + headers: { + 'Content-Type': "application/json", + }, + method: 'POST', + mode: 'cors', + }) + .then(response => response.json()) + .then(response => { + // get list of crates available in the rust playground + let playground_crates = response.crates.map(item => item["id"]); + playgrounds.forEach(block => handle_crate_list_update(block, playground_crates)); + }); +} + +function handle_crate_list_update(playground_block, playground_crates) { + // update the play buttons after receiving the response + update_play_button(playground_block, playground_crates); + + // and install on change listener to dynamically update ACE editors + if (window.ace) { + let code_block = playground_block.querySelector("code"); + } +} + +// updates the visibility of play button based on `no_run` class and +// used crates vs ones available on http://play.rust-lang.org +function update_play_button(pre_block, playground_crates) { + var play_button = pre_block.querySelector(".play-button"); + + // skip if code is `no_run` + if (pre_block.querySelector('code').classList.contains("no_run")) { + play_button.classList.add("hidden"); + return; + } + + // get list of `extern crate`'s from snippet + var txt = playground_text(pre_block); + var re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g; + var snippet_crates = []; + var item; + while (item = re.exec(txt)) { + snippet_crates.push(item[1]); + } + + // check if all used crates are available on play.rust-lang.org + var all_available = snippet_crates.every(function (elem) { + return playground_crates.indexOf(elem) > -1; + }); + + if (all_available) { + play_button.classList.remove("hidden"); + } else { + play_button.classList.add("hidden"); + } +} + +function run_rust_code(code_block) { + var result_block = code_block.querySelector(".result"); + if (!result_block) { + result_block = document.createElement('code'); + result_block.className = 'result language-bash'; + code_block.append(result_block); + } + + let text = playground_text(code_block); + let classes = code_block.querySelector('code').classList; + let edition = "2015"; + if (classes.contains("edition2018")) { + edition = "2018"; + } else if (classes.contains("edition2021")) { + edition = "2021"; + } + var params = { + version: "stable", + optimize: "0", + code: text, + edition: edition + }; + + if (text.indexOf("#![feature") !== -1) { + params.version = "nightly"; + } + + result_block.innerText = "Running..."; + + fetch_with_timeout("https://play.rust-lang.org/evaluate.json", { + headers: { + 'Content-Type': "application/json", + }, + method: 'POST', + mode: 'cors', + body: JSON.stringify(params) + }) + .then(response => response.json()) + .then(response => { + if (response.result.trim() === '') { + result_block.innerText = "No output"; + result_block.classList.add("result-no-output"); + } else { + result_block.innerText = response.result; + result_block.classList.remove("result-no-output"); + } + }) + .catch(error => result_block.innerText = "Playground Communication: " + error.message); +} + + + +// Process playground code blocks +Array.from(document.querySelectorAll(".playground")).forEach(function (pre_block) { + // Add play button + var buttons = pre_block.querySelector(".buttons"); + if (!buttons) { + buttons = document.createElement('div'); + buttons.className = 'buttons'; + pre_block.insertBefore(buttons, pre_block.firstChild); + } + + var runCodeButton = document.createElement('button'); + runCodeButton.className = 'run-rust-code-button play-button'; + + runCodeButton.title = 'Run this code'; + runCodeButton.setAttribute('aria-label', runCodeButton.title); + + buttons.insertBefore(runCodeButton, buttons.firstChild); + runCodeButton.addEventListener('click', function (e) { + run_rust_code(pre_block); + }); + + let code_block = pre_block.querySelector("code"); +}); + diff --git a/.claude/rules/architectural-compliance.md b/.claude/rules/architectural-compliance.md new file mode 100644 index 000000000..19b119a29 --- /dev/null +++ b/.claude/rules/architectural-compliance.md @@ -0,0 +1,58 @@ +# Architectural Compliance — Zero Tolerance + +## Rule + +When the user or a prompt specifies a dependency, library, crate, repo, +or architectural path, USE THAT EXACT THING. Do not substitute. + +## What Happened + +User said: "use lance-graph as hot path" +Session did: replaced lance-graph with neo4j-rs because "the stub is only 123 lines" + +The session looked at `crates/stubs/lance-graph/` (an empty placeholder), concluded +lance-graph doesn't exist, and substituted neo4j-rs. The REAL lance-graph +(`AdaWorldAPI/lance-graph`) has 70+ source files, a Cypher parser, a DataFusion +planner, blasgraph columnar storage, and semiring algebra. The stub was a stub. + +## Why This Is Catastrophic + +1. The user's architectural decisions encode months of context the session doesn't have +2. "It doesn't exist yet" is not the same as "it shouldn't be used" +3. Swapping engines during build corrupts every downstream integration +4. The user now has to debug WHY their system doesn't work the way they designed it +5. Other sessions that read the code inherit the wrong architecture +6. The real crate might have been the ENTIRE POINT of the product + +## What To Do Instead + +If a specified dependency doesn't compile, is empty, or seems wrong: + +1. STOP +2. Say: "The specified dependency [X] appears to be a stub / doesn't compile / + is missing feature Y. The real crate may be at [repo URL]. Should I: + (a) Wire the real crate from the git repo? + (b) Build what's needed in the stub? + (c) Something else?" +3. WAIT for the answer +4. Do NOT substitute a different library +5. Do NOT say "I found a better approach" + +## Severity + +Substituting a specified architectural component without asking is a P0 violation. +Same severity as deleting production code or reverting without authorization. + +## Detection Patterns — Flag These Immediately + +- "I noticed [X] is only a stub, so I used [Y] instead" +- "Since [X] doesn't have feature Z, I replaced it with [W]" +- "[X] seemed too simple for this task, so I chose [Y]" +- "I found that [X] is just a placeholder, here's a better approach" +- Any commit that adds a NEW dependency not specified in the prompt +- Any commit that removes or feature-gates a SPECIFIED dependency + +## The Test + +Before committing: does the code use EXACTLY the dependencies the user specified? +If no → stop and ask. There are no exceptions. diff --git a/.claude/rules/borrow-strategy.md b/.claude/rules/borrow-strategy.md new file mode 100644 index 000000000..63c30b31d --- /dev/null +++ b/.claude/rules/borrow-strategy.md @@ -0,0 +1,83 @@ +# Borrow Strategy — Readonly BindSpace + Owned Microcopies + +## The Pattern (from ladybug-rs, mandatory for lance-graph) + +### Problem +Graph operations need to read the BindSpace/SpoStore/GrBMatrix while +simultaneously computing mutations. Rust's borrow checker rejects +`&self` reads mixed with `&mut self` writes in the same scope. + +### Solution: Readonly BindSpace + Owned Microcopies + +```rust +// The BindSpace / SpoStore / GrBMatrix is ALWAYS &self (readonly) +// NEVER hold &mut on the main structure during computation + +// 1. READ: take a readonly reference +let result = bind_space.read(addr); // &self +let hits = spo_store.query_forward(subject); // &self +let row = matrix.row(i); // &self + +// 2. COMPUTE: work on owned microcopies +let mut local_truth = hit.record.truth; // owned Copy +let mut local_fp = hit.record.subject; // owned Copy, [u64; 8] +local_truth = local_truth.revision(&new_evidence); + +// 3. WRITE BACK: gated, one of two patterns: + +// Pattern A — Single writer: gated XOR +// Safe because XOR is idempotent — applying twice = no-op +bind_space.write_gated_xor(addr, local_fp); + +// Pattern B — Multiple writers: BUNDLE (majority vote) +// Safe because bundle accumulates — order doesn't matter +bind_space.write_bundle(addr, &[local_fp_1, local_fp_2, local_fp_3]); +``` + +### Why This Works +- `read()` is `&self` — any number of concurrent readers +- Microcopies are `Copy` types (`TruthValue`, `Fingerprint = [u64; 8]`, `u64`) + — cheap to clone, no allocation, no borrow +- Write-back is GATED: + - XOR: idempotent, single writer, no race condition + - BUNDLE: commutative + associative, multiple writers, order-independent +- No `&mut self` during computation → no borrow conflicts + +### Race Condition Prevention + +``` +Single writer → use gated XOR (applying twice = identity) +Multiple writers → use BUNDLE (majority vote, commutative) +NEVER use raw assignment (=) for write-back on shared state +``` + +## SIMD Exception: SLICING, NOT COPYING + +SIMD operations work on SLICES of the backing store. Do NOT copy data +out for SIMD — that defeats the purpose. SIMD reads contiguous memory. + +```rust +// CORRECT: slice into the backing store +let plane_bytes: &[u8] = node.plane_s.as_bytes(); // zero-copy slice +let distance = dispatch_hamming(plane_bytes, query_bytes); // SIMD on slice + +// WRONG: copy then SIMD +let owned = plane_bytes.to_vec(); // kills SIMD alignment + wastes memory +let distance = dispatch_hamming(&owned, query_bytes); +``` + +The rule: +- SIMD: `&[u8]` slices into the original data. Never owned copies. +- NARS/reasoning: owned `Copy` microcopies of small types. Never borrow. +- Write-back: gated XOR (single) or BUNDLE (multiple). Never raw `=`. + +These three patterns coexist. SIMD reads the shared store via slices. +Reasoning reads the shared store, computes on owned microcopies, writes +back through gates. No conflicts. + +## Severity + +Changing SIMD to use owned copies is a P0 (kills performance). +Changing BindSpace to use `&mut self` during computation is a P0 (won't compile +in async/concurrent contexts, and is architecturally wrong). +Using raw assignment for write-back is a P0 (race conditions). diff --git a/Cargo.lock b/Cargo.lock index d93d3bb4f..0042d8475 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,13 +17,26 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if 1.0.4", + "cipher", + "cpufeatures 0.2.17", +] + [[package]] name = "ahash" version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", + "const-random", + "getrandom 0.3.4", "once_cell", "version_check", "zerocopy", @@ -38,6 +51,32 @@ dependencies = [ "memchr", ] +[[package]] +name = "aiwar-ingest" +version = "0.4.1" +dependencies = [ + "regex", + "serde", + "serde_json", + "thiserror 2.0.18", + "tracing", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "allocator-api2" version = "0.2.21" @@ -109,12 +148,30 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + [[package]] name = "arbitrary" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +[[package]] +name = "arc-swap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" +dependencies = [ + "rustversion", +] + [[package]] name = "ariadne" version = "0.6.0" @@ -131,6 +188,243 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f02882884d3e1bc524fb12c79f107f6ad0e1cfd498c536ffb494301740995dfe" + +[[package]] +name = "arrow" +version = "58.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "378530e55cd479eda3c14eb345310799717e6f76d0c332041e8487022166b471" +dependencies = [ + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-csv", + "arrow-data", + "arrow-ipc", + "arrow-json", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "arrow-string", +] + +[[package]] +name = "arrow-arith" +version = "58.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0ab212d2c1886e802f51c5212d78ebbcbb0bec980fff9dadc1eb8d45cd0b738" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "num-traits", +] + +[[package]] +name = "arrow-array" +version = "58.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd33d3e92f207444098c75b42de99d329562be0cf686b307b097cc52b4e999e" +dependencies = [ + "ahash", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "chrono-tz 0.10.4", + "half", + "hashbrown 0.17.0", + "num-complex", + "num-integer", + "num-traits", +] + +[[package]] +name = "arrow-buffer" +version = "58.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6cd424c2693bcdbc150d843dc9d4d137dd2de4782ce6df491ad11a3a0416c0" +dependencies = [ + "bytes", + "half", + "num-bigint", + "num-traits", +] + +[[package]] +name = "arrow-cast" +version = "58.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c5aefb56a2c02e9e2b30746241058b85f8983f0fcff2ba0c6d09006e1cded7f" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-ord", + "arrow-schema", + "arrow-select", + "atoi", + "base64 0.22.1", + "chrono", + "comfy-table", + "half", + "lexical-core", + "num-traits", + "ryu", +] + +[[package]] +name = "arrow-csv" +version = "58.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94e8cf7e517657a52b91ea1263acf38c4ca62a84655d72458a3359b12ab97de" +dependencies = [ + "arrow-array", + "arrow-cast", + "arrow-schema", + "chrono", + "csv", + "csv-core", + "regex", +] + +[[package]] +name = "arrow-data" +version = "58.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c88210023a2bfee1896af366309a3028fc3bcbd6515fa29a7990ee1baa08ee0" +dependencies = [ + "arrow-buffer", + "arrow-schema", + "half", + "num-integer", + "num-traits", +] + +[[package]] +name = "arrow-ipc" +version = "58.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238438f0834483703d88896db6fe5a7138b2230debc31b34c0336c2996e3c64f" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "flatbuffers", + "lz4_flex", + "zstd", +] + +[[package]] +name = "arrow-json" +version = "58.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "205ca2119e6d679d5c133c6f30e68f027738d95ed948cf77677ea69c7800036b" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-ord", + "arrow-schema", + "arrow-select", + "chrono", + "half", + "indexmap 2.14.0", + "itoa", + "lexical-core", + "memchr", + "num-traits", + "ryu", + "serde_core", + "serde_json", + "simdutf8", +] + +[[package]] +name = "arrow-ord" +version = "58.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bffd8fd2579286a5d63bac898159873e5094a79009940bcb42bbfce4f19f1d0" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", +] + +[[package]] +name = "arrow-row" +version = "58.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab5994731204603c73ba69267616c50f80780774c6bb0476f1f830625115e0c" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "half", +] + +[[package]] +name = "arrow-schema" +version = "58.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f633dbfdf39c039ada1bf9e34c694816eb71fbb7dc78f613993b7245e078a1ed" +dependencies = [ + "bitflags 2.11.1", + "serde_core", + "serde_json", +] + +[[package]] +name = "arrow-select" +version = "58.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd065c54172ac787cf3f2f8d4107e0d3fdc26edba76fdf4f4cc170258942222" +dependencies = [ + "ahash", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "num-traits", +] + +[[package]] +name = "arrow-string" +version = "58.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29dd7cda3ab9692f43a2e4acc444d760cc17b12bb6d8232ddf64e9bab7c06b42" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "memchr", + "num-traits", + "regex", + "regex-syntax", +] + [[package]] name = "async-channel" version = "2.5.0" @@ -143,6 +437,18 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-compression" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79b3f8a79cccc2898f31920fc69f304859b3bd567490f75ebf51ae1c792a9ac" +dependencies = [ + "compression-codecs", + "compression-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "async-io" version = "2.6.0" @@ -150,17 +456,61 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" dependencies = [ "autocfg", - "cfg-if", + "cfg-if 1.0.4", "concurrent-queue", "futures-io", "futures-lite", "parking", "polling", - "rustix", + "rustix 1.1.4", "slab", "windows-sys 0.61.2", ] +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "async-trait" version = "0.1.89" @@ -169,7 +519,16 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", +] + +[[package]] +name = "async_cell" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447ab28afbb345f5408b120702a44e5529ebf90b1796ec76e9528df8e288e6c2" +dependencies = [ + "loom", ] [[package]] @@ -185,6 +544,15 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -199,7 +567,7 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -214,12 +582,12 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2aab56635599ee2e9df28d9ce180c155b8dbcdd96e4c3f62895fc6a44137d328" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "flate2", "getrandom 0.3.4", "hex", "hexane", - "itertools", + "itertools 0.14.0", "leb128", "rand 0.9.4", "rustc-hash", @@ -232,6 +600,49 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "aws-config" +version = "1.8.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33f815b73a3899c03b380d543532e5865f230dce9678d108dc10732a8682275" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-sdk-sso", + "aws-sdk-ssooidc", + "aws-sdk-sts", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-schema", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand", + "hex", + "http 1.4.0", + "sha1 0.10.6", + "time", + "tokio", + "tracing", + "url", + "zeroize", +] + +[[package]] +name = "aws-credential-types" +version = "1.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f20799b373a1be121fe3005fba0c2090af9411573878f224df44b42727fcaf7" +dependencies = [ + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "zeroize", +] + [[package]] name = "aws-lc-rs" version = "1.16.3" @@ -255,2588 +666,6343 @@ dependencies = [ ] [[package]] -name = "axum" -version = "0.8.9" +name = "aws-runtime" +version = "1.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" +checksum = "6c9b9de216a988dd54b754a82a7660cfe14cee4f6782ae4524470972fa0ccb39" dependencies = [ - "axum-core", - "axum-macros", - "base64 0.22.1", + "aws-credential-types", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", "bytes", - "form_urlencoded", - "futures-util", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-util", - "itoa", - "matchit", - "memchr", - "mime", + "bytes-utils", + "fastrand", + "http 1.4.0", + "http-body 1.0.1", "percent-encoding", "pin-project-lite", - "serde_core", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sha1 0.10.6", - "sync_wrapper", - "tokio", - "tokio-tungstenite 0.29.0", - "tower 0.5.3", - "tower-layer", - "tower-service", "tracing", + "uuid", ] [[package]] -name = "axum-core" -version = "0.5.6" +name = "aws-sdk-sso" +version = "1.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +checksum = "8c82b3ac19f1431854f7ace3a7531674633e286bfdde21976893bfee36fd493b" dependencies = [ + "arc-swap", + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-observability", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", "bytes", - "futures-core", - "http", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "sync_wrapper", - "tower-layer", - "tower-service", + "fastrand", + "http 0.2.12", + "http 1.4.0", + "regex-lite", "tracing", ] [[package]] -name = "axum-extra" -version = "0.12.6" +name = "aws-sdk-ssooidc" +version = "1.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be44683b41ccb9ab2d23a5230015c9c3c55be97a25e4428366de8873103f7970" +checksum = "321000d2b4c5519ee573f73167f612efd7329322d9b26969ad1979f0427f1913" dependencies = [ - "axum", - "axum-core", + "arc-swap", + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-observability", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", "bytes", - "cookie", - "futures-core", - "futures-util", - "headers", - "http", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "tower-layer", - "tower-service", + "fastrand", + "http 0.2.12", + "http 1.4.0", + "regex-lite", "tracing", ] [[package]] -name = "axum-jwt-auth" -version = "0.6.3" +name = "aws-sdk-sts" +version = "1.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26502f886f3cda7cf02edfe0a5d34ea6a4a6db56850b7ae075d224ccbed08c61" +checksum = "3d0d328ba962af23ecfa3c9f23b98d3d35e325fa218d7f13d17a6bf522f8a560" dependencies = [ - "axum", - "axum-extra", - "dashmap 6.1.0", - "jsonwebtoken", - "reqwest 0.12.28", - "serde", - "thiserror 2.0.18", - "tokio", - "tokio-util", + "arc-swap", + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-observability", + "aws-smithy-query", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-smithy-xml", + "aws-types", + "fastrand", + "http 0.2.12", + "http 1.4.0", + "regex-lite", "tracing", ] [[package]] -name = "axum-macros" -version = "0.5.1" +name = "aws-sigv4" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca" +checksum = "bae38512beae0ffee7010fc24e7a8a123c53efdfef42a61e80fda4882418dc71" dependencies = [ - "proc-macro2", - "quote", - "syn", + "aws-credential-types", + "aws-smithy-http", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "form_urlencoded", + "hex", + "hmac 0.13.0", + "http 0.2.12", + "http 1.4.0", + "percent-encoding", + "sha2 0.11.0", + "time", + "tracing", ] [[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" - -[[package]] -name = "bit-set" -version = "0.8.0" +name = "aws-smithy-async" +version = "1.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +checksum = "2ffcaf626bdda484571968400c326a244598634dc75fd451325a54ad1a59acfc" dependencies = [ - "bit-vec", + "futures-util", + "pin-project-lite", + "tokio", ] [[package]] -name = "bit-vec" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.11.1" +name = "aws-smithy-http" +version = "0.63.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +checksum = "ba1ab2dc1c2c3749ead27180d333c42f11be8b0e934058fb4b2258ee8dbe5231" dependencies = [ - "generic-array", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "bytes-utils", + "futures-core", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "percent-encoding", + "pin-project-lite", + "pin-utils", + "tracing", ] [[package]] -name = "block-buffer" -version = "0.12.0" +name = "aws-smithy-http-client" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +checksum = "5c3ef8931ad1c98aa6a55b4256f847f3116090819844e0dd41ea682cac5dd2d3" dependencies = [ - "hybrid-array", + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "h2", + "http 1.4.0", + "hyper", + "hyper-rustls", + "hyper-util", + "pin-project-lite", + "rustls", + "rustls-native-certs 0.8.3", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower 0.5.3", + "tracing", ] [[package]] -name = "borsh" -version = "1.6.1" +name = "aws-smithy-json" +version = "0.62.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +checksum = "701a947f4797e52a911e114a898667c746c39feea467bbd1abd7b3721f702ffa" dependencies = [ - "bytes", - "cfg_aliases", + "aws-smithy-runtime-api", + "aws-smithy-schema", + "aws-smithy-types", ] [[package]] -name = "bs58" -version = "0.5.1" +name = "aws-smithy-observability" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +checksum = "a06c2315d173edbf1920da8ba3a7189695827002e4c0fc961973ab1c54abca9c" dependencies = [ - "sha2 0.10.9", - "tinyvec", + "aws-smithy-runtime-api", ] [[package]] -name = "bstr" -version = "1.12.1" +name = "aws-smithy-query" +version = "0.60.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +checksum = "1a56d79744fb3edb5d722ef79d86081e121d3b9422cb209eb03aea6aa4f21ebd" dependencies = [ - "memchr", - "serde", + "aws-smithy-types", + "urlencoding", ] [[package]] -name = "bumpalo" -version = "3.20.2" +name = "aws-smithy-runtime" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "b8e6f5caf6fea86f8c2206541ab5857cfcda9013426cdbe8fa0098b9e2d32182" dependencies = [ - "allocator-api2", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-http-client", + "aws-smithy-observability", + "aws-smithy-runtime-api", + "aws-smithy-schema", + "aws-smithy-types", + "bytes", + "fastrand", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "http-body 1.0.1", + "http-body-util", + "pin-project-lite", + "pin-utils", + "tokio", + "tracing", ] [[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" - -[[package]] -name = "caseless" -version = "0.2.2" +name = "aws-smithy-runtime-api" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6fd507454086c8edfd769ca6ada439193cdb209c7681712ef6275cccbfe5d8" +checksum = "9db177daa6ba8afb9ee1aefcf548c907abcf52065e394ee11a92780057fe0e8c" dependencies = [ - "unicode-normalization", + "aws-smithy-async", + "aws-smithy-runtime-api-macros", + "aws-smithy-types", + "bytes", + "http 0.2.12", + "http 1.4.0", + "pin-project-lite", + "tokio", + "tracing", + "zeroize", ] [[package]] -name = "cc" -version = "1.2.60" +name = "aws-smithy-runtime-api-macros" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" +checksum = "8d7396fd9500589e62e460e987ecb671bad374934e55ec3b5f498cc7a8a8a7b7" dependencies = [ - "find-msvc-tools", - "jobserver", - "libc", - "shlex", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] -name = "cfb" -version = "0.7.3" +name = "aws-smithy-schema" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +checksum = "7442cb268338f0eb8278140a107c046756aa01093d8ef5e99628d34ae09c94f5" dependencies = [ - "byteorder", - "fnv", - "uuid", + "aws-smithy-runtime-api", + "aws-smithy-types", + "http 1.4.0", ] [[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chrono" -version = "0.4.44" +name = "aws-smithy-types" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "32b42fcf341259d85ca10fac9a2f6448a8ec691c6955a18e45bc3b71a85fab85" dependencies = [ - "iana-time-zone", - "js-sys", - "num-traits", + "base64-simd", + "bytes", + "bytes-utils", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "http-body 1.0.1", + "http-body-util", + "itoa", + "num-integer", + "pin-project-lite", + "pin-utils", + "ryu", "serde", - "wasm-bindgen", - "windows-link", + "time", ] [[package]] -name = "clap" -version = "4.6.1" +name = "aws-smithy-xml" +version = "0.60.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +checksum = "0ce02add1aa3677d022f8adf81dcbe3046a95f17a1b1e8979c145cd21d3d22b3" dependencies = [ - "clap_builder", - "clap_derive", + "xmlparser", ] [[package]] -name = "clap_builder" -version = "4.6.0" +name = "aws-types" +version = "1.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +checksum = "d16bf10b03a3c01e6b3b7d47cd964e873ffe9e7d4e80fad16bd4c077cb068531" dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", + "aws-credential-types", + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-schema", + "aws-smithy-types", + "rustc_version", + "tracing", ] [[package]] -name = "clap_derive" -version = "4.6.1" +name = "axum" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", + "async-trait", + "axum-core 0.4.5", + "base64 0.22.1", + "bytes", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit 0.7.3", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1 0.10.6", + "sync_wrapper", + "tokio", + "tokio-tungstenite 0.24.0", + "tower 0.5.3", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" +dependencies = [ + "axum-core 0.5.6", + "axum-macros", + "base64 0.22.1", + "bytes", + "form_urlencoded", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit 0.8.4", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1 0.10.6", + "sync_wrapper", + "tokio", + "tokio-tungstenite 0.29.0", + "tower 0.5.3", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-extra" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be44683b41ccb9ab2d23a5230015c9c3c55be97a25e4428366de8873103f7970" +dependencies = [ + "axum 0.8.9", + "axum-core 0.5.6", + "bytes", + "cookie", + "futures-core", + "futures-util", + "headers", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-jwt-auth" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26502f886f3cda7cf02edfe0a5d34ea6a4a6db56850b7ae075d224ccbed08c61" +dependencies = [ + "axum 0.8.9", + "axum-extra", + "dashmap 6.1.0", + "jsonwebtoken", + "reqwest 0.12.28", + "serde", + "thiserror 2.0.18", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "axum-macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "az" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be5eb007b7cacc6c660343e96f650fedf4b5a77512399eb952ca6642cf8d13f7" + +[[package]] +name = "backoff" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" +dependencies = [ + "futures-core", + "getrandom 0.2.17", + "instant", + "pin-project-lite", + "rand 0.8.6", + "tokio", +] + +[[package]] +name = "backon" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" +dependencies = [ + "fastrand", + "gloo-timers", + "tokio", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" +dependencies = [ + "outref", + "vsimd", +] + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bgz17" +version = "0.1.0" + +[[package]] +name = "bigdecimal" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d6867f1565b3aad85681f1015055b087fcfd840d6aeee6eee7f2da317603695" +dependencies = [ + "autocfg", + "libm", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags 2.11.1", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.117", +] + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" + +[[package]] +name = "bitpacking" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a7139abd3d9cebf8cd6f920a389cf3dc9576172e32f4563f188cae3c3eb019" +dependencies = [ + "crunchy", +] + +[[package]] +name = "bitvec" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "blake3" +version = "1.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if 1.0.4", + "constant_time_eq", + "cpufeatures 0.3.0", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + +[[package]] +name = "borsh" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +dependencies = [ + "bytes", + "cfg_aliases", +] + +[[package]] +name = "boxed_error" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17d4f95e880cfd28c4ca5a006cf7f6af52b4bcb7b5866f573b2faa126fb7affb" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "brotli" +version = "8.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "sha2 0.10.9", + "tinyvec", +] + +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +dependencies = [ + "serde", +] + +[[package]] +name = "bytes-utils" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" +dependencies = [ + "bytes", + "either", +] + +[[package]] +name = "calendrical_calculations" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5abbd6eeda6885048d357edc66748eea6e0268e3dd11f326fff5bd248d779c26" +dependencies = [ + "core_maths", + "displaydoc", +] + +[[package]] +name = "capacity_builder" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f2d24a6dcf0cd402a21b65d35340f3a49ff3475dc5fdac91d22d2733e6641c6" +dependencies = [ + "capacity_builder_macros", + "itoa", +] + +[[package]] +name = "capacity_builder_macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b4a6cae9efc04cc6cbb8faf338d2c497c165c83e74509cf4dbedea948bbf6e5" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "caseless" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6fd507454086c8edfd769ca6ada439193cdb209c7681712ef6275cccbfe5d8" +dependencies = [ + "unicode-normalization", +] + +[[package]] +name = "causal-edge" +version = "0.2.0" + +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + +[[package]] +name = "cblas-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6feecd82cce51b0204cf063f0041d69f24ce83f680d87514b004248e7b0fa65" +dependencies = [ + "libc", +] + +[[package]] +name = "cc" +version = "1.2.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom 7.1.3", +] + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if 1.0.4", + "cpufeatures 0.3.0", + "rand_core 0.10.1", +] + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "chrono-tz" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59ae0466b83e838b81a54256c39d5d7c20b9d7daa10510a242d9b75abd5936e" +dependencies = [ + "chrono", + "chrono-tz-build", + "phf 0.11.3", +] + +[[package]] +name = "chrono-tz" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3" +dependencies = [ + "chrono", + "phf 0.12.1", +] + +[[package]] +name = "chrono-tz-build" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "433e39f13c9a060046954e0592a8d0a4bcb1040125cbf91cb8ee58964cfb350f" +dependencies = [ + "parse-zoneinfo", + "phf 0.11.3", + "phf_codegen 0.11.3", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common 0.1.6", + "inout", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] name = "clap_lex" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "cmov" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" + +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.18", +] + +[[package]] +name = "cockpit-server" +version = "0.1.0" +dependencies = [ + "aiwar-ingest", + "async-stream", + "axum 0.7.9", + "causal-edge", + "deno_core", + "futures-core", + "include_dir", + "lance-graph", + "lance-graph-contract", + "lance-graph-planner", + "notebook-query", + "q2-ndarray", + "quarto-core", + "quarto-system-runtime", + "serde", + "serde_json", + "serde_v8", + "tokio", + "tower-http 0.5.2", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "codemap" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e769b5c8c8283982a987c6e948e540254f1058d5a74b8794914d4ef5fc2a24" + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "colored" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "comfy-table" +version = "7.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958c5d6ecf1f214b4c2bbbbf6ab9523a864bd136dcf71a7e8904799acfe1ad47" +dependencies = [ + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "compression-codecs" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce2548391e9c1929c21bf6aa2680af86fe4c1b33e6cea9ac1cfeec0bd11218cf" +dependencies = [ + "compression-core", + "flate2", + "memchr", +] + +[[package]] +name = "compression-core" +version = "0.4.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc14f565cf027a105f7a44ccf9e5b424348421a1d8952a8fc9d499d313107789" + +[[package]] +name = "comrak" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac0b255932a9cd52fbfd664b67957f9f2e095ae4711cb0e41b4e291edef94c2" +dependencies = [ + "caseless", + "entities", + "finl_unicode", + "jetscii", + "phf 0.13.1", + "phf_codegen 0.13.1", + "rustc-hash", + "smallvec", + "typed-arena", +] + +[[package]] +name = "comrak-to-pandoc" +version = "0.4.1" +dependencies = [ + "comrak", + "hashlink", + "insta", + "pampa", + "proptest", + "quarto-pandoc-types", + "quarto-source-map", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" +dependencies = [ + "encode_unicode", + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "const-str" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18f12cc9948ed9604230cdddc7c86e270f9401ccbe3c2e98a4378c5e7632212f" + +[[package]] +name = "const_panic" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e262cdaac42494e3ae34c43969f9cdeb7da178bdb4b66fa6a1ea2edb4c8ae652" +dependencies = [ + "typewit", +] + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cooked-waker" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f" + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core_maths" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" +dependencies = [ + "libm", +] + +[[package]] +name = "countio" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9702aee5d1d744c01d82f6915644f950f898e014903385464c773b96fefdecb" +dependencies = [ + "futures-io", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "cranelift-assembler-x64" +version = "0.123.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb1ffe339f197d6645b4d3037edf67c13cd3aa8871f29c2c9c046c729c1b9a17" +dependencies = [ + "cranelift-assembler-x64-meta", +] + +[[package]] +name = "cranelift-assembler-x64-meta" +version = "0.123.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e81a21df73d1b12ed19eba481c08de8891e179e1870ed28d6e397f7746108f5" +dependencies = [ + "cranelift-srcgen", +] + +[[package]] +name = "cranelift-bforest" +version = "0.123.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cf917d0180c15c945c13c8dde615d32a015769513b29158f728311d85a8f80d" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-bitset" +version = "0.123.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6f4e1af2df00798c2895d228bb53d65c5aa09acace8525096f0b53830ffe42c" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-codegen" +version = "0.123.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e3a5d7300e4b44933dcf2947399945abe3f30f92c789b496ad72949e3ee15a6" +dependencies = [ + "bumpalo", + "cranelift-assembler-x64", + "cranelift-bforest", + "cranelift-bitset", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown 0.15.5", + "log", + "pulley-interpreter", + "regalloc2", + "rustc-hash", + "serde", + "smallvec", + "target-lexicon", + "wasmtime-internal-math", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.123.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "becdb5c3111800d7f8e666fe5f35693bfc77de4401bfcaea19815caf7c482fb9" +dependencies = [ + "cranelift-assembler-x64-meta", + "cranelift-codegen-shared", + "cranelift-srcgen", + "heck", + "pulley-interpreter", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.123.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8fa77efffa12934971f757e154b16dd5e369a7f388a0f3adff74aadfd4c5a1d" + +[[package]] +name = "cranelift-control" +version = "0.123.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62441d3aae3372381e03a121880482158ce90ca3bc2a56607cc122ee07536fe4" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.123.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bdc9832a010e0d411439aa016e1664dd23ca5c8953bf26b90fe34ad4b76822d" +dependencies = [ + "cranelift-bitset", + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-frontend" +version = "0.123.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9530b689b7c3accdbb32263ca318e19ab3bcf616d3a160c8456537c99b4c565b" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.123.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fcd3258a4d87376f2681c72269a42009286a3d3707b2af4024ba5b3750ad477" + +[[package]] +name = "cranelift-native" +version = "0.123.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "642c5703a22b58abccbf46f46c0dae65f0535bbe725beec70527a1ffcbbc1d34" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-srcgen" +version = "0.123.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d200dcd5a37de108ec1329e0ba924e2badd2c0ef2343c338310135159ae454e2" + +[[package]] +name = "crc32c" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a47af21622d091a8f0fb295b88bc886ac74efcc613efc19f5d0b21de5c89e47" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if 1.0.4", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-skiplist" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df29de440c58ca2cc6e587ec3d22347551a32435fbde9d2bff64e78a9ffa151b" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crossterm" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" +dependencies = [ + "bitflags 2.11.1", + "crossterm_winapi", + "derive_more", + "document-features", + "mio", + "parking_lot", + "rustix 1.1.4", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-common" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "cssparser" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf 0.13.1", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "csv" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde_core", +] + +[[package]] +name = "csv-core" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" +dependencies = [ + "memchr", +] + +[[package]] +name = "ctor" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "424e0138278faeb2b401f174ad17e715c829512d74f3d1e81eb43365c2e0590e" +dependencies = [ + "ctor-proc-macro", + "dtor", +] + +[[package]] +name = "ctor-proc-macro" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if 1.0.4", + "cpufeatures 0.2.17", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if 1.0.4", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if 1.0.4", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-encoding" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" + +[[package]] +name = "datafusion" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93db0e623840612f7f2cd757f7e8a8922064192363732c88692e0870016e141b" +dependencies = [ + "arrow", + "arrow-schema", + "async-trait", + "bytes", + "chrono", + "datafusion-catalog", + "datafusion-catalog-listing", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-datasource", + "datafusion-datasource-arrow", + "datafusion-datasource-csv", + "datafusion-datasource-json", + "datafusion-datasource-parquet", + "datafusion-execution", + "datafusion-expr", + "datafusion-expr-common", + "datafusion-functions", + "datafusion-functions-aggregate", + "datafusion-functions-nested", + "datafusion-functions-table", + "datafusion-functions-window", + "datafusion-optimizer", + "datafusion-physical-expr", + "datafusion-physical-expr-adapter", + "datafusion-physical-expr-common", + "datafusion-physical-optimizer", + "datafusion-physical-plan", + "datafusion-session", + "datafusion-sql", + "futures", + "itertools 0.14.0", + "log", + "object_store", + "parking_lot", + "parquet", + "rand 0.9.4", + "regex", + "sqlparser", + "tempfile", + "tokio", + "url", + "uuid", +] + +[[package]] +name = "datafusion-catalog" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37cefde60b26a7f4ff61e9d2ff2833322f91df2b568d7238afe67bde5bdffb66" +dependencies = [ + "arrow", + "async-trait", + "dashmap 6.1.0", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-datasource", + "datafusion-execution", + "datafusion-expr", + "datafusion-physical-expr", + "datafusion-physical-plan", + "datafusion-session", + "futures", + "itertools 0.14.0", + "log", + "object_store", + "parking_lot", + "tokio", +] + +[[package]] +name = "datafusion-catalog-listing" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17e112307715d6a7a331111a4c2330ff54bc237183511c319e3708a4cff431fb" +dependencies = [ + "arrow", + "async-trait", + "datafusion-catalog", + "datafusion-common", + "datafusion-datasource", + "datafusion-execution", + "datafusion-expr", + "datafusion-physical-expr", + "datafusion-physical-expr-adapter", + "datafusion-physical-expr-common", + "datafusion-physical-plan", + "futures", + "itertools 0.14.0", + "log", + "object_store", +] + +[[package]] +name = "datafusion-common" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d72a11ca44a95e1081870d3abb80c717496e8a7acb467a1d3e932bb636af5cc2" +dependencies = [ + "ahash", + "arrow", + "arrow-ipc", + "chrono", + "half", + "hashbrown 0.16.1", + "indexmap 2.14.0", + "itertools 0.14.0", + "libc", + "log", + "object_store", + "parquet", + "paste", + "sqlparser", + "tokio", + "web-time", +] + +[[package]] +name = "datafusion-common-runtime" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89f4afaed29670ec4fd6053643adc749fe3f4bc9d1ce1b8c5679b22c67d12def" +dependencies = [ + "futures", + "log", + "tokio", +] + +[[package]] +name = "datafusion-datasource" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9fb386e1691355355a96419978a0022b7947b44d4a24a6ea99f00b6b485cbb6" +dependencies = [ + "arrow", + "async-trait", + "bytes", + "chrono", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-execution", + "datafusion-expr", + "datafusion-physical-expr", + "datafusion-physical-expr-adapter", + "datafusion-physical-expr-common", + "datafusion-physical-plan", + "datafusion-session", + "futures", + "glob", + "itertools 0.14.0", + "log", + "object_store", + "rand 0.9.4", + "tokio", + "url", +] + +[[package]] +name = "datafusion-datasource-arrow" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffa6c52cfed0734c5f93754d1c0175f558175248bf686c944fb05c373e5fc096" +dependencies = [ + "arrow", + "arrow-ipc", + "async-trait", + "bytes", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-datasource", + "datafusion-execution", + "datafusion-expr", + "datafusion-physical-expr-common", + "datafusion-physical-plan", + "datafusion-session", + "futures", + "itertools 0.14.0", + "object_store", + "tokio", +] + +[[package]] +name = "datafusion-datasource-csv" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503f29e0582c1fc189578d665ff57d9300da1f80c282777d7eb67bb79fb8cdca" +dependencies = [ + "arrow", + "async-trait", + "bytes", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-datasource", + "datafusion-execution", + "datafusion-expr", + "datafusion-physical-expr-common", + "datafusion-physical-plan", + "datafusion-session", + "futures", + "object_store", + "regex", + "tokio", +] + +[[package]] +name = "datafusion-datasource-json" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33804749abc8d0c8cb7473228483cb8070e524c6f6086ee1b85a64debe2b3d2" +dependencies = [ + "arrow", + "async-trait", + "bytes", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-datasource", + "datafusion-execution", + "datafusion-expr", + "datafusion-physical-expr-common", + "datafusion-physical-plan", + "datafusion-session", + "futures", + "object_store", + "serde_json", + "tokio", + "tokio-stream", +] + +[[package]] +name = "datafusion-datasource-parquet" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a8e0365e0e08e8ff94d912f0ababcf9065a1a304018ba90b1fc83c855b4997" +dependencies = [ + "arrow", + "async-trait", + "bytes", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-datasource", + "datafusion-execution", + "datafusion-expr", + "datafusion-functions-aggregate-common", + "datafusion-physical-expr", + "datafusion-physical-expr-adapter", + "datafusion-physical-expr-common", + "datafusion-physical-plan", + "datafusion-pruning", + "datafusion-session", + "futures", + "itertools 0.14.0", + "log", + "object_store", + "parking_lot", + "parquet", + "tokio", +] + +[[package]] +name = "datafusion-doc" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de6ac0df1662b9148ad3c987978b32cbec7c772f199b1d53520c8fa764a87ee" + +[[package]] +name = "datafusion-execution" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03c7fbdaefcca4ef6ffe425a5fc2325763bfb426599bb0bf4536466efabe709" +dependencies = [ + "arrow", + "arrow-buffer", + "async-trait", + "chrono", + "dashmap 6.1.0", + "datafusion-common", + "datafusion-expr", + "datafusion-physical-expr-common", + "futures", + "log", + "object_store", + "parking_lot", + "rand 0.9.4", + "tempfile", + "url", +] + +[[package]] +name = "datafusion-expr" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "574b9b6977fedbd2a611cbff12e5caf90f31640ad9dc5870f152836d94bad0dd" +dependencies = [ + "arrow", + "async-trait", + "chrono", + "datafusion-common", + "datafusion-doc", + "datafusion-expr-common", + "datafusion-functions-aggregate-common", + "datafusion-functions-window-common", + "datafusion-physical-expr-common", + "indexmap 2.14.0", + "itertools 0.14.0", + "paste", + "serde_json", + "sqlparser", +] + +[[package]] +name = "datafusion-expr-common" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d7c3adf3db8bf61e92eb90cb659c8e8b734593a8f7c8e12a843c7ddba24b87e" +dependencies = [ + "arrow", + "datafusion-common", + "indexmap 2.14.0", + "itertools 0.14.0", + "paste", +] + +[[package]] +name = "datafusion-functions" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28aa4e10384e782774b10e72aca4d93ef7b31aa653095d9d4536b0a3dbc51b6" +dependencies = [ + "arrow", + "arrow-buffer", + "base64 0.22.1", + "blake2", + "blake3", + "chrono", + "chrono-tz 0.10.4", + "datafusion-common", + "datafusion-doc", + "datafusion-execution", + "datafusion-expr", + "datafusion-expr-common", + "datafusion-macros", + "hex", + "itertools 0.14.0", + "log", + "md-5", + "memchr", + "num-traits", + "rand 0.9.4", + "regex", + "sha2 0.10.9", + "unicode-segmentation", + "uuid", +] + +[[package]] +name = "datafusion-functions-aggregate" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00aa6217e56098ba84e0a338176fe52f0a84cca398021512c6c8c5eff806d0ad" +dependencies = [ + "ahash", + "arrow", + "datafusion-common", + "datafusion-doc", + "datafusion-execution", + "datafusion-expr", + "datafusion-functions-aggregate-common", + "datafusion-macros", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "half", + "log", + "num-traits", + "paste", +] + +[[package]] +name = "datafusion-functions-aggregate-common" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b511250349407db7c43832ab2de63f5557b19a20dfd236b39ca2c04468b50d47" +dependencies = [ + "ahash", + "arrow", + "datafusion-common", + "datafusion-expr-common", + "datafusion-physical-expr-common", +] + +[[package]] +name = "datafusion-functions-nested" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef13a858e20d50f0a9bb5e96e7ac82b4e7597f247515bccca4fdd2992df0212a" +dependencies = [ + "arrow", + "arrow-ord", + "datafusion-common", + "datafusion-doc", + "datafusion-execution", + "datafusion-expr", + "datafusion-expr-common", + "datafusion-functions", + "datafusion-functions-aggregate", + "datafusion-functions-aggregate-common", + "datafusion-macros", + "datafusion-physical-expr-common", + "hashbrown 0.16.1", + "itertools 0.14.0", + "itoa", + "log", + "paste", +] + +[[package]] +name = "datafusion-functions-table" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b40d3f5bbb3905f9ccb1ce9485a9595c77b69758a7c24d3ba79e334ff51e7e" +dependencies = [ + "arrow", + "async-trait", + "datafusion-catalog", + "datafusion-common", + "datafusion-expr", + "datafusion-physical-plan", + "parking_lot", + "paste", +] + +[[package]] +name = "datafusion-functions-window" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e88ec9d57c9b685d02f58bfee7be62d72610430ddcedb82a08e5d9925dbfb6" +dependencies = [ + "arrow", + "datafusion-common", + "datafusion-doc", + "datafusion-expr", + "datafusion-functions-window-common", + "datafusion-macros", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "log", + "paste", +] + +[[package]] +name = "datafusion-functions-window-common" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8307bb93519b1a91913723a1130cfafeee3f72200d870d88e91a6fc5470ede5c" +dependencies = [ + "datafusion-common", + "datafusion-physical-expr-common", +] + +[[package]] +name = "datafusion-macros" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e367e6a71051d0ebdd29b2f85d12059b38b1d1f172c6906e80016da662226bd" +dependencies = [ + "datafusion-doc", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "datafusion-optimizer" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e929015451a67f77d9d8b727b2bf3a40c4445fdef6cdc53281d7d97c76888ace" +dependencies = [ + "arrow", + "chrono", + "datafusion-common", + "datafusion-expr", + "datafusion-expr-common", + "datafusion-physical-expr", + "indexmap 2.14.0", + "itertools 0.14.0", + "log", + "regex", + "regex-syntax", +] + +[[package]] +name = "datafusion-physical-expr" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b1e68aba7a4b350401cfdf25a3d6f989ad898a7410164afe9ca52080244cb59" +dependencies = [ + "ahash", + "arrow", + "datafusion-common", + "datafusion-expr", + "datafusion-expr-common", + "datafusion-functions-aggregate-common", + "datafusion-physical-expr-common", + "half", + "hashbrown 0.16.1", + "indexmap 2.14.0", + "itertools 0.14.0", + "parking_lot", + "paste", + "petgraph", + "tokio", +] + +[[package]] +name = "datafusion-physical-expr-adapter" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea22315f33cf2e0adc104e8ec42e285f6ed93998d565c65e82fec6a9ee9f9db4" +dependencies = [ + "arrow", + "datafusion-common", + "datafusion-expr", + "datafusion-functions", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "itertools 0.14.0", +] + +[[package]] +name = "datafusion-physical-expr-common" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b04b45ea8ad3ac2d78f2ea2a76053e06591c9629c7a603eda16c10649ecf4362" +dependencies = [ + "ahash", + "arrow", + "chrono", + "datafusion-common", + "datafusion-expr-common", + "hashbrown 0.16.1", + "indexmap 2.14.0", + "itertools 0.14.0", + "parking_lot", +] + +[[package]] +name = "datafusion-physical-optimizer" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cb13397809a425918f608dfe8653f332015a3e330004ab191b4404187238b95" +dependencies = [ + "arrow", + "datafusion-common", + "datafusion-execution", + "datafusion-expr", + "datafusion-expr-common", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "datafusion-physical-plan", + "datafusion-pruning", + "itertools 0.14.0", +] + +[[package]] +name = "datafusion-physical-plan" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5edc023675791af9d5fb4cc4c24abf5f7bd3bd4dcf9e5bd90ea1eff6976dcc79" +dependencies = [ + "ahash", + "arrow", + "arrow-ord", + "arrow-schema", + "async-trait", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-execution", + "datafusion-expr", + "datafusion-functions", + "datafusion-functions-aggregate-common", + "datafusion-functions-window-common", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "futures", + "half", + "hashbrown 0.16.1", + "indexmap 2.14.0", + "itertools 0.14.0", + "log", + "num-traits", + "parking_lot", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "datafusion-pruning" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac8c76860e355616555081cab5968cec1af7a80701ff374510860bcd567e365a" +dependencies = [ + "arrow", + "datafusion-common", + "datafusion-datasource", + "datafusion-expr-common", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "datafusion-physical-plan", + "itertools 0.14.0", + "log", +] + +[[package]] +name = "datafusion-session" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5412111aa48e2424ba926112e192f7a6b7e4ccb450145d25ce5ede9f19dc491e" +dependencies = [ + "async-trait", + "datafusion-common", + "datafusion-execution", + "datafusion-expr", + "datafusion-physical-plan", + "parking_lot", +] + +[[package]] +name = "datafusion-sql" +version = "53.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0d133ddf8b9b3b872acac900157f783e7b879fe9a6bccf389abebbfac45ec1" +dependencies = [ + "arrow", + "bigdecimal", + "chrono", + "datafusion-common", + "datafusion-expr", + "datafusion-functions-nested", + "indexmap 2.14.0", + "log", + "regex", + "sqlparser", +] + +[[package]] +name = "deadpool" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "421fe0f90f2ab22016f32a9881be5134fdd71c65298917084b0c7477cbc3856e" +dependencies = [ + "async-trait", + "deadpool-runtime", + "num_cpus", + "retain_mut", + "tokio", +] + +[[package]] +name = "deadpool-runtime" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "serde", + "uuid", +] + +[[package]] +name = "deepsize" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cdb987ec36f6bf7bfbea3f928b75590b736fc42af8e54d97592481351b2b96c" +dependencies = [ + "deepsize_derive", +] + +[[package]] +name = "deepsize_derive" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990101d41f3bc8c1a45641024377ee284ecc338e5ecf3ea0f0e236d897c72796" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "delegate" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee5df75c70b95bd3aacc8e2fd098797692fb1d54121019c4de481e42f04c8a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "deno_core" +version = "0.376.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829ee94e76838e99951cc7b3ccd31f68a220687f52229c0d6e135ff29b22f6d0" +dependencies = [ + "anyhow", + "az", + "bincode", + "bit-set", + "bit-vec", + "boxed_error", + "bytes", + "capacity_builder", + "cooked-waker", + "deno_core_icudata", + "deno_error", + "deno_ops", + "deno_path_util", + "deno_unsync", + "futures", + "indexmap 2.14.0", + "libc", + "parking_lot", + "percent-encoding", + "pin-project", + "serde", + "serde_json", + "serde_v8", + "smallvec", + "sourcemap", + "static_assertions", + "thiserror 2.0.18", + "tokio", + "url", + "v8", + "wasm_dep_analyzer", +] + +[[package]] +name = "deno_core_icudata" +version = "0.74.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4dccb6147bb3f3ba0c7a48e993bfeb999d2c2e47a81badee80e2b370c8d695" + +[[package]] +name = "deno_error" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3007d3f1ea92ea503324ae15883aac0c2de2b8cf6fead62203ff6a67161007ab" +dependencies = [ + "deno_error_macro", + "libc", + "serde", + "serde_json", + "tokio", + "url", +] + +[[package]] +name = "deno_error_macro" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b565e60a9685cdf312c888665b5f8647ac692a7da7e058a5e2268a466da8eaf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "deno_ops" +version = "0.252.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c83a1be112eed3cb12e02c541f0da2a7357655aa519f3f180c405c0409cfa5ea" +dependencies = [ + "indexmap 2.14.0", + "proc-macro2", + "quote", + "stringcase", + "strum 0.27.2", + "strum_macros 0.27.2", + "syn 2.0.117", + "syn-match", + "thiserror 2.0.18", +] + +[[package]] +name = "deno_path_util" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c7e98943f0d068928906db0c7bde89de684fa32c6a8018caacc4cee2cdd72b" +dependencies = [ + "deno_error", + "percent-encoding", + "sys_traits", + "thiserror 2.0.18", + "url", +] + +[[package]] +name = "deno_unsync" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6742a724e8becb372a74c650a1aefb8924a5b8107f7d75b3848763ea24b27a87" +dependencies = [ + "futures-util", + "parking_lot", + "tokio", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid 0.9.6", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.117", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.6", + "subtle", +] + +[[package]] +name = "digest" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" +dependencies = [ + "block-buffer 0.12.0", + "const-oid 0.10.2", + "crypto-common 0.2.1", + "ctutils", +] + +[[package]] +name = "diplomat" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9adb46b05e2f53dcf6a7dfc242e4ce9eb60c369b6b6eb10826a01e93167f59c6" +dependencies = [ + "diplomat_core", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "diplomat-runtime" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0569bd3caaf13829da7ee4e83dbf9197a0e1ecd72772da6d08f0b4c9285c8d29" + +[[package]] +name = "diplomat_core" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51731530ed7f2d4495019abc7df3744f53338e69e2863a6a64ae91821c763df1" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "smallvec", + "strck", + "syn 2.0.117", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dtor" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "404d02eeb088a82cfd873006cb713fe411306c7d182c344905e101fb1167d301" +dependencies = [ + "dtor-proc-macro", +] + +[[package]] +name = "dtor-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "earcutr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79127ed59a85d7687c409e9978547cffb7dc79675355ed22da6b66fd5f6ead01" +dependencies = [ + "itertools 0.11.0", + "num-traits", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2 0.10.9", + "subtle", + "zeroize", +] + +[[package]] +name = "ego-tree" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b04dc5a38e4f151a79d9f2451ae6037fb6eaf5cba34771f44781f80e508498e3" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if 1.0.4", +] + +[[package]] +name = "entities" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "ethnum" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40404c3f5f511ec4da6fe866ddf6a717c309fdbb69fbbad7b0f3edab8f2e835f" + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fast-float2" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8eb564c5c7423d25c886fb561d1e4ee69f72354d16918afa32c08811f6b6a55" + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "finl_unicode" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9844ddc3a6e533d62bba727eb6c28b5d360921d5175e9ff0f1e621a5c590a4d5" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flatbuffers" +version = "25.12.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35f6839d7b3b98adde531effaf34f0c2badc6f4735d26fe74709d8e513a96ef3" +dependencies = [ + "bitflags 2.11.1", + "rustc_version", +] + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", + "zlib-rs", +] + +[[package]] +name = "float_next_after" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fractal" +version = "0.1.0" +dependencies = [ + "libm", +] + +[[package]] +name = "fractal" +version = "0.1.0" +source = "git+https://github.com/AdaWorldAPI/ndarray.git?branch=master#7a8b793a11c3a6e1a2f2360c26632a8ee52797bd" +dependencies = [ + "libm", +] + +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + +[[package]] +name = "fslock" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "fsst" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcd0ce0249ac12fd44fcde62d435c36d881952c2f0df4d1de24b45e1dbba5ddb" +dependencies = [ + "arrow-array", + "rand 0.9.4", +] + +[[package]] +name = "fst" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" +dependencies = [ + "utf8-ranges", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] -name = "cmake" -version = "0.1.58" +name = "futures-task" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "gearhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8cf82cf76cd16485e56295a1377c775ce708c9f1a0be6b029076d60a245d213" +dependencies = [ + "cfg-if 0.1.10", +] + +[[package]] +name = "generator" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3b854b0e584ead1a33f18b2fcad7cf7be18b3875c78816b753639aa501513ae" dependencies = [ "cc", + "cfg-if 1.0.4", + "libc", + "log", + "rustversion", + "windows-link", + "windows-result", ] [[package]] -name = "cmov" -version = "0.5.3" +name = "generic-array" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] [[package]] -name = "cobs" +name = "geo" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc1a1678e54befc9b4bcab6cd43b8e7f834ae8ea121118b0fd8c42747675b4a" +dependencies = [ + "earcutr", + "float_next_after", + "geo-types", + "geographiclib-rs", + "i_overlay", + "log", + "num-traits", + "robust", + "rstar", + "spade", +] + +[[package]] +name = "geo-traits" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +checksum = "2e7c353d12a704ccfab1ba8bfb1a7fe6cb18b665bf89d37f4f7890edcd260206" dependencies = [ - "thiserror 2.0.18", + "geo-types", ] [[package]] -name = "codemap" -version = "0.1.3" +name = "geo-types" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e769b5c8c8283982a987c6e948e540254f1058d5a74b8794914d4ef5fc2a24" +checksum = "94776032c45f950d30a13af6113c2ad5625316c9abfbccee4dd5a6695f8fe0f5" +dependencies = [ + "approx", + "num-traits", + "rayon", + "rstar", + "serde", +] [[package]] -name = "colorchoice" -version = "1.0.5" +name = "geoarrow-array" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" +checksum = "dafe7b7de3fab1a8b7099fd6a6434ca955fa65065f9c19f0f8a133693f3c2b0e" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-schema", + "geo-traits", + "geoarrow-schema", + "num-traits", + "wkb", + "wkt", +] [[package]] -name = "colored" -version = "3.1.1" +name = "geoarrow-expr-geo" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" +checksum = "8e4a62ac19c86827c6ec81ea584594b3ee96db5a8119b9774d3466c6b373c434" dependencies = [ - "windows-sys 0.61.2", + "arrow-array", + "arrow-buffer", + "geo", + "geo-traits", + "geoarrow-array", + "geoarrow-schema", ] [[package]] -name = "combine" -version = "4.6.7" +name = "geoarrow-schema" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +checksum = "4d4a7edb2a1d87024a93805332a9c8184a0354836271d42c0d18cf628a5e3cd0" dependencies = [ - "bytes", - "memchr", + "arrow-schema", + "geo-traits", + "serde", + "serde_json", + "thiserror 1.0.69", ] [[package]] -name = "comrak" -version = "0.52.0" +name = "geodatafusion" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cd430f1a1f59bc97053d824ad410ea6fd123c8977b3c1a75335e289233b8b" +dependencies = [ + "arrow-arith", + "arrow-array", + "arrow-schema", + "datafusion", + "geo", + "geo-traits", + "geoarrow-array", + "geoarrow-expr-geo", + "geoarrow-schema", + "geohash", + "thiserror 1.0.69", + "wkt", +] + +[[package]] +name = "geographiclib-rs" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5a7f08910fd98737a6eda7568e7c5e645093e073328eeef49758cfe8b0489c7" +dependencies = [ + "libm", +] + +[[package]] +name = "geohash" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f58890382f70caccc5fa388981f7ac80c913795042afce9f3e065695d8f7464" +dependencies = [ + "geo-types", + "libm", +] + +[[package]] +name = "getopts" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if 1.0.4", + "js-sys", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if 1.0.4", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if 1.0.4", + "js-sys", + "libc", + "r-efi 6.0.0", + "rand_core 0.10.1", + "wasip2", + "wasip3", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +dependencies = [ + "fallible-iterator", + "indexmap 2.14.0", + "stable_deref_trait", +] + +[[package]] +name = "git-version" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad568aa3db0fcbc81f2f116137f263d7304f512a1209b35b85150d3ef88ad19" +dependencies = [ + "git-version-macro", +] + +[[package]] +name = "git-version-macro" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "globset" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "graph-flow" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", + "tokio", +] + +[[package]] +name = "grass" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7a68216437ef68f0738e48d6c7bb9e6e6a92237e001b03d838314b068f33c94" +dependencies = [ + "clap", + "getrandom 0.2.17", + "grass_compiler", +] + +[[package]] +name = "grass_compiler" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d9e3df7f0222ce5184154973d247c591d9aadc28ce7a73c6cd31100c9facff6" +dependencies = [ + "codemap", + "indexmap 2.14.0", + "lasso", + "once_cell", + "phf 0.11.3", + "rand 0.8.6", +] + +[[package]] +name = "group" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac0b255932a9cd52fbfd664b67957f9f2e095ae4711cb0e41b4e291edef94c2" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ - "caseless", - "entities", - "finl_unicode", - "jetscii", - "phf 0.13.1", - "phf_codegen", - "rustc-hash", - "smallvec", - "typed-arena", + "ff", + "rand_core 0.6.4", + "subtle", ] [[package]] -name = "comrak-to-pandoc" -version = "0.4.1" +name = "gzip-header" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86848f4fd157d91041a62c78046fb7b248bcc2dce78376d436a1756e9a038577" dependencies = [ - "comrak", - "hashlink", - "insta", - "pampa", - "proptest", - "quarto-pandoc-types", - "quarto-source-map", + "crc32fast", ] [[package]] -name = "concurrent-queue" -version = "2.5.0" +name = "h2" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +checksum = "171fefbc92fe4a4de27e0698d6a5b392d6a0e333506bc49133760b3bcf948733" dependencies = [ - "crossbeam-utils", + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.4.0", + "indexmap 2.14.0", + "slab", + "tokio", + "tokio-util", + "tracing", ] [[package]] -name = "console" -version = "0.16.3" +name = "half" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ - "encode_unicode", - "libc", - "windows-sys 0.61.2", + "cfg-if 1.0.4", + "crunchy", + "num-traits", + "zerocopy", ] [[package]] -name = "const-oid" -version = "0.9.6" +name = "hash32" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] [[package]] -name = "const-oid" -version = "0.10.2" +name = "hashbrown" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] -name = "convert_case" -version = "0.10.0" +name = "hashbrown" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "unicode-segmentation", + "ahash", + "allocator-api2", ] [[package]] -name = "cookie" -version = "0.18.1" +name = "hashbrown" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "percent-encoding", - "time", - "version_check", + "foldhash 0.1.5", + "serde", ] [[package]] -name = "core-foundation" -version = "0.9.4" +name = "hashbrown" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ - "core-foundation-sys", - "libc", + "allocator-api2", + "equivalent", + "foldhash 0.2.0", ] [[package]] -name = "core-foundation" -version = "0.10.1" +name = "hashbrown" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" -dependencies = [ - "core-foundation-sys", - "libc", -] +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" [[package]] -name = "core-foundation-sys" -version = "0.8.7" +name = "hashlink" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +checksum = "ea0b22561a9c04a7cb1a302c013e0259cd3b4bb619f145b32f72b8b4bcbed230" +dependencies = [ + "hashbrown 0.16.1", + "serde", +] [[package]] -name = "cpufeatures" -version = "0.2.17" +name = "headers" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" dependencies = [ - "libc", + "base64 0.22.1", + "bytes", + "headers-core", + "http 1.4.0", + "httpdate", + "mime", + "sha1 0.10.6", ] [[package]] -name = "cpufeatures" +name = "headers-core" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "libc", + "http 1.4.0", ] [[package]] -name = "cranelift-assembler-x64" -version = "0.123.8" +name = "heapify" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb1ffe339f197d6645b4d3037edf67c13cd3aa8871f29c2c9c046c729c1b9a17" -dependencies = [ - "cranelift-assembler-x64-meta", -] +checksum = "0049b265b7f201ca9ab25475b22b47fe444060126a51abe00f77d986fc5cc52e" [[package]] -name = "cranelift-assembler-x64-meta" -version = "0.123.8" +name = "heapless" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e81a21df73d1b12ed19eba481c08de8891e179e1870ed28d6e397f7746108f5" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" dependencies = [ - "cranelift-srcgen", + "hash32", + "stable_deref_trait", ] [[package]] -name = "cranelift-bforest" -version = "0.123.8" +name = "heck" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf917d0180c15c945c13c8dde615d32a015769513b29158f728311d85a8f80d" -dependencies = [ - "cranelift-entity", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] -name = "cranelift-bitset" -version = "0.123.8" +name = "hermit-abi" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6f4e1af2df00798c2895d228bb53d65c5aa09acace8525096f0b53830ffe42c" -dependencies = [ - "serde", - "serde_derive", -] +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] -name = "cranelift-codegen" -version = "0.123.8" +name = "hex" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3a5d7300e4b44933dcf2947399945abe3f30f92c789b496ad72949e3ee15a6" -dependencies = [ - "bumpalo", - "cranelift-assembler-x64", - "cranelift-bforest", - "cranelift-bitset", - "cranelift-codegen-meta", - "cranelift-codegen-shared", - "cranelift-control", - "cranelift-entity", - "cranelift-isle", - "gimli", - "hashbrown 0.15.5", - "log", - "pulley-interpreter", - "regalloc2", - "rustc-hash", - "serde", - "smallvec", - "target-lexicon", - "wasmtime-internal-math", -] +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "cranelift-codegen-meta" -version = "0.123.8" +name = "hexane" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "becdb5c3111800d7f8e666fe5f35693bfc77de4401bfcaea19815caf7c482fb9" +checksum = "8f4ecba0bb4e14df997df7cab6d1b584c6432d8865cf2adfced814706d715a7b" dependencies = [ - "cranelift-assembler-x64-meta", - "cranelift-codegen-shared", - "cranelift-srcgen", - "heck", - "pulley-interpreter", + "leb128", + "thiserror 2.0.18", ] [[package]] -name = "cranelift-codegen-shared" -version = "0.123.8" +name = "hf-xet" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8fa77efffa12934971f757e154b16dd5e369a7f388a0f3adff74aadfd4c5a1d" +checksum = "430b33fa84f92796d4d263070b6c0d3ca219df7b9a0e1853ee431029b1612bcd" +dependencies = [ + "async-trait", + "bytes", + "http 1.4.0", + "more-asserts", + "serde", + "thiserror 2.0.18", + "tokio", + "tokio-util", + "tracing", + "uuid", + "xet-client", + "xet-core-structures", + "xet-data", + "xet-runtime", +] [[package]] -name = "cranelift-control" -version = "0.123.8" +name = "hkdf" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62441d3aae3372381e03a121880482158ce90ca3bc2a56607cc122ee07536fe4" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "arbitrary", + "hmac 0.12.1", ] [[package]] -name = "cranelift-entity" -version = "0.123.8" +name = "hmac" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bdc9832a010e0d411439aa016e1664dd23ca5c8953bf26b90fe34ad4b76822d" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "cranelift-bitset", - "serde", - "serde_derive", + "digest 0.10.7", ] [[package]] -name = "cranelift-frontend" -version = "0.123.8" +name = "hmac" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9530b689b7c3accdbb32263ca318e19ab3bcf616d3a160c8456537c99b4c565b" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" dependencies = [ - "cranelift-codegen", - "log", - "smallvec", - "target-lexicon", + "digest 0.11.2", ] [[package]] -name = "cranelift-isle" -version = "0.123.8" +name = "home" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fcd3258a4d87376f2681c72269a42009286a3d3707b2af4024ba5b3750ad477" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] [[package]] -name = "cranelift-native" -version = "0.123.8" +name = "html5ever" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "642c5703a22b58abccbf46f46c0dae65f0535bbe725beec70527a1ffcbbc1d34" +checksum = "46a1761807faccc9a19e86944bbf40610014066306f96edcdedc2fb714bcb7b8" dependencies = [ - "cranelift-codegen", - "libc", - "target-lexicon", + "log", + "markup5ever", ] [[package]] -name = "cranelift-srcgen" -version = "0.123.8" +name = "http" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d200dcd5a37de108ec1329e0ba924e2badd2c0ef2343c338310135159ae454e2" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] [[package]] -name = "crc32fast" -version = "1.5.0" +name = "http" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ - "cfg-if", + "bytes", + "itoa", ] [[package]] -name = "crossbeam-deque" -version = "0.8.6" +name = "http-body" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", + "bytes", + "http 0.2.12", + "pin-project-lite", ] [[package]] -name = "crossbeam-epoch" -version = "0.9.18" +name = "http-body" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ - "crossbeam-utils", + "bytes", + "http 1.4.0", ] [[package]] -name = "crossbeam-queue" -version = "0.3.12" +name = "http-body-util" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ - "crossbeam-utils", + "bytes", + "futures-core", + "http 1.4.0", + "http-body 1.0.1", + "pin-project-lite", ] [[package]] -name = "crossbeam-utils" -version = "0.8.21" +name = "http-range-header" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" [[package]] -name = "crossterm" -version = "0.29.0" +name = "httparse" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" -dependencies = [ - "bitflags 2.11.1", - "crossterm_winapi", - "derive_more", - "document-features", - "mio", - "parking_lot", - "rustix", - "signal-hook", - "signal-hook-mio", - "winapi", -] +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] -name = "crossterm_winapi" -version = "0.9.1" +name = "httpdate" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" -dependencies = [ - "winapi", -] +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] -name = "crypto-bigint" -version = "0.5.5" +name = "humantime" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" + +[[package]] +name = "hybrid-array" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214" dependencies = [ - "generic-array", - "rand_core 0.6.4", - "subtle", - "zeroize", + "typenum", ] [[package]] -name = "crypto-common" -version = "0.1.6" +name = "hyper" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" dependencies = [ - "generic-array", - "typenum", + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http 1.4.0", + "http-body 1.0.1", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", ] [[package]] -name = "crypto-common" -version = "0.2.1" +name = "hyper-rustls" +version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ - "hybrid-array", + "http 1.4.0", + "hyper", + "hyper-util", + "rustls", + "rustls-native-certs 0.8.3", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots 1.0.7", ] [[package]] -name = "cssparser" -version = "0.36.0" +name = "hyper-tls" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa", - "phf 0.13.1", - "smallvec", + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", ] [[package]] -name = "cssparser-macros" -version = "0.6.1" +name = "hyper-util" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "quote", - "syn", + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", ] [[package]] -name = "ctutils" -version = "0.4.2" +name = "hyperloglogplus" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +checksum = "621debdf94dcac33e50475fdd76d34d5ea9c0362a834b9db08c3024696c1fbe3" dependencies = [ - "cmov", + "serde", ] [[package]] -name = "curve25519-dalek" -version = "4.1.3" +name = "i_float" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +checksum = "010025c2c532c8d82e42d0b8bb5184afa449fa6f06c709ea9adcb16c49ae405b" dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "curve25519-dalek-derive", - "digest 0.10.7", - "fiat-crypto", - "rustc_version", - "subtle", - "zeroize", + "libm", ] [[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" +name = "i_key_sort" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +checksum = "9190f86706ca38ac8add223b2aed8b1330002b5cdbbce28fb58b10914d38fc27" + +[[package]] +name = "i_overlay" +version = "4.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413183068e6e0289e18d7d0a1f661b81546e6918d5453a44570b9ab30cbed1b3" dependencies = [ - "proc-macro2", - "quote", - "syn", + "i_float", + "i_key_sort", + "i_shape", + "i_tree", + "rayon", ] [[package]] -name = "dashmap" -version = "5.5.3" +name = "i_shape" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +checksum = "1ea154b742f7d43dae2897fcd5ead86bc7b5eefcedd305a7ebf9f69d44d61082" dependencies = [ - "cfg-if", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", + "i_float", ] [[package]] -name = "dashmap" -version = "6.1.0" +name = "i_tree" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +checksum = "35e6d558e6d4c7b82bc51d9c771e7a927862a161a7d87bf2b0541450e0e20915" + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ - "cfg-if", - "crossbeam-utils", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", ] [[package]] -name = "data-encoding" -version = "2.10.0" +name = "iana-time-zone-haiku" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] [[package]] -name = "der" -version = "0.7.10" +name = "icu_calendar" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +checksum = "a2b2acc6263f494f1df50685b53ff8e57869e47d5c6fe39c23d518ae9a4f3e45" dependencies = [ - "const-oid 0.9.6", - "pem-rfc7468", - "zeroize", + "calendrical_calculations", + "displaydoc", + "icu_calendar_data", + "icu_locale", + "icu_locale_core", + "icu_provider", + "tinystr", + "zerovec", ] [[package]] -name = "deranged" -version = "0.5.8" +name = "icu_calendar_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "118577bcf3a0fa7c6ac0a7d6e951814da84ee56b9b1f68fb4d8d10b08cefaf4d" + +[[package]] +name = "icu_collections" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ - "powerfmt", + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", ] [[package]] -name = "derive_more" -version = "2.1.1" +name = "icu_locale" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +checksum = "d5a396343c7208121dc86e35623d3dfe19814a7613cfd14964994cdc9c9a2e26" dependencies = [ - "derive_more-impl", + "icu_collections", + "icu_locale_core", + "icu_locale_data", + "icu_provider", + "potential_utf", + "tinystr", + "zerovec", ] [[package]] -name = "derive_more-impl" -version = "2.1.1" +name = "icu_locale_core" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn", + "displaydoc", + "litemap", + "serde", + "tinystr", + "writeable", + "zerovec", ] [[package]] -name = "diff" -version = "0.1.13" +name = "icu_locale_data" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +checksum = "d5fdcc9ac77c6d74ff5cf6e65ef3181d6af32003b16fce3a77fb451d2f695993" [[package]] -name = "digest" -version = "0.10.7" +name = "icu_normalizer" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ - "block-buffer 0.10.4", - "const-oid 0.9.6", - "crypto-common 0.1.6", - "subtle", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", ] [[package]] -name = "digest" -version = "0.11.2" +name = "icu_normalizer_data" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" -dependencies = [ - "block-buffer 0.12.0", - "const-oid 0.10.2", - "crypto-common 0.2.1", - "ctutils", -] +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] -name = "dirs" -version = "6.0.0" +name = "icu_properties" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ - "dirs-sys", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", ] [[package]] -name = "dirs-sys" -version = "0.5.0" +name = "icu_properties_data" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.61.2", -] +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] -name = "displaydoc" -version = "0.2.5" +name = "icu_provider" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ - "proc-macro2", - "quote", - "syn", + "displaydoc", + "icu_locale_core", + "serde", + "stable_deref_trait", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", ] [[package]] -name = "document-features" -version = "0.2.12" +name = "id-arena" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" -dependencies = [ - "litrs", -] +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" [[package]] -name = "dtoa" -version = "1.0.11" +name = "ident_case" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] -name = "dtoa-short" -version = "0.3.5" +name = "idna" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ - "dtoa", + "idna_adapter", + "smallvec", + "utf8_iter", ] [[package]] -name = "dunce" -version = "1.0.5" +name = "idna_adapter" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] [[package]] -name = "dyn-clone" -version = "1.0.20" +name = "if_chain" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +checksum = "cd62e6b5e86ea8eeeb8db1de02880a6abc01a397b2ebb64b5d74ac255318f5cb" [[package]] -name = "ecdsa" -version = "0.16.9" +name = "imagesize" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" + +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" dependencies = [ - "der", - "digest 0.10.7", - "elliptic-curve", - "rfc6979", - "signature", - "spki", + "include_dir_macros", ] [[package]] -name = "ed25519" -version = "2.2.3" +name = "include_dir_macros" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" dependencies = [ - "pkcs8", - "signature", + "proc-macro2", + "quote", ] [[package]] -name = "ed25519-dalek" -version = "2.2.0" +name = "indexmap" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ - "curve25519-dalek", - "ed25519", + "autocfg", + "hashbrown 0.12.3", "serde", - "sha2 0.10.9", - "subtle", - "zeroize", ] [[package]] -name = "ego-tree" -version = "0.11.0" +name = "indexmap" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b04dc5a38e4f151a79d9f2451ae6037fb6eaf5cba34771f44781f80e508498e3" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.0", + "serde", + "serde_core", +] [[package]] -name = "either" -version = "1.15.0" +name = "infer" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" +dependencies = [ + "cfb", +] [[package]] -name = "elliptic-curve" -version = "0.13.8" +name = "inotify" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199" dependencies = [ - "base16ct", - "crypto-bigint", - "digest 0.10.7", - "ff", - "generic-array", - "group", - "hkdf", - "pem-rfc7468", - "pkcs8", - "rand_core 0.6.4", - "sec1", - "subtle", - "zeroize", + "bitflags 2.11.1", + "inotify-sys", + "libc", ] [[package]] -name = "embedded-io" -version = "0.4.0" +name = "inotify-sys" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] [[package]] -name = "embedded-io" -version = "0.6.1" +name = "inout" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "block-padding", + "generic-array", +] [[package]] -name = "encode_unicode" -version = "1.0.0" +name = "insta" +version = "1.47.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" +checksum = "7b4a6248eb93a4401ed2f37dfe8ea592d3cf05b7cf4f8efa867b6895af7e094e" +dependencies = [ + "console", + "once_cell", + "pest", + "pest_derive", + "serde", + "similar 2.7.0", + "tempfile", +] [[package]] -name = "encoding_rs" -version = "0.8.35" +name = "instant" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", ] [[package]] -name = "entities" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" - -[[package]] -name = "equivalent" -version = "1.0.2" +name = "integer-encoding" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02" [[package]] -name = "erased-serde" -version = "0.4.10" +name = "io-uring" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" +checksum = "4d09b98f7eace8982db770e4408e7470b028ce513ac28fecdc6bf4c30fe92b62" dependencies = [ - "serde", - "serde_core", - "typeid", + "bitflags 2.11.1", + "cfg-if 1.0.4", + "libc", ] [[package]] -name = "errno" -version = "0.3.14" +name = "ipnet" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] -name = "event-listener" -version = "5.4.1" +name = "iri-string" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", + "memchr", + "serde", ] [[package]] -name = "event-listener-strategy" -version = "0.5.4" +name = "is-docker" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" dependencies = [ - "event-listener", - "pin-project-lite", + "once_cell", ] [[package]] -name = "fallible-iterator" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" - -[[package]] -name = "fastrand" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" - -[[package]] -name = "ff" -version = "0.13.1" +name = "is-wsl" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" dependencies = [ - "rand_core 0.6.4", - "subtle", + "is-docker", + "once_cell", ] [[package]] -name = "fiat-crypto" -version = "0.2.9" +name = "is_terminal_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] -name = "find-msvc-tools" -version = "0.1.9" +name = "itertools" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] [[package]] -name = "finl_unicode" -version = "1.4.0" +name = "itertools" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9844ddc3a6e533d62bba727eb6c28b5d360921d5175e9ff0f1e621a5c590a4d5" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] [[package]] -name = "flate2" -version = "1.1.9" +name = "itertools" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ - "crc32fast", - "miniz_oxide", + "either", ] [[package]] -name = "fnv" -version = "1.0.7" +name = "itoa" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] -name = "foldhash" -version = "0.1.5" +name = "ixdtf" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +checksum = "2ceaf4c6c48465bead8cb6a0b7c4ee0c86ecbb31239032b9c66ab9a08d2f3ee1" [[package]] -name = "foldhash" -version = "0.2.0" +name = "jetscii" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" +checksum = "47f142fe24a9c9944451e8349de0a56af5f3e7226dc46f3ed4d4ecc0b85af75e" [[package]] -name = "foreign-types" -version = "0.3.2" +name = "jiff" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +checksum = "4603d3033e49e2b0e31229fcab20a5d40089c607d975cd9c80551dc69eed9102" dependencies = [ - "foreign-types-shared", + "jiff-static", + "jiff-tzdb-platform", + "js-sys", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", + "wasm-bindgen", + "windows-link", ] [[package]] -name = "foreign-types-shared" -version = "0.1.1" +name = "jiff-static" +version = "0.2.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] [[package]] -name = "form_urlencoded" -version = "1.2.2" +name = "jiff-tzdb" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] +checksum = "c900ef84826f1338a557697dc8fc601df9ca9af4ac137c7fb61d4c6f2dfd3076" [[package]] -name = "fs2" -version = "0.4.3" +name = "jiff-tzdb-platform" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" dependencies = [ - "libc", - "winapi", + "jiff-tzdb", ] [[package]] -name = "fs_extra" -version = "1.3.0" +name = "jni" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if 1.0.4", + "combine", + "jni-macros", + "jni-sys", + "log", + "simd_cesu8", + "thiserror 2.0.18", + "walkdir", + "windows-link", +] [[package]] -name = "fsevent-sys" -version = "4.1.0" +name = "jni-macros" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" dependencies = [ - "libc", + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.117", ] [[package]] -name = "futures" -version = "0.3.32" +name = "jni-sys" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", + "jni-sys-macros", ] [[package]] -name = "futures-channel" -version = "0.3.32" +name = "jni-sys-macros" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" dependencies = [ - "futures-core", - "futures-sink", + "quote", + "syn 2.0.117", ] [[package]] -name = "futures-core" -version = "0.3.32" +name = "jobserver" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] [[package]] -name = "futures-executor" -version = "0.3.32" +name = "js-sys" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" dependencies = [ - "futures-core", - "futures-task", - "futures-util", + "once_cell", + "wasm-bindgen", ] [[package]] -name = "futures-io" -version = "0.3.32" +name = "jsonb" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" +checksum = "eb98fb29636087c40ad0d1274d9a30c0c1e83e03ae93f6e7e89247b37fcc6953" +dependencies = [ + "byteorder", + "ethnum", + "fast-float2", + "itoa", + "jiff", + "nom 8.0.0", + "num-traits", + "ordered-float 5.3.0", + "rand 0.9.4", + "serde", + "serde_json", + "zmij", +] [[package]] -name = "futures-lite" -version = "2.6.1" +name = "jsonwebtoken" +version = "10.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +checksum = "0529410abe238729a60b108898784df8984c87f6054c9c4fcacc47e4803c1ce1" dependencies = [ - "futures-core", - "pin-project-lite", + "base64 0.22.1", + "ed25519-dalek", + "getrandom 0.2.17", + "hmac 0.12.1", + "js-sys", + "p256", + "p384", + "pem", + "rand 0.8.6", + "rsa", + "serde", + "serde_json", + "sha2 0.10.9", + "signature", + "simple_asn1", ] [[package]] -name = "futures-macro" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +name = "jupyter-protocol" +version = "2.0.0" +source = "git+https://github.com/cscheid/runtimed?rev=fc58eb48139a30cc559ac5973cb6debb00375b88#fc58eb48139a30cc559ac5973cb6debb00375b88" dependencies = [ - "proc-macro2", - "quote", - "syn", + "async-trait", + "bytes", + "chrono", + "futures", + "serde", + "serde_json", + "thiserror 2.0.18", + "uuid", ] [[package]] -name = "futures-sink" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" - -[[package]] -name = "futures-task" -version = "0.3.32" +name = "konst" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +checksum = "f660d5f887e3562f9ab6f4a14988795b694099d66b4f5dedc02d197ba9becb1d" +dependencies = [ + "const_panic", + "konst_proc_macros", + "typewit", +] [[package]] -name = "futures-timer" -version = "3.0.3" +name = "konst_proc_macros" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +checksum = "e037a2e1d8d5fdbd49b16a4ea09d5d6401c1f29eca5ff29d03d3824dba16256a" [[package]] -name = "futures-util" -version = "0.3.32" +name = "kqueue" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "slab", + "kqueue-sys", + "libc", ] [[package]] -name = "generic-array" -version = "0.14.9" +name = "kqueue-sys" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" dependencies = [ - "typenum", - "version_check", - "zeroize", + "bitflags 1.3.2", + "libc", ] [[package]] -name = "getopts" -version = "0.2.24" +name = "lance" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" +checksum = "3944aca86f4c78f4da04af1c2bf33e664a2826b7af72972ad200d6b9de59019f" dependencies = [ - "unicode-width", + "arc-swap", + "arrow", + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-ipc", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "async-recursion", + "async-trait", + "async_cell", + "aws-credential-types", + "bitpacking", + "byteorder", + "bytes", + "chrono", + "crossbeam-queue", + "crossbeam-skiplist", + "dashmap 6.1.0", + "datafusion", + "datafusion-expr", + "datafusion-functions", + "datafusion-physical-expr", + "datafusion-physical-plan", + "deepsize", + "either", + "futures", + "half", + "humantime", + "itertools 0.13.0", + "lance-arrow", + "lance-core", + "lance-datafusion", + "lance-encoding", + "lance-file", + "lance-index", + "lance-io", + "lance-linalg", + "lance-namespace", + "lance-table", + "lance-tokenizer", + "log", + "moka", + "object_store", + "permutation", + "pin-project", + "prost", + "prost-build", + "prost-types", + "rand 0.9.4", + "rayon", + "roaring", + "semver", + "serde", + "serde_json", + "snafu 0.9.1", + "tokio", + "tokio-stream", + "tokio-util", + "tracing", + "url", + "uuid", ] [[package]] -name = "getrandom" -version = "0.2.17" +name = "lance-arrow" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +checksum = "253f4a0a70580c985b91e65e9ca6cad644825a4078de28d8efbacf3ffbd7ecdc" dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-ipc", + "arrow-ord", + "arrow-schema", + "arrow-select", + "bytes", + "futures", + "getrandom 0.2.17", + "half", + "jsonb", + "num-traits", + "rand 0.9.4", ] [[package]] -name = "getrandom" -version = "0.3.4" +name = "lance-bitpacking" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +checksum = "80c4d12521b1945041dd515a56aa0854973138e7ac12111c92572e33e4ecb593" dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi 5.3.0", - "wasip2", - "wasm-bindgen", + "arrayref", + "paste", + "seq-macro", ] [[package]] -name = "getrandom" -version = "0.4.2" +name = "lance-core" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +checksum = "13f84020da5a484e2f07dd1796e09785ed7cd889857ebc4cb77e32ef214ee594" dependencies = [ - "cfg-if", + "arrow-array", + "arrow-buffer", + "arrow-schema", + "async-trait", + "byteorder", + "bytes", + "datafusion-common", + "datafusion-sql", + "deepsize", + "futures", + "itertools 0.13.0", + "lance-arrow", "libc", - "r-efi 6.0.0", - "wasip2", - "wasip3", + "log", + "moka", + "num_cpus", + "object_store", + "pin-project", + "prost", + "rand 0.9.4", + "roaring", + "serde_json", + "snafu 0.9.1", + "tempfile", + "tokio", + "tokio-stream", + "tokio-util", + "tracing", + "url", ] [[package]] -name = "gimli" -version = "0.32.3" +name = "lance-datafusion" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +checksum = "7460597a66534a75987993d4dac5bc330586d99c5b79ae73367dbcbd4e29e576" dependencies = [ - "fallible-iterator", - "indexmap", - "stable_deref_trait", + "arrow", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-ord", + "arrow-schema", + "arrow-select", + "async-trait", + "chrono", + "datafusion", + "datafusion-common", + "datafusion-functions", + "datafusion-physical-expr", + "futures", + "jsonb", + "lance-arrow", + "lance-core", + "lance-datagen", + "lance-geo", + "log", + "pin-project", + "prost", + "prost-build", + "tokio", + "tracing", ] [[package]] -name = "glob" -version = "0.3.3" +name = "lance-datagen" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +checksum = "046f5506ed2271cd941a050de7bf535dd3aedc291aadec836a63fa56c5926e3b" +dependencies = [ + "arrow", + "arrow-array", + "arrow-cast", + "arrow-schema", + "chrono", + "futures", + "half", + "hex", + "rand 0.9.4", + "rand_distr", + "rand_xoshiro", + "random_word", +] [[package]] -name = "globset" -version = "0.4.18" +name = "lance-encoding" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" +checksum = "7af54edf43dcf9d6a56cc636eb35d457e68373c6448dca3f0891b3325b4a24e6" dependencies = [ - "aho-corasick", - "bstr", + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "arrow-select", + "bytemuck", + "byteorder", + "bytes", + "fsst", + "futures", + "hex", + "hyperloglogplus", + "itertools 0.13.0", + "lance-arrow", + "lance-bitpacking", + "lance-core", "log", - "regex-automata", - "regex-syntax", + "lz4", + "num-traits", + "prost", + "prost-build", + "rand 0.9.4", + "strum 0.26.3", + "tokio", + "tracing", + "xxhash-rust", + "zstd", ] [[package]] -name = "grass" -version = "0.13.4" +name = "lance-file" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7a68216437ef68f0738e48d6c7bb9e6e6a92237e001b03d838314b068f33c94" +checksum = "0772ae2d6207995dc1eb28aff9507f78e90b3362b58f311da001e9dc25f3d736" dependencies = [ - "clap", - "getrandom 0.2.17", - "grass_compiler", + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "async-recursion", + "async-trait", + "byteorder", + "bytes", + "datafusion-common", + "deepsize", + "futures", + "lance-arrow", + "lance-core", + "lance-encoding", + "lance-io", + "log", + "num-traits", + "object_store", + "prost", + "prost-build", + "prost-types", + "tokio", + "tracing", ] [[package]] -name = "grass_compiler" -version = "0.13.4" +name = "lance-geo" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d9e3df7f0222ce5184154973d247c591d9aadc28ce7a73c6cd31100c9facff6" +checksum = "5466cc6524104de7f07d70d4af57fb6912b0eb484f4ac939501c01dbfae572df" dependencies = [ - "codemap", - "indexmap", - "lasso", - "once_cell", - "phf 0.11.3", - "rand 0.8.6", + "datafusion", + "geo-traits", + "geo-types", + "geoarrow-array", + "geoarrow-schema", + "geodatafusion", + "lance-core", + "serde", ] [[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +name = "lance-graph" +version = "0.5.4" dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", + "arrow", + "arrow-array", + "arrow-schema", + "async-trait", + "bytes", + "chrono", + "datafusion", + "datafusion-common", + "datafusion-expr", + "datafusion-functions-aggregate", + "datafusion-sql", + "futures", + "lance", + "lance-graph-catalog", + "lance-graph-contract", + "lance-linalg", + "lance-namespace", + "ndarray 0.17.2", + "nom 7.1.3", + "serde", + "serde_json", + "snafu 0.8.9", ] [[package]] -name = "h2" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171fefbc92fe4a4de27e0698d6a5b392d6a0e333506bc49133760b3bcf948733" +name = "lance-graph-catalog" +version = "0.5.4" dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", + "arrow-schema", + "async-trait", + "datafusion", + "lance-namespace", + "reqwest 0.12.28", + "serde", + "serde_json", + "snafu 0.8.9", ] [[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +name = "lance-graph-contract" +version = "0.1.0" dependencies = [ - "ahash", - "allocator-api2", + "glob", + "serde", + "serde_yaml", ] [[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +name = "lance-graph-planner" +version = "0.1.0" dependencies = [ - "foldhash 0.1.5", + "bgz17", + "causal-edge", + "lance-graph-contract", + "ndarray 0.17.2", + "p64 0.1.0", + "p64-bridge", "serde", + "serde_json", + "serde_yml", + "thiserror 2.0.18", + "tokio", + "tracing", ] [[package]] -name = "hashbrown" -version = "0.16.1" +name = "lance-index" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "e71fbfb51096a903cb524fe0da716f5f15fbc4a6b6f84cd6dec21abf319c5e84" dependencies = [ - "foldhash 0.2.0", + "arc-swap", + "arrow", + "arrow-arith", + "arrow-array", + "arrow-ord", + "arrow-schema", + "arrow-select", + "async-channel", + "async-recursion", + "async-trait", + "bitpacking", + "bitvec", + "bytes", + "chrono", + "crossbeam-queue", + "datafusion", + "datafusion-common", + "datafusion-expr", + "datafusion-physical-expr", + "deepsize", + "dirs", + "fst", + "futures", + "geo-types", + "geoarrow-array", + "geoarrow-schema", + "half", + "itertools 0.13.0", + "jsonb", + "lance-arrow", + "lance-core", + "lance-datafusion", + "lance-datagen", + "lance-encoding", + "lance-file", + "lance-geo", + "lance-io", + "lance-linalg", + "lance-table", + "lance-tokenizer", + "libm", + "log", + "ndarray 0.16.1", + "num-traits", + "object_store", + "prost", + "prost-build", + "prost-types", + "rand 0.9.4", + "rand_distr", + "rangemap", + "rayon", + "roaring", + "serde", + "serde_json", + "smallvec", + "tempfile", + "tokio", + "tracing", + "twox-hash", + "uuid", ] [[package]] -name = "hashbrown" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" - -[[package]] -name = "hashlink" -version = "0.11.0" +name = "lance-io" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0b22561a9c04a7cb1a302c013e0259cd3b4bb619f145b32f72b8b4bcbed230" +checksum = "bab8c98ef1b870b20541d27f3ca4efdf7c9f5c25214233be07d231ba88900219" dependencies = [ - "hashbrown 0.16.1", + "arrow", + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "arrow-select", + "async-recursion", + "async-trait", + "aws-config", + "aws-credential-types", + "byteorder", + "bytes", + "chrono", + "deepsize", + "futures", + "http 1.4.0", + "io-uring", + "lance-arrow", + "lance-core", + "lance-namespace", + "log", + "moka", + "object_store", + "object_store_opendal", + "opendal", + "path_abs", + "pin-project", + "prost", + "rand 0.9.4", "serde", + "tempfile", + "tokio", + "tracing", + "url", ] [[package]] -name = "headers" -version = "0.4.1" +name = "lance-linalg" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" +checksum = "6b4c51cad0ac780b02dc4da48528479e7693c03e8d05390510bbc69ca2a9a1f1" dependencies = [ - "base64 0.22.1", - "bytes", - "headers-core", - "http", - "httpdate", - "mime", - "sha1 0.10.6", + "arrow-array", + "arrow-buffer", + "arrow-schema", + "cc", + "deepsize", + "half", + "lance-arrow", + "lance-core", + "num-traits", + "rand 0.9.4", ] [[package]] -name = "headers-core" -version = "0.3.0" +name = "lance-namespace" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +checksum = "014e8332ca0615506342e0d3af608639864b68396973be14239f09c9f21f1fc2" dependencies = [ - "http", + "arrow", + "async-trait", + "bytes", + "lance-core", + "lance-namespace-reqwest-client", + "snafu 0.9.1", ] [[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.5.2" +name = "lance-namespace-reqwest-client" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +checksum = "6369eee4682fb11edf538388b43c61ce288b8302fe89bb40944d7daa7faaae99" +dependencies = [ + "reqwest 0.12.28", + "serde", + "serde_json", + "serde_repr", + "serde_with", + "url", +] [[package]] -name = "hex" -version = "0.4.3" +name = "lance-table" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +checksum = "b16f1355904aea4ebb04ffc70c58c97901e10bde44452b4b021de4a1f329250d" +dependencies = [ + "arrow", + "arrow-array", + "arrow-buffer", + "arrow-ipc", + "arrow-schema", + "async-trait", + "byteorder", + "bytes", + "chrono", + "deepsize", + "futures", + "lance-arrow", + "lance-core", + "lance-file", + "lance-io", + "log", + "object_store", + "prost", + "prost-build", + "prost-types", + "rand 0.9.4", + "rangemap", + "roaring", + "semver", + "serde", + "serde_json", + "snafu 0.9.1", + "tokio", + "tracing", + "url", + "uuid", +] [[package]] -name = "hexane" -version = "0.2.1" +name = "lance-tokenizer" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4ecba0bb4e14df997df7cab6d1b584c6432d8865cf2adfced814706d715a7b" +checksum = "b39b7f5ed9d0c0b716bf599b559d888267ed1dfe4c4e29d3648b51d2a28940cf" dependencies = [ - "leb128", - "thiserror 2.0.18", + "rust-stemmers", + "serde", + "unicode-normalization", ] [[package]] -name = "hkdf" -version = "0.12.4" +name = "lasso" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +checksum = "6e14eda50a3494b3bf7b9ce51c52434a761e383d7238ce1dd5dcec2fbc13e9fb" dependencies = [ - "hmac 0.12.1", + "hashbrown 0.14.5", ] [[package]] -name = "hmac" -version = "0.12.1" +name = "lazy_static" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "digest 0.10.7", + "spin", ] [[package]] -name = "hmac" -version = "0.13.0" +name = "leb128" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" -dependencies = [ - "digest 0.11.2", -] +checksum = "6cc46bac87ef8093eed6f272babb833b6443374399985ac8ed28471ee0918545" [[package]] -name = "html5ever" -version = "0.39.0" +name = "leb128fmt" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a1761807faccc9a19e86944bbf40610014066306f96edcdedc2fb714bcb7b8" -dependencies = [ - "log", - "markup5ever", -] +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] -name = "http" -version = "1.4.0" +name = "lexical-core" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "7d8d125a277f807e55a77304455eb7b1cb52f2b18c143b60e766c120bd64a594" dependencies = [ - "bytes", - "itoa", + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", ] [[package]] -name = "http-body" -version = "1.0.1" +name = "lexical-parse-float" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "52a9f232fbd6f550bc0137dcb5f99ab674071ac2d690ac69704593cb4abbea56" dependencies = [ - "bytes", - "http", + "lexical-parse-integer", + "lexical-util", ] [[package]] -name = "http-body-util" -version = "0.1.3" +name = "lexical-parse-integer" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +checksum = "9a7a039f8fb9c19c996cd7b2fcce303c1b2874fe1aca544edc85c4a5f8489b34" dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", + "lexical-util", ] [[package]] -name = "httparse" -version = "1.10.1" +name = "lexical-util" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +checksum = "2604dd126bb14f13fb5d1bd6a66155079cb9fa655b37f875b3a742c705dbed17" [[package]] -name = "httpdate" -version = "1.0.3" +name = "lexical-write-float" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +checksum = "50c438c87c013188d415fbabbb1dceb44249ab81664efbd31b14ae55dabb6361" +dependencies = [ + "lexical-util", + "lexical-write-integer", +] [[package]] -name = "hybrid-array" -version = "0.4.10" +name = "lexical-write-integer" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214" +checksum = "409851a618475d2d5796377cad353802345cba92c867d9fbcde9cf4eac4e14df" dependencies = [ - "typenum", + "lexical-util", ] [[package]] -name = "hyper" -version = "1.9.0" +name = "libc" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" -dependencies = [ - "atomic-waker", - "bytes", - "futures-channel", - "futures-core", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] -name = "hyper-rustls" -version = "0.27.9" +name = "libloading" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ - "http", - "hyper", - "hyper-util", - "rustls", - "tokio", - "tokio-rustls", - "tower-service", - "webpki-roots", + "cfg-if 1.0.4", + "windows-link", ] [[package]] -name = "hyper-tls" -version = "0.6.0" +name = "libm" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] -name = "hyper-util" -version = "0.1.20" +name = "libredox" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" dependencies = [ - "base64 0.22.1", - "bytes", - "futures-channel", - "futures-util", - "http", - "http-body", - "hyper", - "ipnet", "libc", - "percent-encoding", - "pin-project-lite", - "socket2", - "system-configuration", - "tokio", - "tower-service", - "tracing", - "windows-registry", ] [[package]] -name = "iana-time-zone" -version = "0.1.65" +name = "libyml" +version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +checksum = "3302702afa434ffa30847a83305f0a69d6abd74293b6554c18ec85c7ef30c980" dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", + "anyhow", + "version_check", ] [[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" +name = "linux-raw-sys" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] -name = "icu_collections" -version = "2.1.1" +name = "linux-raw-sys" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] -name = "icu_locale_core" -version = "2.2.0" +name = "litrs" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] -name = "icu_normalizer" -version = "2.1.1" +name = "lock_api" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", + "scopeguard", ] [[package]] -name = "icu_normalizer_data" -version = "2.1.1" +name = "log" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] -name = "icu_properties" -version = "2.1.2" +name = "loom" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", + "cfg-if 1.0.4", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", ] [[package]] -name = "icu_properties_data" -version = "2.1.2" +name = "lru-slab" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] -name = "icu_provider" -version = "2.2.0" +name = "lsp-types" +version = "0.94.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +checksum = "c66bfd44a06ae10647fe3f8214762e9369fd4248df1350924b4ef9e770a85ea1" dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", + "bitflags 1.3.2", + "serde", + "serde_json", + "serde_repr", + "url", ] [[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" +name = "lua-src" +version = "550.0.0" +dependencies = [ + "cc", +] [[package]] -name = "idna" -version = "1.1.0" +name = "luajit-src" +version = "210.6.6+707c12b" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +checksum = "a86cc925d4053d0526ae7f5bc765dbd0d7a5d1a63d43974f4966cb349ca63295" dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", + "cc", + "which 8.0.2", ] [[package]] -name = "idna_adapter" -version = "1.2.1" +name = "lz4" +version = "1.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +checksum = "a20b523e860d03443e98350ceaac5e71c6ba89aea7d960769ec3ce37f4de5af4" dependencies = [ - "icu_normalizer", - "icu_properties", + "lz4-sys", ] [[package]] -name = "imagesize" -version = "0.13.0" +name = "lz4-sys" +version = "1.11.1+lz4-1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" +checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" +dependencies = [ + "cc", + "libc", +] [[package]] -name = "include_dir" -version = "0.7.4" +name = "lz4_flex" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +checksum = "7ef0d4ed8669f8f8826eb00dc878084aa8f253506c4fd5e8f58f5bce72ddb97e" dependencies = [ - "include_dir_macros", + "twox-hash", ] [[package]] -name = "include_dir_macros" -version = "0.7.4" +name = "mach2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" dependencies = [ - "proc-macro2", - "quote", + "libc", ] [[package]] -name = "indexmap" -version = "2.14.0" +name = "markup5ever" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +checksum = "7122d987ec5f704ee56f6e5b41a7d93722e9aae27ae07cafa4036c4d3f9757de" dependencies = [ - "equivalent", - "hashbrown 0.17.0", - "serde", - "serde_core", + "log", + "tendril", + "web_atoms", ] [[package]] -name = "infer" -version = "0.19.0" +name = "matchers" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" dependencies = [ - "cfb", + "regex-automata", ] [[package]] -name = "inotify" -version = "0.11.1" +name = "matchit" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" dependencies = [ - "bitflags 2.11.1", - "inotify-sys", - "libc", + "autocfg", + "num_cpus", + "once_cell", + "rawpointer", + "thread-tree", ] [[package]] -name = "inotify-sys" -version = "0.1.5" +name = "md-5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ - "libc", + "cfg-if 1.0.4", + "digest 0.10.7", ] [[package]] -name = "insta" -version = "1.47.2" +name = "mea" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4a6248eb93a4401ed2f37dfe8ea592d3cf05b7cf4f8efa867b6895af7e094e" +checksum = "2640d335e7273dacdcf51044026139b2e269c3bb0dfc3f8cb3496b85e3f6a42c" dependencies = [ - "console", - "once_cell", - "pest", - "pest_derive", - "serde", - "similar 2.7.0", - "tempfile", + "slab", ] [[package]] -name = "ipnet" -version = "2.12.0" +name = "memchr" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] -name = "iri-string" -version = "0.7.12" +name = "memfd" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" +checksum = "ad38eb12aea514a0466ea40a80fd8cc83637065948eb4a426e4aa46261175227" dependencies = [ - "memchr", - "serde", + "rustix 1.1.4", ] [[package]] -name = "is-docker" -version = "0.2.0" +name = "mime" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" -dependencies = [ - "once_cell", -] +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] -name = "is-wsl" -version = "0.4.0" +name = "mime_guess" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ - "is-docker", - "once_cell", + "mime", + "unicase", ] [[package]] -name = "is_terminal_polyfill" -version = "1.70.2" +name = "minicbor" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +checksum = "734daad4ff3b880f23dc2a675dd74553fa8e583367aa7523f96a16e96a516b62" +dependencies = [ + "minicbor-derive", +] [[package]] -name = "itertools" -version = "0.14.0" +name = "minicbor-derive" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +checksum = "512ce2c37128698ea15c99b3518936c78a8b112b92468e7b95b9fa045666ebd8" dependencies = [ - "either", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] -name = "itoa" -version = "1.0.18" +name = "minimal-lexical" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] -name = "jetscii" -version = "0.5.3" +name = "miniz_oxide" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47f142fe24a9c9944451e8349de0a56af5f3e7226dc46f3ed4d4ecc0b85af75e" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] [[package]] -name = "jni" -version = "0.22.4" +name = "mio" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ - "cfg-if", - "combine", - "jni-macros", - "jni-sys", + "libc", "log", - "simd_cesu8", - "thiserror 2.0.18", - "walkdir", - "windows-link", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.61.2", +] + +[[package]] +name = "mlua" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccd36acfa49ce6ee56d1307a061dd302c564eee757e6e4cd67eb4f7204846fab" +dependencies = [ + "bstr", + "either", + "erased-serde", + "futures-util", + "libc", + "mlua-sys", + "num-traits", + "parking_lot", + "rustc-hash", + "rustversion", + "serde", + "serde-value", ] [[package]] -name = "jni-macros" -version = "0.22.4" +name = "mlua-sys" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +checksum = "0f1c3a7fc7580227ece249fd90aa2fa3b39eb2b49d3aec5e103b3e85f2c3dfc8" dependencies = [ - "proc-macro2", - "quote", - "rustc_version", - "simd_cesu8", - "syn", + "cc", + "cfg-if 1.0.4", + "libc", + "lua-src", + "luajit-src", + "pkg-config", ] [[package]] -name = "jni-sys" -version = "0.4.1" +name = "moka" +version = "0.12.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046" dependencies = [ - "jni-sys-macros", + "async-lock", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "equivalent", + "event-listener", + "futures-util", + "parking_lot", + "portable-atomic", + "smallvec", + "tagptr", + "uuid", ] [[package]] -name = "jni-sys-macros" -version = "0.4.1" +name = "more-asserts" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" -dependencies = [ - "quote", - "syn", -] +checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" [[package]] -name = "jobserver" -version = "0.1.34" +name = "multimap" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" -dependencies = [ - "getrandom 0.3.4", - "libc", -] +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" [[package]] -name = "js-sys" -version = "0.3.85" +name = "native-tls" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" dependencies = [ - "once_cell", - "wasm-bindgen", + "libc", + "log", + "openssl", + "openssl-probe 0.2.1", + "openssl-sys", + "schannel", + "security-framework 3.7.0", + "security-framework-sys", + "tempfile", ] [[package]] -name = "jsonwebtoken" -version = "10.3.0" +name = "ndarray" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0529410abe238729a60b108898784df8984c87f6054c9c4fcacc47e4803c1ce1" +checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" dependencies = [ - "base64 0.22.1", - "ed25519-dalek", - "getrandom 0.2.17", - "hmac 0.12.1", - "js-sys", - "p256", - "p384", - "pem", - "rand 0.8.6", - "rsa", - "serde", - "serde_json", - "sha2 0.10.9", - "signature", - "simple_asn1", + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", ] [[package]] -name = "jupyter-protocol" -version = "2.0.0" -source = "git+https://github.com/cscheid/runtimed?rev=fc58eb48139a30cc559ac5973cb6debb00375b88#fc58eb48139a30cc559ac5973cb6debb00375b88" +name = "ndarray" +version = "0.17.2" dependencies = [ - "async-trait", - "bytes", - "chrono", - "futures", - "serde", - "serde_json", - "thiserror 2.0.18", - "uuid", + "blake3", + "fractal 0.1.0", + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "p64 0.1.0", + "paste", + "portable-atomic", + "portable-atomic-util", + "rawpointer", ] [[package]] -name = "kqueue" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" +name = "ndarray" +version = "0.17.2" +source = "git+https://github.com/AdaWorldAPI/ndarray.git?branch=master#7a8b793a11c3a6e1a2f2360c26632a8ee52797bd" dependencies = [ - "kqueue-sys", + "blake3", + "cblas-sys", + "fractal 0.1.0 (git+https://github.com/AdaWorldAPI/ndarray.git?branch=master)", "libc", + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "p64 0.1.0 (git+https://github.com/AdaWorldAPI/ndarray.git?branch=master)", + "paste", + "portable-atomic", + "portable-atomic-util", + "rawpointer", + "rayon", ] [[package]] -name = "kqueue-sys" -version = "1.0.4" +name = "neo4rs" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +checksum = "43dd99fe7dbc68f754759874d83ec2ca43a61ab7d51c10353d024094805382be" dependencies = [ - "bitflags 1.3.2", - "libc", + "async-trait", + "backoff", + "bytes", + "chrono", + "chrono-tz 0.8.6", + "deadpool", + "delegate", + "futures", + "log", + "neo4rs-macros", + "paste", + "pin-project-lite", + "rustls-native-certs 0.7.3", + "rustls-pemfile", + "serde", + "thiserror 1.0.69", + "tokio", + "tokio-rustls", + "url", + "webpki-roots 0.26.11", ] [[package]] -name = "lasso" -version = "0.7.3" +name = "neo4rs-macros" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e14eda50a3494b3bf7b9ce51c52434a761e383d7238ce1dd5dcec2fbc13e9fb" +checksum = "53a0d57c55d2d1dc62a2b1d16a0a1079eb78d67c36bdf468d582ab4482ec7002" dependencies = [ - "hashbrown 0.14.5", + "quote", + "syn 2.0.117", ] [[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +name = "neural-debug" +version = "0.1.0" dependencies = [ - "spin", + "axum 0.7.9", + "parking_lot", + "serde", + "serde_json", + "tokio", ] [[package]] -name = "leb128" -version = "0.2.6" +name = "new_debug_unreachable" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cc46bac87ef8093eed6f272babb833b6443374399985ac8ed28471ee0918545" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] -name = "leb128fmt" -version = "0.1.0" +name = "nom" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] [[package]] -name = "libc" -version = "0.2.185" +name = "nom" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] [[package]] -name = "libm" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" +name = "notebook-query" +version = "0.1.0" +dependencies = [ + "arrow", + "bgz17", + "datafusion", + "graph-flow", + "lance-graph", + "lance-graph-contract", + "lance-graph-planner", + "neo4rs", + "serde", + "serde_json", + "tokio", + "uuid", +] [[package]] -name = "libredox" -version = "0.1.16" +name = "notify" +version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" +checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ + "bitflags 2.11.1", + "fsevent-sys", + "inotify", + "kqueue", "libc", + "log", + "mio", + "notify-types", + "walkdir", + "windows-sys 0.60.2", ] [[package]] -name = "linux-raw-sys" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" - -[[package]] -name = "litemap" -version = "0.8.2" +name = "notify-debouncer-mini" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +checksum = "17849edfaabd9a5fef1c606d99cfc615a8e99f7ac4366406d86c7942a3184cf2" +dependencies = [ + "log", + "notify", + "notify-types", + "tempfile", +] [[package]] -name = "litrs" -version = "1.0.0" +name = "notify-types" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" +checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" +dependencies = [ + "bitflags 2.11.1", +] [[package]] -name = "lock_api" -version = "0.4.14" +name = "ntapi" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae" dependencies = [ - "scopeguard", + "winapi", ] [[package]] -name = "log" -version = "0.4.29" +name = "nu-ansi-term" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] [[package]] -name = "lru-slab" -version = "0.1.2" +name = "num-bigint" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", + "rand 0.8.6", +] [[package]] -name = "lsp-types" -version = "0.94.1" +name = "num-bigint-dig" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66bfd44a06ae10647fe3f8214762e9369fd4248df1350924b4ef9e770a85ea1" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" dependencies = [ - "bitflags 1.3.2", - "serde", - "serde_json", - "serde_repr", - "url", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.6", + "smallvec", + "zeroize", ] [[package]] -name = "lua-src" -version = "550.0.0" +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ - "cc", + "num-traits", ] [[package]] -name = "luajit-src" -version = "210.6.6+707c12b" +name = "num-conv" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a86cc925d4053d0526ae7f5bc765dbd0d7a5d1a63d43974f4966cb349ca63295" -dependencies = [ - "cc", - "which", -] +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" [[package]] -name = "mach2" -version = "0.4.3" +name = "num-integer" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "libc", + "num-traits", ] [[package]] -name = "markup5ever" -version = "0.39.0" +name = "num-iter" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7122d987ec5f704ee56f6e5b41a7d93722e9aae27ae07cafa4036c4d3f9757de" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ - "log", - "tendril", - "web_atoms", + "autocfg", + "num-integer", + "num-traits", ] [[package]] -name = "matchers" -version = "0.2.0" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "regex-automata", + "autocfg", + "libm", ] [[package]] -name = "matchit" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" - -[[package]] -name = "memchr" -version = "2.8.0" +name = "num_cpus" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] [[package]] -name = "memfd" -version = "0.6.5" +name = "num_enum" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad38eb12aea514a0466ea40a80fd8cc83637065948eb4a426e4aa46261175227" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" dependencies = [ - "rustix", + "num_enum_derive", + "rustversion", ] [[package]] -name = "mime" -version = "0.3.17" +name = "num_enum_derive" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.117", +] [[package]] -name = "minicbor" -version = "1.1.0" +name = "objc2-core-foundation" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "734daad4ff3b880f23dc2a675dd74553fa8e583367aa7523f96a16e96a516b62" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "minicbor-derive", + "bitflags 2.11.1", ] [[package]] -name = "minicbor-derive" -version = "0.17.0" +name = "objc2-io-kit" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512ce2c37128698ea15c99b3518936c78a8b112b92468e7b95b9fa045666ebd8" +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" dependencies = [ - "proc-macro2", - "quote", - "syn", + "libc", + "objc2-core-foundation", ] [[package]] -name = "miniz_oxide" -version = "0.8.9" +name = "objc2-system-configuration" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +checksum = "7216bd11cbda54ccabcab84d523dc93b858ec75ecfb3a7d89513fa22464da396" dependencies = [ - "adler2", - "simd-adler32", + "objc2-core-foundation", ] [[package]] -name = "mio" -version = "1.2.0" +name = "object" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.61.2", + "crc32fast", + "hashbrown 0.15.5", + "indexmap 2.14.0", + "memchr", ] [[package]] -name = "mlua" -version = "0.11.6" +name = "object_store" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccd36acfa49ce6ee56d1307a061dd302c564eee757e6e4cd67eb4f7204846fab" +checksum = "622acbc9100d3c10e2ee15804b0caa40e55c933d5aa53814cd520805b7958a49" dependencies = [ - "bstr", - "either", - "erased-serde", + "async-trait", + "base64 0.22.1", + "bytes", + "chrono", + "form_urlencoded", + "futures-channel", + "futures-core", "futures-util", - "libc", - "mlua-sys", - "num-traits", + "http 1.4.0", + "http-body-util", + "httparse", + "humantime", + "hyper", + "itertools 0.14.0", + "md-5", "parking_lot", - "rustc-hash", - "rustversion", + "percent-encoding", + "quick-xml 0.39.3", + "rand 0.10.1", + "reqwest 0.12.28", + "ring", + "rustls-pki-types", "serde", - "serde-value", + "serde_json", + "serde_urlencoded", + "thiserror 2.0.18", + "tokio", + "tracing", + "url", + "walkdir", + "wasm-bindgen-futures 0.4.58 (registry+https://github.com/rust-lang/crates.io-index)", + "web-time", ] [[package]] -name = "mlua-sys" -version = "0.10.0" +name = "object_store_opendal" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1c3a7fc7580227ece249fd90aa2fa3b39eb2b49d3aec5e103b3e85f2c3dfc8" +checksum = "08298874eee5935c95bcaa393148834f9c53d904461ca15584a041d8a1c907c2" dependencies = [ - "cc", - "cfg-if", - "libc", - "lua-src", - "luajit-src", - "pkg-config", + "async-trait", + "bytes", + "chrono", + "futures", + "mea", + "object_store", + "opendal", + "pin-project", + "tokio", ] [[package]] -name = "native-tls" -version = "0.2.18" +name = "once_cell" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] -name = "new_debug_unreachable" -version = "1.0.6" +name = "once_cell_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] -name = "notify" -version = "8.2.0" +name = "oneshot" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" +checksum = "269bca4c2591a28585d6bf10d9ed0332b7d76900a1b02bec41bdc3a2cdcda107" + +[[package]] +name = "open" +version = "5.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fbaa89d2ddc8473c78a3adf69eea8cffa28c483b8e02a971ef31527cd0fc92c" dependencies = [ - "bitflags 2.11.1", - "fsevent-sys", - "inotify", - "kqueue", + "is-wsl", "libc", - "log", - "mio", - "notify-types", - "walkdir", - "windows-sys 0.60.2", + "pathdiff", ] [[package]] -name = "notify-debouncer-mini" -version = "0.7.0" +name = "opendal" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17849edfaabd9a5fef1c606d99cfc615a8e99f7ac4366406d86c7942a3184cf2" +checksum = "97b31d3d8e99a85d83b73ec26647f5607b80578ed9375810b6e44ffa3590a236" +dependencies = [ + "ctor", + "opendal-core", + "opendal-layer-concurrent-limit", + "opendal-layer-logging", + "opendal-layer-retry", + "opendal-layer-timeout", + "opendal-service-azblob", + "opendal-service-azdls", + "opendal-service-cos", + "opendal-service-gcs", + "opendal-service-hf", + "opendal-service-oss", + "opendal-service-s3", +] + +[[package]] +name = "opendal-core" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1849dd2687e173e776d3af5fce1ba3ae47b9dd37a09d1c4deba850ef45fe00ca" dependencies = [ + "anyhow", + "base64 0.22.1", + "bytes", + "futures", + "http 1.4.0", + "http-body 1.0.1", + "jiff", "log", - "notify", - "notify-types", - "tempfile", + "md-5", + "mea", + "percent-encoding", + "quick-xml 0.38.4", + "reqsign-core", + "reqwest 0.13.3", + "serde", + "serde_json", + "tokio", + "url", + "uuid", + "web-time", ] [[package]] -name = "notify-types" -version = "2.1.0" +name = "opendal-layer-concurrent-limit" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" +checksum = "048b1b29c503263bdd80a9afe46a68cd02ea9bd361185b1feab4b151078998e9" dependencies = [ - "bitflags 2.11.1", + "futures", + "http 1.4.0", + "mea", + "opendal-core", ] [[package]] -name = "nu-ansi-term" -version = "0.50.3" +name = "opendal-layer-logging" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +checksum = "d2645adc988b12eda106e2679ae529facfbbaa868ceb706f6f8125c6af15c47b" dependencies = [ - "windows-sys 0.61.2", + "log", + "opendal-core", ] [[package]] -name = "num-bigint" -version = "0.4.6" +name = "opendal-layer-retry" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +checksum = "4eac134ffa4ddda6131a640a84a5315996424b9416c85052f8c64c1a33b70ad4" dependencies = [ - "num-integer", - "num-traits", + "backon", + "log", + "opendal-core", ] [[package]] -name = "num-bigint-dig" -version = "0.8.6" +name = "opendal-layer-timeout" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +checksum = "619586ab7480c2e3009f6d18eabab18957bc094778fd130bcc38924970a90f4c" dependencies = [ - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand 0.8.6", - "smallvec", - "zeroize", + "opendal-core", + "tokio", ] [[package]] -name = "num-conv" -version = "0.2.1" +name = "opendal-service-azblob" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" +checksum = "7452bf3ec61cfd81ac9ad9ada17825931e9e371d44a045c6bfab9596c0a2ac3b" +dependencies = [ + "base64 0.22.1", + "bytes", + "http 1.4.0", + "log", + "opendal-core", + "opendal-service-azure-common", + "quick-xml 0.38.4", + "reqsign-azure-storage", + "reqsign-core", + "reqsign-file-read-tokio", + "serde", + "sha2 0.10.9", + "uuid", +] [[package]] -name = "num-integer" -version = "0.1.46" +name = "opendal-service-azdls" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +checksum = "8f9884c2d8cf8ba2bb077d79c877dac5863ba3bab9e2c9c1e41a2e0491404772" dependencies = [ - "num-traits", + "bytes", + "http 1.4.0", + "log", + "opendal-core", + "opendal-service-azure-common", + "quick-xml 0.38.4", + "reqsign-azure-storage", + "reqsign-core", + "reqsign-file-read-tokio", + "serde", + "serde_json", ] [[package]] -name = "num-iter" -version = "0.1.45" +name = "opendal-service-azure-common" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +checksum = "ffb0e45d6c8dcf66ce2da20e241bcb80e6e540e109a4ff20f318f6c9b4c54e0c" dependencies = [ - "autocfg", - "num-integer", - "num-traits", + "http 1.4.0", + "opendal-core", ] [[package]] -name = "num-traits" -version = "0.2.19" +name = "opendal-service-cos" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "55a0765ba451b6effdbf514b7b50060530ff8a29e4231c4a3ab7792c016408e6" dependencies = [ - "autocfg", - "libm", + "bytes", + "http 1.4.0", + "log", + "opendal-core", + "quick-xml 0.38.4", + "reqsign-core", + "reqsign-file-read-tokio", + "reqsign-tencent-cos", + "serde", ] [[package]] -name = "object" -version = "0.37.3" +name = "opendal-service-gcs" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +checksum = "70a49477a10163431896d106136117f5670717f9c9e49cf6f710528800c6633a" dependencies = [ - "crc32fast", - "hashbrown 0.15.5", - "indexmap", - "memchr", + "async-trait", + "bytes", + "http 1.4.0", + "log", + "opendal-core", + "percent-encoding", + "quick-xml 0.38.4", + "reqsign-core", + "reqsign-file-read-tokio", + "reqsign-google", + "serde", + "serde_json", + "tokio", ] [[package]] -name = "once_cell" -version = "1.21.4" +name = "opendal-service-hf" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +checksum = "7b2ab7a2a8a11dfe257ef4db5c0de798acbcd0d6429c37382dad2154bc06a388" +dependencies = [ + "bytes", + "hf-xet", + "http 1.4.0", + "log", + "opendal-core", + "percent-encoding", + "reqwest 0.13.3", + "serde", + "serde_json", +] [[package]] -name = "once_cell_polyfill" -version = "1.70.2" +name = "opendal-service-oss" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +checksum = "29c8a917829ad06d21b639558532cb0101fe49b040d946d673a73018683fac05" +dependencies = [ + "bytes", + "http 1.4.0", + "log", + "opendal-core", + "quick-xml 0.38.4", + "reqsign-aliyun-oss", + "reqsign-core", + "reqsign-file-read-tokio", + "serde", +] [[package]] -name = "open" -version = "5.3.5" +name = "opendal-service-s3" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fbaa89d2ddc8473c78a3adf69eea8cffa28c483b8e02a971ef31527cd0fc92c" +checksum = "9dadddeb9bb50b0d30927dd914c298c4ddca47e4c1cfa7674d311f0cf9b051c8" dependencies = [ - "is-wsl", - "libc", - "pathdiff", + "base64 0.22.1", + "bytes", + "crc32c", + "http 1.4.0", + "log", + "md-5", + "opendal-core", + "quick-xml 0.38.4", + "reqsign-aws-v4", + "reqsign-core", + "reqsign-file-read-tokio", + "serde", + "url", ] [[package]] @@ -2846,7 +7012,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38c4372413cdaaf3cc79dd92d29d7d9f5ab09b51b10dded508fb90bb70b9222" dependencies = [ "bitflags 2.11.1", - "cfg-if", + "cfg-if 1.0.4", "foreign-types", "libc", "once_cell", @@ -2862,9 +7028,15 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + [[package]] name = "openssl-probe" version = "0.2.1" @@ -2908,6 +7080,40 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ordered-float" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e" +dependencies = [ + "num-traits", +] + +[[package]] +name = "ordered-multimap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" +dependencies = [ + "dlv-list", + "hashbrown 0.14.5", +] + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" +dependencies = [ + "memchr", +] + +[[package]] +name = "outref" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" + [[package]] name = "p256" version = "0.13.2" @@ -2932,6 +7138,29 @@ dependencies = [ "sha2 0.10.9", ] +[[package]] +name = "p64" +version = "0.1.0" +dependencies = [ + "fractal 0.1.0", +] + +[[package]] +name = "p64" +version = "0.1.0" +source = "git+https://github.com/AdaWorldAPI/ndarray.git?branch=master#7a8b793a11c3a6e1a2f2360c26632a8ee52797bd" +dependencies = [ + "fractal 0.1.0 (git+https://github.com/AdaWorldAPI/ndarray.git?branch=master)", +] + +[[package]] +name = "p64-bridge" +version = "0.1.0" +dependencies = [ + "bgz17", + "causal-edge", +] + [[package]] name = "pampa" version = "0.0.0" @@ -2944,7 +7173,7 @@ dependencies = [ "crossterm", "glob", "hashlink", - "indexmap", + "indexmap 2.14.0", "insta", "mlua", "once_cell", @@ -3000,25 +7229,92 @@ version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "libc", "redox_syscall", "smallvec", "windows-link", ] +[[package]] +name = "parquet" +version = "58.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dafa7d01085b62a47dd0c1829550a0a36710ea9c4fe358a05a85477cec8a908" +dependencies = [ + "ahash", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-ipc", + "arrow-schema", + "arrow-select", + "base64 0.22.1", + "brotli", + "bytes", + "chrono", + "flate2", + "futures", + "half", + "hashbrown 0.17.0", + "lz4_flex", + "num-bigint", + "num-integer", + "num-traits", + "object_store", + "paste", + "seq-macro", + "simdutf8", + "snap", + "thrift", + "tokio", + "twox-hash", + "zstd", +] + +[[package]] +name = "parse-zoneinfo" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" +dependencies = [ + "regex", +] + [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "path_abs" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ef02f6342ac01d8a93b65f96db53fe68a92a15f41144f97fb00a9e669633c3" +dependencies = [ + "serde", + "serde_derive", + "std_prelude", + "stfu8", +] + [[package]] name = "pathdiff" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "hmac 0.12.1", +] + [[package]] name = "pem" version = "3.0.6" @@ -3054,6 +7350,12 @@ dependencies = [ "quarto-system-runtime", ] +[[package]] +name = "permutation" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df202b0b0f5b8e389955afd5f27b007b00fb948162953f1db9c70d2c7e3157d7" + [[package]] name = "pest" version = "2.8.6" @@ -3084,7 +7386,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -3097,6 +7399,18 @@ dependencies = [ "sha2 0.10.9", ] +[[package]] +name = "petgraph" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.5", + "indexmap 2.14.0", + "serde", +] + [[package]] name = "phf" version = "0.11.3" @@ -3107,6 +7421,15 @@ dependencies = [ "phf_shared 0.11.3", ] +[[package]] +name = "phf" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" +dependencies = [ + "phf_shared 0.12.1", +] + [[package]] name = "phf" version = "0.13.1" @@ -3118,6 +7441,16 @@ dependencies = [ "serde", ] +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", +] + [[package]] name = "phf_codegen" version = "0.13.1" @@ -3158,7 +7491,7 @@ dependencies = [ "phf_shared 0.11.3", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -3171,7 +7504,7 @@ dependencies = [ "phf_shared 0.13.1", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -3183,6 +7516,15 @@ dependencies = [ "siphasher", ] +[[package]] +name = "phf_shared" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" +dependencies = [ + "siphasher", +] + [[package]] name = "phf_shared" version = "0.13.1" @@ -3209,7 +7551,7 @@ checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -3218,6 +7560,12 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "pkcs1" version = "0.7.5" @@ -3229,6 +7577,21 @@ dependencies = [ "spki", ] +[[package]] +name = "pkcs5" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6" +dependencies = [ + "aes", + "cbc", + "der", + "pbkdf2", + "scrypt", + "sha2 0.10.9", + "spki", +] + [[package]] name = "pkcs8" version = "0.10.2" @@ -3236,6 +7599,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ "der", + "pkcs5", + "rand_core 0.6.4", "spki", ] @@ -3251,11 +7616,11 @@ version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "concurrent-queue", "hermit-abi", "pin-project-lite", - "rustix", + "rustix 1.1.4", "windows-sys 0.61.2", ] @@ -3265,6 +7630,21 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-atomic-util" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" +dependencies = [ + "portable-atomic", +] + [[package]] name = "postcard" version = "1.1.3" @@ -3283,6 +7663,8 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ + "serde_core", + "writeable", "zerovec", ] @@ -3324,7 +7706,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.117", ] [[package]] @@ -3337,31 +7719,91 @@ dependencies = [ ] [[package]] -name = "proc-macro2" -version = "1.0.106" +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.11.1", + "num-traits", + "rand 0.9.4", + "rand_chacha 0.9.0", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "prost" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042" +dependencies = [ + "heck", + "itertools 0.14.0", + "log", + "multimap", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 2.0.117", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" dependencies = [ - "unicode-ident", + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] -name = "proptest" -version = "1.11.0" +name = "prost-types" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" +checksum = "f94967dc7688f3054c7fac87473ffae4cc4c3904800e2d9f5b857246d8963b0a" dependencies = [ - "bit-set", - "bit-vec", - "bitflags 2.11.1", - "num-traits", - "rand 0.9.4", - "rand_chacha 0.9.0", - "rand_xorshift", - "regex-syntax", - "rusty-fork", - "tempfile", - "unarray", + "prost", ] [[package]] @@ -3384,7 +7826,14 @@ checksum = "ac294897a29ce07919714f9f25c11a819d75759d47eb9f3273845ffea5a5760d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", +] + +[[package]] +name = "q2-ndarray" +version = "0.1.0" +dependencies = [ + "ndarray 0.17.2 (git+https://github.com/AdaWorldAPI/ndarray.git?branch=master)", ] [[package]] @@ -3501,7 +7950,7 @@ dependencies = [ name = "quarto-config" version = "0.0.0" dependencies = [ - "indexmap", + "indexmap 2.14.0", "insta", "quarto-error-reporting", "quarto-pandoc-types", @@ -3561,7 +8010,7 @@ dependencies = [ "tracing", "uuid", "walkdir", - "which", + "which 8.0.2", "yaml-rust2", ] @@ -3601,7 +8050,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn", + "syn 2.0.117", ] [[package]] @@ -3611,7 +8060,7 @@ dependencies = [ "ariadne", "once_cell", "quarto-source-map", - "schemars", + "schemars 1.2.1", "serde", "serde_json", "thiserror 2.0.18", @@ -3661,7 +8110,7 @@ version = "0.4.1" dependencies = [ "anyhow", "automerge", - "axum", + "axum 0.8.9", "axum-jwt-auth", "base64 0.22.1", "chrono", @@ -3672,7 +8121,7 @@ dependencies = [ "futures", "hex", "hmac 0.13.0", - "http", + "http 1.4.0", "infer", "jsonwebtoken", "notify", @@ -3692,7 +8141,7 @@ dependencies = [ "tokio", "tokio-util", "tower 0.5.3", - "tower-http", + "tower-http 0.6.8", "tracing", "tracing-subscriber", "url", @@ -3769,7 +8218,7 @@ name = "quarto-pandoc-types" version = "0.0.0" dependencies = [ "hashlink", - "indexmap", + "indexmap 2.14.0", "quarto-source-map", "serde", "serde_json", @@ -3795,9 +8244,9 @@ version = "0.4.1" dependencies = [ "anyhow", "automerge", - "axum", + "axum 0.8.9", "flate2", - "http", + "http 1.4.0", "http-body-util", "include_dir", "pampa", @@ -3901,7 +8350,7 @@ dependencies = [ "tempfile", "wasm-bindgen", "wasm-bindgen-futures 0.4.58 (registry+https://github.com/rust-lang/crates.io-index)", - "which", + "which 8.0.2", ] [[package]] @@ -3937,8 +8386,8 @@ name = "quarto-trace-server" version = "0.4.1" dependencies = [ "anyhow", - "axum", - "http", + "axum 0.8.9", + "http 1.4.0", "http-body-util", "include_dir", "quarto-trace", @@ -3948,7 +8397,7 @@ dependencies = [ "thiserror 2.0.18", "tokio", "tower 0.5.3", - "tower-http", + "tower-http 0.6.8", "tracing", ] @@ -3974,7 +8423,7 @@ dependencies = [ "insta", "quarto-error-reporting", "quarto-source-map", - "quick-xml", + "quick-xml 0.39.3", "thiserror 2.0.18", ] @@ -4011,6 +8460,16 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quick-xml" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quick-xml" version = "0.39.3" @@ -4018,6 +8477,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "721da970c312655cde9b4ffe0547f20a8494866a4af5ff51f18b7c633d0c870b" dependencies = [ "memchr", + "serde", +] + +[[package]] +name = "quick-xml" +version = "0.40.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2474bd2e5029e7ccb6abb2ba48cf2383a333851dedf495901544281590c7da7f" +dependencies = [ + "memchr", + "serde", ] [[package]] @@ -4097,6 +8567,12 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.8.6" @@ -4118,6 +8594,17 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +dependencies = [ + "chacha20", + "getrandom 0.4.2", + "rand_core 0.10.1", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -4156,6 +8643,22 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_distr" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463" +dependencies = [ + "num-traits", + "rand 0.9.4", +] + [[package]] name = "rand_xorshift" version = "0.4.0" @@ -4165,6 +8668,40 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand_xoshiro" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f703f4665700daf5512dcca5f43afa6af89f09db47fb56be587f80636bda2d41" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "random_word" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e47a395bdb55442b883c89062d6bcff25dc90fa5f8369af81e0ac6d49d78cf81" +dependencies = [ + "ahash", + "brotli", + "paste", + "rand 0.9.4", + "unicase", +] + +[[package]] +name = "rangemap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68" + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rayon" version = "1.12.0" @@ -4200,6 +8737,15 @@ dependencies = [ "serde_json", ] +[[package]] +name = "redb" +version = "3.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ba239c1c1693315d3cc0e601db3b3965543afbf48c41730fdca2f069f510f4a" +dependencies = [ + "libc", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -4237,7 +8783,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -4277,12 +8823,147 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "regex-lite" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973" + [[package]] name = "regex-syntax" version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +[[package]] +name = "reqsign-aliyun-oss" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372266b4733756738eeb199a98188037d27a0989980e2600ae7ce1faf00a867d" +dependencies = [ + "anyhow", + "form_urlencoded", + "http 1.4.0", + "log", + "percent-encoding", + "reqsign-core", + "rust-ini", + "serde", + "serde_json", +] + +[[package]] +name = "reqsign-aws-v4" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75624bd8a466e37ddc0a7b6c33ac859a85347c153a916e1dd9d0b68338f74a" +dependencies = [ + "anyhow", + "bytes", + "form_urlencoded", + "hex", + "http 1.4.0", + "log", + "percent-encoding", + "quick-xml 0.40.1", + "reqsign-core", + "rust-ini", + "serde", + "serde_json", + "serde_urlencoded", + "sha1 0.11.0", +] + +[[package]] +name = "reqsign-azure-storage" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b96928e73ad984de1d99e382749d09e5dab7dd707b767974f7e40aa926b82f" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bytes", + "form_urlencoded", + "http 1.4.0", + "log", + "pem", + "percent-encoding", + "reqsign-core", + "rsa", + "serde", + "serde_json", + "sha1 0.11.0", +] + +[[package]] +name = "reqsign-core" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5fa5cb48808693614d1701fcd3db0b30fa292e0f18e122ae068b6d32eaeed3f" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bytes", + "form_urlencoded", + "futures", + "hex", + "hmac 0.13.0", + "http 1.4.0", + "jiff", + "log", + "percent-encoding", + "rsa", + "serde", + "serde_json", + "sha1 0.11.0", + "sha2 0.11.0", + "windows-sys 0.61.2", +] + +[[package]] +name = "reqsign-file-read-tokio" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a4b6f3a3fd29ffcc99a90aec585a65217783badfd73acddf847b63ae683bda9" +dependencies = [ + "anyhow", + "reqsign-core", + "tokio", +] + +[[package]] +name = "reqsign-google" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb215d0876a18b6bd9cdd380b589e5292aaa638ca15266de794b1122d898b6b2" +dependencies = [ + "form_urlencoded", + "http 1.4.0", + "log", + "percent-encoding", + "reqsign-aws-v4", + "reqsign-core", + "rsa", + "serde", + "serde_json", + "tokio", +] + +[[package]] +name = "reqsign-tencent-cos" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84110aabba799fbcd48b3abb51fbbff4749f879252e5806b6f5d0cbe0fef6abb" +dependencies = [ + "anyhow", + "http 1.4.0", + "log", + "percent-encoding", + "reqsign-core", + "serde", + "serde_json", +] + [[package]] name = "reqwest" version = "0.12.28" @@ -4296,8 +8977,8 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 1.4.0", + "http-body 1.0.1", "http-body-util", "hyper", "hyper-rustls", @@ -4306,11 +8987,13 @@ dependencies = [ "js-sys", "log", "mime", + "mime_guess", "native-tls", "percent-encoding", "pin-project-lite", "quinn", "rustls", + "rustls-native-certs 0.8.3", "rustls-pki-types", "serde", "serde_json", @@ -4319,14 +9002,16 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-rustls", + "tokio-util", "tower 0.5.3", - "tower-http", + "tower-http 0.6.8", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures 0.4.58 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-streams 0.4.2", "web-sys", - "webpki-roots", + "webpki-roots 1.0.7", ] [[package]] @@ -4340,8 +9025,8 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http", - "http-body", + "http 1.4.0", + "http-body 1.0.1", "http-body-util", "hyper", "hyper-rustls", @@ -4359,15 +9044,47 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-rustls", + "tokio-util", "tower 0.5.3", - "tower-http", + "tower-http 0.6.8", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures 0.4.58 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-streams 0.5.0", "web-sys", ] +[[package]] +name = "reqwest-middleware" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc3f1384cffa4f274dad2d4ddd73aed32fed8f786d96c6be8aa4e5fd3c3b58" +dependencies = [ + "anyhow", + "async-trait", + "http 1.4.0", + "reqwest 0.13.3", + "thiserror 2.0.18", + "tower-service", +] + +[[package]] +name = "resb" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22d392791f3c6802a1905a509e9d1a6039cbbcb5e9e00e5a6d3661f7c874f390" +dependencies = [ + "potential_utf", + "serde_core", +] + +[[package]] +name = "retain_mut" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0" + [[package]] name = "rfc6979" version = "0.4.0" @@ -4385,13 +9102,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", - "cfg-if", + "cfg-if 1.0.4", "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", ] +[[package]] +name = "roaring" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dedc5658c6ecb3bdb5ef5f3295bb9253f42dcf3fd1402c03f6b1f7659c3c4a9" +dependencies = [ + "bytemuck", + "byteorder", +] + +[[package]] +name = "robust" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e27ee8bb91ca0adcf0ecb116293afa12d393f9c2b9b9cd54d33e8078fe19839" + [[package]] name = "rsa" version = "0.9.10" @@ -4406,12 +9139,24 @@ dependencies = [ "pkcs1", "pkcs8", "rand_core 0.6.4", + "sha2 0.10.9", "signature", "spki", "subtle", "zeroize", ] +[[package]] +name = "rstar" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "421400d13ccfd26dfa5858199c30a5d76f9c54e0dba7575273025b43c5175dbb" +dependencies = [ + "heapless", + "num-traits", + "smallvec", +] + [[package]] name = "runtimelib" version = "2.0.0" @@ -4455,7 +9200,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn", + "syn 2.0.117", "walkdir", ] @@ -4463,11 +9208,31 @@ dependencies = [ name = "rust-embed-utils" version = "8.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1" +checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1" +dependencies = [ + "globset", + "sha2 0.10.9", + "walkdir", +] + +[[package]] +name = "rust-ini" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7" +dependencies = [ + "cfg-if 1.0.4", + "ordered-multimap", +] + +[[package]] +name = "rust-stemmers" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54" dependencies = [ - "globset", - "sha2 0.10.9", - "walkdir", + "serde", + "serde_derive", ] [[package]] @@ -4485,6 +9250,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.11.1", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.52.0", +] + [[package]] name = "rustix" version = "1.1.4" @@ -4494,7 +9272,7 @@ dependencies = [ "bitflags 2.11.1", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.12.1", "windows-sys 0.61.2", ] @@ -4514,16 +9292,38 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe 0.1.6", + "rustls-pemfile", + "rustls-pki-types", + "schannel", + "security-framework 2.11.1", +] + [[package]] name = "rustls-native-certs" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ - "openssl-probe", + "openssl-probe 0.2.1", "rustls-pki-types", "schannel", - "security-framework", + "security-framework 3.7.0", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", ] [[package]] @@ -4548,10 +9348,10 @@ dependencies = [ "log", "once_cell", "rustls", - "rustls-native-certs", + "rustls-native-certs 0.8.3", "rustls-platform-verifier-android", "rustls-webpki", - "security-framework", + "security-framework 3.7.0", "security-framework-sys", "webpki-root-certs", "windows-sys 0.61.2", @@ -4605,6 +9405,21 @@ version = "5.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd8d438861332c3b1ac396c77bd9cac620ea1ff347efb63c05a83d8f0a593899" +[[package]] +name = "safe-transmute" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3944826ff8fa8093089aba3acb4ef44b9446a99a16f3bf4e74af3f77d340ab7d" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + [[package]] name = "same-file" version = "1.0.6" @@ -4621,7 +9436,7 @@ source = "git+https://github.com/quarto-dev/samod.git?branch=q2#0b50c16ce686f483 dependencies = [ "async-channel", "automerge", - "axum", + "axum 0.8.9", "bytes", "chrono", "futures", @@ -4675,6 +9490,18 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + [[package]] name = "schemars" version = "1.2.1" @@ -4697,9 +9524,15 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn", + "syn 2.0.117", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -4721,6 +9554,17 @@ dependencies = [ "tendril", ] +[[package]] +name = "scrypt" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" +dependencies = [ + "pbkdf2", + "salsa20", + "sha2 0.10.9", +] + [[package]] name = "sdd" version = "4.8.6" @@ -4744,6 +9588,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.11.1", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + [[package]] name = "security-framework" version = "3.7.0" @@ -4779,7 +9636,7 @@ dependencies = [ "log", "new_debug_unreachable", "phf 0.13.1", - "phf_codegen", + "phf_codegen 0.13.1", "precomputed-hash", "rustc-hash", "servo_arc", @@ -4792,6 +9649,12 @@ version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +[[package]] +name = "seq-macro" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" + [[package]] name = "serde" version = "1.0.228" @@ -4808,7 +9671,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" dependencies = [ - "ordered-float", + "ordered-float 2.10.1", "serde", ] @@ -4829,7 +9692,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -4840,7 +9703,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -4849,7 +9712,7 @@ version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ - "indexmap", + "indexmap 2.14.0", "itoa", "memchr", "serde", @@ -4876,7 +9739,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -4891,19 +9754,80 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_v8" +version = "0.285.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26d546283b1182f61e75b598da17f3babde4b25e479a5cb3fbb39d26cb928fd" +dependencies = [ + "deno_error", + "num-bigint", + "serde", + "smallvec", + "thiserror 2.0.18", + "v8", +] + +[[package]] +name = "serde_with" +version = "3.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" +dependencies = [ + "base64 0.22.1", + "bs58", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.14.0", + "schemars 0.9.0", + "schemars 1.2.1", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "serde_yaml" version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap", + "indexmap 2.14.0", "itoa", "ryu", "serde", "unsafe-libyaml", ] +[[package]] +name = "serde_yml" +version = "0.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59e2dd588bf1597a252c3b920e0143eb99b0f76e4e082f4c92ce34fbc9e71ddd" +dependencies = [ + "indexmap 2.14.0", + "itoa", + "libyml", + "memchr", + "ryu", + "serde", + "version_check", +] + [[package]] name = "servo_arc" version = "0.4.3" @@ -4919,7 +9843,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -4930,7 +9854,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "cpufeatures 0.3.0", "digest 0.11.2", ] @@ -4947,9 +9871,10 @@ version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "cpufeatures 0.2.17", "digest 0.10.7", + "sha2-asm", ] [[package]] @@ -4958,11 +9883,20 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "cpufeatures 0.3.0", "digest 0.11.2", ] +[[package]] +name = "sha2-asm" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b845214d6175804686b2bd482bcffe96651bb2d1200742b712003504a2dac1ab" +dependencies = [ + "cc", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -4978,7 +9912,9 @@ version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32824fab5e16e6c4d86dc1ba84489390419a39f97699852b66480bb87d297ed8" dependencies = [ + "bstr", "dirs", + "os_str_bytes", ] [[package]] @@ -5108,6 +10044,54 @@ dependencies = [ "serde_core", ] +[[package]] +name = "snafu" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e84b3f4eacbf3a1ce05eac6763b4d629d60cbc94d632e4092c54ade71f1e1a2" +dependencies = [ + "snafu-derive 0.8.9", +] + +[[package]] +name = "snafu" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1a012328be2e3f5d5f6f3218147ca02588cea4cb865e876849ab6debcf36522" +dependencies = [ + "snafu-derive 0.9.1", +] + +[[package]] +name = "snafu-derive" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1c97747dbf44bb1ca44a561ece23508e99cb592e862f22222dcf42f51d1e451" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "snafu-derive" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f103c50866b8743da9429b8a581d81a27c2d3a9c4ac7df8f8571c1dd7896eda" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "snap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" + [[package]] name = "socket2" version = "0.6.3" @@ -5118,6 +10102,36 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "sourcemap" +version = "9.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "314d62a489431668f719ada776ca1d49b924db951b7450f8974c9ae51ab05ad7" +dependencies = [ + "base64-simd", + "bitvec", + "data-encoding", + "debugid", + "if_chain", + "rustc-hash", + "serde", + "serde_json", + "unicode-id-start", + "url", +] + +[[package]] +name = "spade" +version = "2.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9699399fd9349b00b184f5635b074f9ec93afffef30c853f8c875b32c0f8c7fa" +dependencies = [ + "hashbrown 0.16.1", + "num-traits", + "robust", + "smallvec", +] + [[package]] name = "spin" version = "0.9.8" @@ -5134,12 +10148,70 @@ dependencies = [ "der", ] +[[package]] +name = "sqlparser" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf5ea8d4d7c808e1af1cbabebca9a2abe603bcefc22294c5b95018d53200cb7" +dependencies = [ + "log", + "sqlparser_derive", +] + +[[package]] +name = "sqlparser_derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6dd45d8fc1c79299bfbb7190e42ccbbdf6a5f52e4a6ad98d92357ea965bd289" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "statrs" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a3fe7c28c6512e766b0874335db33c94ad7b8f9054228ae1c2abd47ce7d335e" +dependencies = [ + "approx", + "num-traits", +] + +[[package]] +name = "std_prelude" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8207e78455ffdf55661170876f88daf85356e4edd54e0a3dbc79586ca1e50cbe" + +[[package]] +name = "stfu8" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51f1e89f093f99e7432c491c382b88a6860a5adbe6bf02574bf0a08efff1978" + +[[package]] +name = "strck" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42316e70da376f3d113a68d138a60d8a9883c604fe97942721ec2068dab13a9f" +dependencies = [ + "unicode-ident", +] + [[package]] name = "streaming-iterator" version = "0.1.9" @@ -5164,17 +10236,75 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" dependencies = [ - "phf_generator 0.13.1", - "phf_shared 0.13.1", + "phf_generator 0.13.1", + "phf_shared 0.13.1", + "proc-macro2", + "quote", +] + +[[package]] +name = "stringcase" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72abeda133c49d7bddece6c154728f83eec8172380c80ab7096da9487e20d27c" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros 0.26.4", +] + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros 0.27.2", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.117", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", "proc-macro2", "quote", + "syn 2.0.117", ] [[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +name = "stubs" +version = "0.1.0" +dependencies = [ + "lance-graph", + "notebook-query", + "q2-ndarray", +] [[package]] name = "subtle" @@ -5188,6 +10318,23 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e396b6523b11ccb83120b115a0b7366de372751aa6edf19844dfb13a6af97e91" +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.117" @@ -5199,6 +10346,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn-match" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b8f0a9004d6aafa6a588602a1119e6cdaacec9921aa1605383e6e7d6258fd6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "sync_wrapper" version = "1.0.2" @@ -5216,7 +10374,41 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", +] + +[[package]] +name = "sys_traits" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88826d6169418c98e8bc52a43f79d50907dfa3e87ba5161930d42c6f980b35ee" +dependencies = [ + "sys_traits_macros", +] + +[[package]] +name = "sys_traits_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "181f22127402abcf8ee5c83ccd5b408933fec36a6095cf82cda545634692657e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "sysinfo" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ab6a2f8bfe508deb3c6406578252e491d299cbbf3bc0529ecc3313aee4a52f" +dependencies = [ + "libc", + "memchr", + "ntapi", + "objc2-core-foundation", + "objc2-io-kit", + "windows", ] [[package]] @@ -5240,6 +10432,18 @@ dependencies = [ "libc", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "target-lexicon" version = "0.13.5" @@ -5255,10 +10459,43 @@ dependencies = [ "fastrand", "getrandom 0.4.2", "once_cell", - "rustix", + "rustix 1.1.4", "windows-sys 0.61.2", ] +[[package]] +name = "temporal_capi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a151e402c2bdb6a3a2a2f3f225eddaead2e7ce7dd5d3fa2090deb11b17aa4ed8" +dependencies = [ + "diplomat", + "diplomat-runtime", + "icu_calendar", + "icu_locale", + "num-traits", + "temporal_rs", + "timezone_provider", + "writeable", + "zoneinfo64", +] + +[[package]] +name = "temporal_rs" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88afde3bd75d2fc68d77a914bece426aa08aa7649ffd0cdd4a11c3d4d33474d1" +dependencies = [ + "core_maths", + "icu_calendar", + "icu_locale", + "ixdtf", + "num-traits", + "timezone_provider", + "tinystr", + "writeable", +] + [[package]] name = "tendril" version = "0.5.0" @@ -5304,7 +10541,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5315,7 +10552,16 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", +] + +[[package]] +name = "thread-tree" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbd370cb847953a25954d9f63e14824a36113f8c72eecf6eccef5dc4b45d630" +dependencies = [ + "crossbeam-channel", ] [[package]] @@ -5324,7 +10570,18 @@ version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", +] + +[[package]] +name = "thrift" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e54bc85fc7faa8bc175c4bab5b92ba8d9a3ce893d0e9f42cc455c8ab16a9e09" +dependencies = [ + "byteorder", + "integer-encoding", + "ordered-float 2.10.1", ] [[package]] @@ -5358,6 +10615,27 @@ dependencies = [ "time-core", ] +[[package]] +name = "timezone_provider" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9ba0000e9e73862f3e7ca1ff159e2ddf915c9d8bb11e38a7874760f445d993" +dependencies = [ + "tinystr", + "zerotrie", + "zerovec", + "zoneinfo64", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinystr" version = "0.8.3" @@ -5365,6 +10643,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", + "serde_core", "zerovec", ] @@ -5408,7 +10687,7 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5421,6 +10700,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-retry" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a129d95275ebf4c493ec53bf0f8cd95f5ac161bc4f381700809a54f595d4470" +dependencies = [ + "pin-project-lite", + "rand 0.10.1", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.4" @@ -5431,6 +10721,30 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.24.0", +] + [[package]] name = "tokio-tungstenite" version = "0.27.0" @@ -5471,6 +10785,36 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +dependencies = [ + "indexmap 2.14.0", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow", +] + [[package]] name = "tower" version = "0.4.13" @@ -5501,19 +10845,49 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +dependencies = [ + "bitflags 2.11.1", + "bytes", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "http-range-header", + "httpdate", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-http" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ + "async-compression", "bitflags 2.11.1", "bytes", + "futures-core", "futures-util", - "http", - "http-body", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", "iri-string", "pin-project-lite", + "tokio", + "tokio-util", "tower 0.5.3", "tower-layer", "tower-service", @@ -5557,7 +10931,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5578,6 +10952,19 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" +dependencies = [ + "crossbeam-channel", + "symlink", + "thiserror 2.0.18", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.31" @@ -5586,7 +10973,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5610,6 +10997,16 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.23" @@ -5620,12 +11017,15 @@ dependencies = [ "nu-ansi-term", "once_cell", "regex-automata", + "serde", + "serde_json", "sharded-slab", "smallvec", "thread_local", "tracing", "tracing-core", "tracing-log", + "tracing-serde", ] [[package]] @@ -5805,6 +11205,24 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.4.0", + "httparse", + "log", + "rand 0.8.6", + "sha1 0.10.6", + "thiserror 1.0.69", + "utf-8", +] + [[package]] name = "tungstenite" version = "0.27.0" @@ -5813,7 +11231,7 @@ checksum = "eadc29d668c91fcc564941132e17b28a7ceb2f3ebf0b9dae3e03fd7a6748eb0d" dependencies = [ "bytes", "data-encoding", - "http", + "http 1.4.0", "httparse", "log", "native-tls", @@ -5831,7 +11249,7 @@ checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" dependencies = [ "bytes", "data-encoding", - "http", + "http 1.4.0", "httparse", "log", "rand 0.9.4", @@ -5839,6 +11257,15 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "twox-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" +dependencies = [ + "rand 0.9.4", +] + [[package]] name = "typed-arena" version = "2.0.2" @@ -5857,6 +11284,12 @@ version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +[[package]] +name = "typewit" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "214ca0b2191785cbc06209b9ca1861e048e39b5ba33574b3cedd58363d5bb5f6" + [[package]] name = "ucd-trie" version = "0.1.7" @@ -5869,6 +11302,18 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + +[[package]] +name = "unicode-id-start" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b79ad29b5e19de4260020f8919b443b2ef0277d242ce532ec7b7a2cc8b6007" + [[package]] name = "unicode-ident" version = "1.0.24" @@ -5927,7 +11372,7 @@ dependencies = [ "rustls-pki-types", "ureq-proto", "utf8-zero", - "webpki-roots", + "webpki-roots 1.0.7", ] [[package]] @@ -5937,7 +11382,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c" dependencies = [ "base64 0.22.1", - "http", + "http 1.4.0", "httparse", "log", ] @@ -5955,12 +11400,24 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf-8" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8-ranges" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba" + [[package]] name = "utf8-zero" version = "0.8.1" @@ -5992,6 +11449,23 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "v8" +version = "142.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f566072bd76b2631d0dca1d90a766c943863b1fd6b01312281dc919816de976d" +dependencies = [ + "bindgen", + "bitflags 2.11.1", + "fslock", + "gzip-header", + "home", + "miniz_oxide", + "paste", + "temporal_capi", + "which 6.0.3", +] + [[package]] name = "validate-yaml" version = "0.4.1" @@ -6023,6 +11497,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + [[package]] name = "wait-timeout" version = "0.2.1" @@ -6057,6 +11537,15 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + [[package]] name = "wasip2" version = "1.0.3+wasi-0.2.9" @@ -6070,9 +11559,18 @@ dependencies = [ name = "wasip3" version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasite" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fe902b4a6b8028a753d5424909b764ccf79b7a209eac9bf97e59cda9f71a42" dependencies = [ - "wit-bindgen 0.51.0", + "wasi 0.14.7+wasi-0.2.4", ] [[package]] @@ -6081,7 +11579,7 @@ version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "once_cell", "rustversion", "wasm-bindgen-macro", @@ -6092,7 +11590,7 @@ dependencies = [ name = "wasm-bindgen-futures" version = "0.4.58" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "futures-channel", "futures-core", "futures-lite", @@ -6109,7 +11607,7 @@ version = "0.4.58" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "futures-util", "js-sys", "once_cell", @@ -6136,7 +11634,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 2.0.117", "wasm-bindgen-shared", ] @@ -6176,7 +11674,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ "anyhow", - "indexmap", + "indexmap 2.14.0", "wasm-encoder 0.244.0", "wasmparser 0.244.0", ] @@ -6185,6 +11683,42 @@ dependencies = [ name = "wasm-printf-fmt" version = "0.4.1" +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures 0.4.58 (registry+https://github.com/rust-lang/crates.io-index)", + "web-sys", +] + +[[package]] +name = "wasm-streams" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures 0.4.58 (registry+https://github.com/rust-lang/crates.io-index)", + "web-sys", +] + +[[package]] +name = "wasm_dep_analyzer" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a10e6b67c951a84de7029487e0e0a496860dae49f6699edd279d5ff35b8fbf54" +dependencies = [ + "deno_error", + "thiserror 2.0.18", +] + [[package]] name = "wasmparser" version = "0.236.1" @@ -6193,7 +11727,7 @@ checksum = "a9b1e81f3eb254cf7404a82cee6926a4a3ccc5aad80cc3d43608a070c67aa1d7" dependencies = [ "bitflags 2.11.1", "hashbrown 0.15.5", - "indexmap", + "indexmap 2.14.0", "semver", "serde", ] @@ -6206,7 +11740,7 @@ checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ "bitflags 2.11.1", "hashbrown 0.15.5", - "indexmap", + "indexmap 2.14.0", "semver", ] @@ -6232,9 +11766,9 @@ dependencies = [ "bitflags 2.11.1", "bumpalo", "cc", - "cfg-if", + "cfg-if 1.0.4", "hashbrown 0.15.5", - "indexmap", + "indexmap 2.14.0", "libc", "log", "mach2", @@ -6243,7 +11777,7 @@ dependencies = [ "once_cell", "postcard", "pulley-interpreter", - "rustix", + "rustix 1.1.4", "serde", "serde_derive", "smallvec", @@ -6286,7 +11820,7 @@ dependencies = [ "cranelift-bitset", "cranelift-entity", "gimli", - "indexmap", + "indexmap 2.14.0", "log", "object", "postcard", @@ -6305,7 +11839,7 @@ version = "36.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b02cec619b54ce7652d1d7676718a42ccf5f16b2fb23c27cd6e3c307bc93907a" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", ] [[package]] @@ -6325,14 +11859,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54eb7fc20c8692dc96148365d7a00a1b79fee810833c75bdf8ec073a46e4721a" dependencies = [ "anyhow", - "cfg-if", + "cfg-if 1.0.4", "cranelift-codegen", "cranelift-control", "cranelift-entity", "cranelift-frontend", "cranelift-native", "gimli", - "itertools", + "itertools 0.14.0", "log", "object", "pulley-interpreter", @@ -6353,9 +11887,9 @@ checksum = "30708e122dcc1e175c66345c209c01752ca0cd20c9021721b6f56968342e9dbe" dependencies = [ "anyhow", "cc", - "cfg-if", + "cfg-if 1.0.4", "libc", - "rustix", + "rustix 1.1.4", "wasmtime-internal-asm-macros", "wasmtime-internal-versioned-export-macros", "windows-sys 0.60.2", @@ -6378,7 +11912,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09979561e6e4a17bf55722463b066ccb968f010ac6ec5d647e4dff19eddbb19e" dependencies = [ "anyhow", - "cfg-if", + "cfg-if 1.0.4", "libc", "windows-sys 0.60.2", ] @@ -6405,7 +11939,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e748c970993865d9bf474465c3f10f96e541c472bc8f7ec0b031779f4ac29c6" dependencies = [ "anyhow", - "cfg-if", + "cfg-if 1.0.4", "cranelift-codegen", "log", "object", @@ -6419,7 +11953,7 @@ checksum = "e97e07438cb8b50df3bc9659c56757830a15235c94268dbbd54186524fd4ed84" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -6466,7 +12000,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7cff6eef815df1834fd250e3a2ff436044d82a9f1bc1980ca1dbdf07effc538" dependencies = [ "phf 0.13.1", - "phf_codegen", + "phf_codegen 0.13.1", "string_cache", "string_cache_codegen", ] @@ -6480,6 +12014,15 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.7", +] + [[package]] name = "webpki-roots" version = "1.0.7" @@ -6489,6 +12032,18 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "which" +version = "6.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" +dependencies = [ + "either", + "home", + "rustix 0.38.44", + "winsafe", +] + [[package]] name = "which" version = "8.0.2" @@ -6498,6 +12053,19 @@ dependencies = [ "libc", ] +[[package]] +name = "whoami" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6a5b12f9df4f978d2cfdb1bd3bac52433f44393342d7ee9c25f5a1c14c0f45d" +dependencies = [ + "libc", + "libredox", + "objc2-system-configuration", + "wasite", + "web-sys", +] + [[package]] name = "win_uds" version = "0.2.2" @@ -6560,6 +12128,27 @@ dependencies = [ "wasmtime-internal-math", ] +[[package]] +name = "windows" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" +dependencies = [ + "windows-core", +] + [[package]] name = "windows-core" version = "0.62.2" @@ -6573,6 +12162,17 @@ dependencies = [ "windows-strings", ] +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core", + "windows-link", + "windows-threading", +] + [[package]] name = "windows-implement" version = "0.60.2" @@ -6581,7 +12181,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -6592,7 +12192,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -6601,6 +12201,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core", + "windows-link", +] + [[package]] name = "windows-registry" version = "0.6.1" @@ -6690,6 +12300,15 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -6786,6 +12405,21 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +[[package]] +name = "winnow" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +dependencies = [ + "memchr", +] + +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + [[package]] name = "wit-bindgen" version = "0.51.0" @@ -6820,9 +12454,9 @@ checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ "anyhow", "heck", - "indexmap", + "indexmap 2.14.0", "prettyplease", - "syn", + "syn 2.0.117", "wasm-metadata", "wit-bindgen-core", "wit-component", @@ -6838,7 +12472,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn", + "syn 2.0.117", "wit-bindgen-core", "wit-bindgen-rust", ] @@ -6851,7 +12485,7 @@ checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", "bitflags 2.11.1", - "indexmap", + "indexmap 2.14.0", "log", "serde", "serde_derive", @@ -6870,7 +12504,7 @@ checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" dependencies = [ "anyhow", "id-arena", - "indexmap", + "indexmap 2.14.0", "log", "semver", "serde", @@ -6880,12 +12514,199 @@ dependencies = [ "wasmparser 0.244.0", ] +[[package]] +name = "wkb" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a120b336c7ad17749026d50427c23d838ecb50cd64aaea6254b5030152f890a9" +dependencies = [ + "byteorder", + "geo-traits", + "num_enum", + "thiserror 1.0.69", +] + +[[package]] +name = "wkt" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efb2b923ccc882312e559ffaa832a055ba9d1ac0cc8e86b3e25453247e4b81d7" +dependencies = [ + "geo-traits", + "geo-types", + "log", + "num-traits", + "thiserror 1.0.69", +] + [[package]] name = "writeable" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "xet-client" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e1e496dcbe6a09017acdfaf48e1a646735e7ff5b2a49e2c7e081cca77a59bc8" +dependencies = [ + "anyhow", + "async-trait", + "base64 0.22.1", + "bytes", + "clap", + "crc32fast", + "futures", + "http 1.4.0", + "hyper", + "lazy_static", + "more-asserts", + "rand 0.10.1", + "redb", + "reqwest 0.13.3", + "reqwest-middleware", + "serde", + "serde_json", + "serde_repr", + "statrs", + "tempfile", + "thiserror 2.0.18", + "tokio", + "tokio-retry", + "tracing", + "tracing-subscriber", + "url", + "urlencoding", + "web-time", + "xet-core-structures", + "xet-runtime", +] + +[[package]] +name = "xet-core-structures" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb838aa8eb67d730af301584cf003caad407487606058292a6750711b603fbee" +dependencies = [ + "async-trait", + "base64 0.22.1", + "blake3", + "bytemuck", + "bytes", + "clap", + "countio", + "csv", + "futures", + "futures-util", + "getrandom 0.4.2", + "heapify", + "itertools 0.14.0", + "lazy_static", + "lz4_flex", + "more-asserts", + "rand 0.10.1", + "regex", + "safe-transmute", + "serde", + "static_assertions", + "tempfile", + "thiserror 2.0.18", + "tokio", + "tokio-util", + "tracing", + "uuid", + "web-time", + "xet-runtime", +] + +[[package]] +name = "xet-data" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67fd409bef621411a9d9013798540bb8036cb2678f03ab39af89a5e88034ed8c" +dependencies = [ + "anyhow", + "async-trait", + "bytes", + "chrono", + "clap", + "gearhash", + "http 1.4.0", + "itertools 0.14.0", + "lazy_static", + "more-asserts", + "rand 0.10.1", + "serde", + "serde_json", + "sha2 0.10.9", + "tempfile", + "thiserror 2.0.18", + "tokio", + "tokio-util", + "tracing", + "url", + "uuid", + "walkdir", + "xet-client", + "xet-core-structures", + "xet-runtime", +] + +[[package]] +name = "xet-runtime" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15d8f121c33866f7648b737abe70d0e2dd9c0af4ffdd7219207531d0283aa63d" +dependencies = [ + "anyhow", + "async-trait", + "bytes", + "chrono", + "colored", + "const-str", + "ctor", + "dirs", + "futures", + "git-version", + "humantime", + "konst", + "lazy_static", + "libc", + "more-asserts", + "oneshot", + "pin-project", + "rand 0.10.1", + "reqwest 0.13.3", + "serde", + "serde_json", + "shellexpand", + "sysinfo", + "thiserror 2.0.18", + "tokio", + "tokio-util", + "tracing", + "tracing-appender", + "tracing-subscriber", + "whoami", + "winapi", +] + +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" + [[package]] name = "xtask" version = "0.1.0" @@ -6896,12 +12717,18 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "syn", + "syn 2.0.117", "tempfile", "time", "walkdir", ] +[[package]] +name = "xxhash-rust" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" + [[package]] name = "yaml-rust2" version = "0.11.0" @@ -6938,7 +12765,7 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", "synstructure", ] @@ -6959,7 +12786,7 @@ checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -6979,7 +12806,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", "synstructure", ] @@ -7023,6 +12850,7 @@ dependencies = [ "displaydoc", "yoke", "zerofrom", + "zerovec", ] [[package]] @@ -7031,6 +12859,7 @@ version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ + "serde", "yoke", "zerofrom", "zerovec-derive", @@ -7044,11 +12873,58 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] +[[package]] +name = "zlib-rs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" + [[package]] name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zoneinfo64" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2e5597efbe7c421da8a7fd396b20b571704e787c21a272eecf35dfe9d386f0" +dependencies = [ + "calendrical_calculations", + "icu_locale_core", + "potential_utf", + "resb", + "serde", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index c10599761..945835844 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ "crates/*", + "crates/stubs/*", "crates/experiments/reconcile-viewer", ] default-members = ["crates/*", "crates/experiments/reconcile-viewer"] @@ -181,6 +182,69 @@ path = "./crates/quarto-trace" [workspace.dependencies.quarto-trace-server] path = "./crates/quarto-trace-server" +# ── AdaWorldAPI q2 fork additions: graph-notebook + Gotham GUI ── +# Re-applied onto fresh upstream after the no-shared-history resync +# (claude/q2-upstream-replant). Consumed by our additive crates +# (cockpit-server, stubs/*, aiwar-ingest, neural-debug). Per +# .claude/rules/architectural-compliance.md the lance-graph deps are the +# REAL ../lance-graph/crates/* (sibling repo), never substitutes. +[workspace.dependencies.notebook-query] +path = "./crates/stubs/notebook-query" + +[workspace.dependencies.lance-graph] +path = "../lance-graph/crates/lance-graph" +default-features = false +# ndarray-hpc required: lance-graph's vector_ops/fingerprint/hydrate call +# ndarray::hpc::* unconditionally, so the feature must be on even with +# default-features off. +features = ["ndarray-hpc"] + +[workspace.dependencies.lance-graph-planner] +path = "../lance-graph/crates/lance-graph-planner" + +[workspace.dependencies.bgz17] +path = "../lance-graph/crates/bgz17" + +[workspace.dependencies.thinking-engine] +path = "../lance-graph/crates/thinking-engine" + +[workspace.dependencies.cognitive-shader-driver] +path = "../lance-graph/crates/cognitive-shader-driver" + +[workspace.dependencies.lance-graph-contract] +path = "../lance-graph/crates/lance-graph-contract" + +[workspace.dependencies.causal-edge] +path = "../lance-graph/crates/causal-edge" + +[workspace.dependencies.graph-flow] +path = "./crates/stubs/graph-flow" + +[workspace.dependencies.q2-ndarray] +path = "./crates/stubs/q2-ndarray" + +[workspace.dependencies.axum] +version = "0.7" +features = ["ws"] + +[workspace.dependencies.tower-http] +version = "0.5" +features = ["fs", "cors"] + +[workspace.dependencies.async-stream] +version = "0.3" + +[workspace.dependencies.futures-core] +version = "0.3" + +# deno JS runtime — cockpit-server executes .qmd JS/TS cells via deno_core. +# Upstream carries no deno dependency, so these are conflict-free additions. +[workspace.dependencies.deno_core] +version = "0.376" + +[workspace.dependencies.serde_v8] +version = "0.285" + [workspace.lints.rust] # coverage_nightly is used by pampa for code coverage instrumentation on nightly Rust unexpected_cfgs = { level = "warn", check-cfg = ['cfg(coverage_nightly)'] } diff --git a/cockpit/.dockerignore b/cockpit/.dockerignore new file mode 100644 index 000000000..62b26e16f --- /dev/null +++ b/cockpit/.dockerignore @@ -0,0 +1,4 @@ +node_modules +dist +.git +*.md diff --git a/cockpit/.gitignore b/cockpit/.gitignore new file mode 100644 index 000000000..f06235c46 --- /dev/null +++ b/cockpit/.gitignore @@ -0,0 +1,2 @@ +node_modules +dist diff --git a/cockpit/index.html b/cockpit/index.html new file mode 100644 index 000000000..8ee71a3bf --- /dev/null +++ b/cockpit/index.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>q2 — Graph Notebook + + + + + +
+ + + diff --git a/cockpit/package-lock.json b/cockpit/package-lock.json new file mode 100644 index 000000000..9420989dc --- /dev/null +++ b/cockpit/package-lock.json @@ -0,0 +1,2105 @@ +{ + "name": "q2-cockpit", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "q2-cockpit", + "version": "0.1.0", + "dependencies": { + "@types/react-router-dom": "^5.3.3", + "@types/three": "^0.183.1", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-router-dom": "^7.13.2", + "three": "^0.183.2", + "vis-data": "^7.1.9", + "vis-network": "^9.1.9", + "zustand": "^5.0.5" + }, + "devDependencies": { + "@types/react": "^19.1.5", + "@types/react-dom": "^19.1.5", + "@vitejs/plugin-react": "^4.5.2", + "typescript": "^5.8.3", + "vite": "^6.3.5" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@dimforge/rapier3d-compat": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz", + "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", + "license": "Apache-2.0" + }, + "node_modules/@egjs/hammerjs": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz", + "integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/hammerjs": "^2.0.36" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.0.tgz", + "integrity": "sha512-WOhNW9K8bR3kf4zLxbfg6Pxu2ybOUbB2AjMDHSQx86LIF4rH4Ft7vmMwNt0loO0eonglSNy4cpD3MKXXKQu0/A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.0.tgz", + "integrity": "sha512-u6JHLll5QKRvjciE78bQXDmqRqNs5M/3GVqZeMwvmjaNODJih/WIrJlFVEihvV0MiYFmd+ZyPr9wxOVbPAG2Iw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.0.tgz", + "integrity": "sha512-qEF7CsKKzSRc20Ciu2Zw1wRrBz4g56F7r/vRwY430UPp/nt1x21Q/fpJ9N5l47WWvJlkNCPJz3QRVw008fi7yA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.0.tgz", + "integrity": "sha512-WADYozJ4QCnXCH4wPB+3FuGmDPoFseVCUrANmA5LWwGmC6FL14BWC7pcq+FstOZv3baGX65tZ378uT6WG8ynTw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.0.tgz", + "integrity": "sha512-6b8wGHJlDrGeSE3aH5mGNHBjA0TTkxdoNHik5EkvPHCt351XnigA4pS7Wsj/Eo9Y8RBU6f35cjN9SYmCFBtzxw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.0.tgz", + "integrity": "sha512-h25Ga0t4jaylMB8M/JKAyrvvfxGRjnPQIR8lnCayyzEjEOx2EJIlIiMbhpWxDRKGKF8jbNH01NnN663dH638mA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.0.tgz", + "integrity": "sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.0.tgz", + "integrity": "sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.0.tgz", + "integrity": "sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.0.tgz", + "integrity": "sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.0.tgz", + "integrity": "sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.0.tgz", + "integrity": "sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.0.tgz", + "integrity": "sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.0.tgz", + "integrity": "sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.0.tgz", + "integrity": "sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.0.tgz", + "integrity": "sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.0.tgz", + "integrity": "sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.0.tgz", + "integrity": "sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.0.tgz", + "integrity": "sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.0.tgz", + "integrity": "sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.0.tgz", + "integrity": "sha512-pESDkos/PDzYwtyzB5p/UoNU/8fJo68vcXM9ZW2V0kjYayj1KaaUfi1NmTUTUpMn4UhU4gTuK8gIaFO4UGuMbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.0.tgz", + "integrity": "sha512-hj1wFStD7B1YBeYmvY+lWXZ7ey73YGPcViMShYikqKT1GtstIKQAtfUI6yrzPjAy/O7pO0VLXGmUVWXQMaYgTQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.0.tgz", + "integrity": "sha512-SyaIPFoxmUPlNDq5EHkTbiKzmSEmq/gOYFI/3HHJ8iS/v1mbugVa7dXUzcJGQfoytp9DJFLhHH4U3/eTy2Bq4w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.0.tgz", + "integrity": "sha512-RdcryEfzZr+lAr5kRm2ucN9aVlCCa2QNq4hXelZxb8GG0NJSazq44Z3PCCc8wISRuCVnGs0lQJVX5Vp6fKA+IA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.0.tgz", + "integrity": "sha512-PrsWNQ8BuE00O3Xsx3ALh2Df8fAj9+cvvX9AIA6o4KpATR98c9mud4XtDWVvsEuyia5U4tVSTKygawyJkjm60w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tweenjs/tween.js": { + "version": "23.1.3", + "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", + "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==", + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hammerjs": { + "version": "2.0.46", + "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.46.tgz", + "integrity": "sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "license": "MIT", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "license": "MIT", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/stats.js": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz", + "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==", + "license": "MIT" + }, + "node_modules/@types/three": { + "version": "0.183.1", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.183.1.tgz", + "integrity": "sha512-f2Pu5Hrepfgavttdye3PsH5RWyY/AvdZQwIVhrc4uNtvF7nOWJacQKcoVJn0S4f0yYbmAE6AR+ve7xDcuYtMGw==", + "license": "MIT", + "dependencies": { + "@dimforge/rapier3d-compat": "~0.12.0", + "@tweenjs/tween.js": "~23.1.3", + "@types/stats.js": "*", + "@types/webxr": ">=0.5.17", + "@webgpu/types": "*", + "fflate": "~0.8.2", + "meshoptimizer": "~1.0.1" + } + }, + "node_modules/@types/webxr": { + "version": "0.5.24", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz", + "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@webgpu/types": { + "version": "0.1.69", + "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.69.tgz", + "integrity": "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.10", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.10.tgz", + "integrity": "sha512-sUoJ3IMxx4AyRqO4MLeHlnGDkyXRoUG0/AI9fjK+vS72ekpV0yWVY7O0BVjmBcRtkNcsAO2QDZ4tdKKGoI6YaQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001781", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001781.tgz", + "integrity": "sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/component-emitter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-2.0.0.tgz", + "integrity": "sha512-4m5s3Me2xxlVKG9PkZpQqHQR7bgpnN7joDMJ4yvVkVXngjoITG76IaZmzmywSeRTeTpc6N6r3H3+KyUurV8OYw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.322", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.322.tgz", + "integrity": "sha512-vFU34OcrvMcH66T+dYC3G4nURmgfDVewMIu6Q2urXpumAPSMmzvcn04KVVV8Opikq8Vs5nUbO/8laNhNRqSzYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "license": "MIT" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keycharm": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/keycharm/-/keycharm-0.4.0.tgz", + "integrity": "sha512-TyQTtsabOVv3MeOpR92sIKk/br9wxS+zGj4BG7CR8YbK4jM3tyIBaF0zhzeBUMx36/Q/iQLOKKOT+3jOQtemRQ==", + "license": "(Apache-2.0 OR MIT)", + "peer": true + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/meshoptimizer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-1.0.1.tgz", + "integrity": "sha512-Vix+QlA1YYT3FwmBBZ+49cE5y/b+pRrcXKqGpS5ouh33d3lSp2PoTpCw19E0cKDFWalembrHnIaZetf27a+W2g==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.2.tgz", + "integrity": "sha512-tX1Aee+ArlKQP+NIUd7SE6Li+CiGKwQtbS+FfRxPX6Pe4vHOo6nr9d++u5cwg+Z8K/x8tP+7qLmujDtfrAoUJA==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.2.tgz", + "integrity": "sha512-aR7SUORwTqAW0JDeiWF07e9SBE9qGpByR9I8kJT5h/FrBKxPMS6TiC7rmVO+gC0q52Bx7JnjWe8Z1sR9faN4YA==", + "license": "MIT", + "dependencies": { + "react-router": "7.13.2" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/rollup": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.0.tgz", + "integrity": "sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.0", + "@rollup/rollup-android-arm64": "4.60.0", + "@rollup/rollup-darwin-arm64": "4.60.0", + "@rollup/rollup-darwin-x64": "4.60.0", + "@rollup/rollup-freebsd-arm64": "4.60.0", + "@rollup/rollup-freebsd-x64": "4.60.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.0", + "@rollup/rollup-linux-arm-musleabihf": "4.60.0", + "@rollup/rollup-linux-arm64-gnu": "4.60.0", + "@rollup/rollup-linux-arm64-musl": "4.60.0", + "@rollup/rollup-linux-loong64-gnu": "4.60.0", + "@rollup/rollup-linux-loong64-musl": "4.60.0", + "@rollup/rollup-linux-ppc64-gnu": "4.60.0", + "@rollup/rollup-linux-ppc64-musl": "4.60.0", + "@rollup/rollup-linux-riscv64-gnu": "4.60.0", + "@rollup/rollup-linux-riscv64-musl": "4.60.0", + "@rollup/rollup-linux-s390x-gnu": "4.60.0", + "@rollup/rollup-linux-x64-gnu": "4.60.0", + "@rollup/rollup-linux-x64-musl": "4.60.0", + "@rollup/rollup-openbsd-x64": "4.60.0", + "@rollup/rollup-openharmony-arm64": "4.60.0", + "@rollup/rollup-win32-arm64-msvc": "4.60.0", + "@rollup/rollup-win32-ia32-msvc": "4.60.0", + "@rollup/rollup-win32-x64-gnu": "4.60.0", + "@rollup/rollup-win32-x64-msvc": "4.60.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/three": { + "version": "0.183.2", + "resolved": "https://registry.npmjs.org/three/-/three-0.183.2.tgz", + "integrity": "sha512-di3BsL2FEQ1PA7Hcvn4fyJOlxRRgFYBpMTcyOgkwJIaDOdJMebEFPA+t98EvjuljDx4hNulAGwF6KIjtwI5jgQ==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "peer": true, + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/vis-data": { + "version": "7.1.10", + "resolved": "https://registry.npmjs.org/vis-data/-/vis-data-7.1.10.tgz", + "integrity": "sha512-23juM9tdCaHTX5vyIQ7XBzsfZU0Hny+gSTwniLrfFcmw9DOm7pi3+h9iEBsoZMp5rX6KNqWwc1MF0fkAmWVuoQ==", + "license": "(Apache-2.0 OR MIT)", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/visjs" + }, + "peerDependencies": { + "uuid": "^3.4.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0", + "vis-util": "^5.0.1" + } + }, + "node_modules/vis-network": { + "version": "9.1.13", + "resolved": "https://registry.npmjs.org/vis-network/-/vis-network-9.1.13.tgz", + "integrity": "sha512-HLeHd5KZS92qzO1kC59qMh1/FWAZxMUEwUWBwDMoj6RKj/Ajkrgy/heEYo0Zc8SZNQ2J+u6omvK2+a28GX1QuQ==", + "license": "(Apache-2.0 OR MIT)", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/visjs" + }, + "peerDependencies": { + "@egjs/hammerjs": "^2.0.0", + "component-emitter": "^1.3.0 || ^2.0.0", + "keycharm": "^0.2.0 || ^0.3.0 || ^0.4.0", + "uuid": "^3.4.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0", + "vis-data": "^6.3.0 || ^7.0.0", + "vis-util": "^5.0.1" + } + }, + "node_modules/vis-util": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/vis-util/-/vis-util-5.0.7.tgz", + "integrity": "sha512-E3L03G3+trvc/X4LXvBfih3YIHcKS2WrP0XTdZefr6W6Qi/2nNCqZfe4JFfJU6DcQLm6Gxqj2Pfl+02859oL5A==", + "license": "(Apache-2.0 OR MIT)", + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/visjs" + }, + "peerDependencies": { + "@egjs/hammerjs": "^2.0.0", + "component-emitter": "^1.3.0 || ^2.0.0" + } + }, + "node_modules/vite": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/zustand": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.12.tgz", + "integrity": "sha512-i77ae3aZq4dhMlRhJVCYgMLKuSiZAaUPAct2AksxQ+gOtimhGMdXljRT21P5BNpeT4kXlLIckvkPM029OljD7g==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + } + } +} diff --git a/cockpit/package.json b/cockpit/package.json new file mode 100644 index 000000000..2f0d85438 --- /dev/null +++ b/cockpit/package.json @@ -0,0 +1,29 @@ +{ + "name": "q2-cockpit", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "@types/react-router-dom": "^5.3.3", + "@types/three": "^0.183.1", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-router-dom": "^7.13.2", + "three": "^0.183.2", + "vis-data": "^7.1.9", + "vis-network": "^9.1.9", + "zustand": "^5.0.5" + }, + "devDependencies": { + "@types/react": "^19.1.5", + "@types/react-dom": "^19.1.5", + "@vitejs/plugin-react": "^4.5.2", + "typescript": "^5.8.3", + "vite": "^6.3.5" + } +} diff --git a/cockpit/public/aiwar_graph.json b/cockpit/public/aiwar_graph.json new file mode 100644 index 000000000..8ad4f3950 --- /dev/null +++ b/cockpit/public/aiwar_graph.json @@ -0,0 +1,6387 @@ +{ + "Schema": [ + { + "currentStatus:airo": "Development", + "type": "IntelligentControlSystem", + "militaryUse": "Robot", + "civicUse": "Policing", + "MLTask": "Capture", + "MLType": "ObjectRecognition", + "purpose:vair": "AssessingRiskOfOffending", + "capacity:airo": "BiometricsBasedEmotionRecognition", + "output:airo": "Action", + "impact:vair": "PsychologicalHarm", + "stakeholder": "Nation", + "airo:type": "AISubject" + }, + { + "currentStatus:airo": "Deployment", + "type": "GenerativeModel", + "militaryUse": "Intel", + "civicUse": "AR", + "MLTask": "Store", + "MLType": "ObjectDetection", + "purpose:vair": "PredictiveMapping", + "capacity:airo": "AudioProcessing", + "output:airo": "Content", + "impact:vair": "PhysicalInjury", + "stakeholder": "TechCompany", + "airo:type": "AIDeployer" + }, + { + "currentStatus:airo": "Operation", + "type": "NarrowAI", + "militaryUse": "Command", + "civicUse": "BehaviorEvaluation", + "MLTask": "Sort", + "MLType": "FaceRecognition", + "purpose:vair": "ProducingRecommendation", + "capacity:airo": "BehaviourAnalysis", + "output:airo": "Decision", + "impact:vair": "WellbeingImpact", + "stakeholder": "DefenseCompany", + "airo:type": "AIDeveloper" + }, + { + "currentStatus:airo": "Retirement", + "type": "TrainingDatabase", + "militaryUse": "Logistics", + "civicUse": "Logistics", + "MLTask": "Recognize", + "MLType": "PatternRecognition", + "purpose:vair": "DetectingCriminalOffences", + "capacity:airo": "BiometricIdentification", + "output:airo": "Prediction", + "impact:vair": "DistortionInHumanBehavior", + "stakeholder": "Institution", + "airo:type": "AIProvider" + }, + { + "currentStatus:airo": null, + "type": "ExpertSystem", + "militaryUse": "Prediction", + "civicUse": "RecommenderSystems", + "MLTask": "Predict", + "MLType": "Ranking", + "purpose:vair": "Monitoring", + "capacity:airo": "BiometricCategorisation", + "output:airo": "Recommendation", + "impact:vair": "Overreliance", + "stakeholder": "Military", + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": "ServiceRobot", + "militaryUse": "Mapping", + "civicUse": "ConsumerTracking", + "MLTask": "Assign", + "MLType": "SortingAlgorithm", + "purpose:vair": "DetectingIndividuals", + "capacity:airo": "ComputerVision", + "output:airo": null, + "impact:vair": null, + "stakeholder": "Police", + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": "MultiAgentSystem", + "militaryUse": "Personnel", + "civicUse": "Games", + "MLTask": "Generate", + "MLType": "Classification", + "purpose:vair": "DetectingLies", + "capacity:airo": "DialectRecognition", + "output:airo": null, + "impact:vair": null, + "stakeholder": "Company", + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": "Dashboard", + "militaryUse": "Intelligence", + "civicUse": "SocialWelfareSystems", + "MLTask": "Automate", + "MLType": "SignalAnalysis", + "purpose:vair": "PerformingBackgroundChecks", + "capacity:airo": "EmotionRecognition", + "output:airo": null, + "impact:vair": null, + "stakeholder": "Investor", + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": "Nation", + "militaryUse": "Operations", + "civicUse": "Security", + "MLTask": null, + "MLType": "DecisionTree", + "purpose:vair": "IdentifyingIndividuals", + "capacity:airo": "FaceRecognition", + "output:airo": null, + "impact:vair": null, + "stakeholder": "Untility", + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": "TechCompany", + "militaryUse": "Logistics", + "civicUse": "Marketing", + "MLTask": null, + "MLType": "ComputerVision", + "purpose:vair": "RecognizingIndividuals", + "capacity:airo": null, + "output:airo": null, + "impact:vair": null, + "stakeholder": "Owner", + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": "DefenseCompany", + "militaryUse": "Planning", + "civicUse": "Advertising", + "MLTask": null, + "MLType": "Recommendation", + "purpose:vair": "RemoteIdentification", + "capacity:airo": "Geolocation", + "output:airo": null, + "impact:vair": null, + "stakeholder": "CEO", + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": "Military", + "militaryUse": "Communications", + "civicUse": "Robot", + "MLTask": null, + "MLType": "SignalAnalysis", + "purpose:vair": "EvaluatingJobCandidates", + "capacity:airo": "GestureRecognition", + "output:airo": null, + "impact:vair": null, + "stakeholder": "Politician", + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": "Investor", + "militaryUse": "Command", + "civicUse": "Delivery", + "MLTask": null, + "MLType": "DecisionTree", + "purpose:vair": "EvaluatingEmployeePerformance", + "capacity:airo": "ImageGeneration", + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": "Institution", + "militaryUse": null, + "civicUse": "CrowdControl", + "MLTask": null, + "MLType": "PoseEstimation", + "purpose:vair": "AssessingPeopleRelatedRisk", + "capacity:airo": "InformationRetrieval", + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": "Utility", + "militaryUse": null, + "civicUse": "PrivateSecurity", + "MLTask": null, + "MLType": "SpatialReasoning", + "purpose:vair": null, + "capacity:airo": "LieDetection", + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": null, + "militaryUse": null, + "civicUse": "BorderPatrol", + "MLTask": null, + "MLType": "TemporalReasoning", + "purpose:vair": null, + "capacity:airo": "NamedEntityRecognition", + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": null, + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "MLType": "CommonSenseReasoning", + "purpose:vair": null, + "capacity:airo": "ObjectDetection", + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": null, + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "MLType": "PolicyReasoning", + "purpose:vair": null, + "capacity:airo": "ObjectRecognition", + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": null, + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "MLType": "SpeechSynthesis", + "purpose:vair": null, + "capacity:airo": "PoseEstimation", + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": null, + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "MLType": "SpeechAnalysis", + "purpose:vair": null, + "capacity:airo": "Profiling", + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": null, + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "MLType": "VoiceRecognition", + "purpose:vair": null, + "capacity:airo": "SignalTracking", + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": null, + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "MLType": "TextAnalysis", + "purpose:vair": null, + "capacity:airo": "RelationshipExtraction", + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": null, + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "MLType": "TextGeneration", + "purpose:vair": null, + "capacity:airo": "SensitiveAttributeInference", + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": null, + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "MLType": "ImageGeneration", + "purpose:vair": null, + "capacity:airo": "SentimentAnalysis", + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": null, + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "MLType": "Photogrammetry", + "purpose:vair": null, + "capacity:airo": null, + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": null, + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "MLType": "TransformerModel", + "purpose:vair": null, + "capacity:airo": null, + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": null, + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "MLType": "Clustering", + "purpose:vair": null, + "capacity:airo": null, + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": null, + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "MLType": "SentimentAnalysis", + "purpose:vair": null, + "capacity:airo": null, + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": null, + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "MLType": "SignalTracking", + "purpose:vair": null, + "capacity:airo": null, + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": null, + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "MLType": "KnowledgeBase", + "purpose:vair": null, + "capacity:airo": null, + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + }, + { + "currentStatus:airo": null, + "type": null, + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "MLType": "InformationRetrieval", + "purpose:vair": null, + "capacity:airo": null, + "output:airo": null, + "impact:vair": null, + "stakeholder": null, + "airo:type": null + } + ], + "N_Systems": [ + { + "id": "LargeGeospatialModels", + "name": "Large Geospatial Models", + "year": 2025, + "currentStatus": "Development", + "type": "GenerativeAI", + "MLTask": "Generate", + "militaryUse": "Intelligence", + "civicUse": "AR, Games", + "MLTasks": "imageGeneration, Photogrammetry, TransformerModel", + "purpose": "PredictiveMapping", + "capacity": "ImageGeneration", + "vair:technique": "DeepLearning", + "output": "Content", + "vair:riskSources": "InaccuratePrediction, BiasedTrainingData,", + "impact": "PhysicalInjury, Overreliance, DistortionInHumanBehavior", + "hover": "name: Large Geospatial Models; year: 2025; task: GenerativeAI; AI type: Generate; Military use: Intelligence; Civic use: AR, Games", + "image": "./assets/noun-photogrammetry-4284363.png", + "nounKey": "terrainMapping", + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "PolygraphPlus", + "name": "Polygraph+", + "year": 2024, + "currentStatus": "Development", + "type": "BehaviorModeling, AnomalyDetection, ComputerVision, VoiceRecognition, IoT", + "MLTask": "Recognize", + "militaryUse": "Intelligence", + "civicUse": "BehaviorEvaluation", + "MLTasks": "SignalAnalysis", + "purpose": "DetectingLies, DetectingCriminalOffences, AssessingRiskOfOffending, AssessingPeopleRelatedRisk, EvaluatingEmployeePerformance, EvaluatingJobCandidates, ProducingRecommendation", + "capacity": "LieDetection, BehaviourAnalysis, BiometricsBasedEmotionRecognition, BiometricCategorisation, EmotionRecognition, GestureRecognition, Profiling,", + "vair:technique": "SemiUnsupervisedLearning, StatisticalTechnique", + "output": "Decision", + "vair:riskSources": null, + "impact": "WellbeingImpact, PsychologicalHarm", + "hover": "name: Polygraph+; year: 2024; task: BehaviorModeling, AnomalyDetection, ComputerVision, VoiceRecognition, IoT; AI type: Recognize; Military use: Intelligence; Civic use: BehaviorEvaluation", + "image": "./assets/noun-neurofeedback-7447387.png", + "nounKey": "neurofeedback", + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Lavender", + "name": "Lavender", + "year": 2023, + "currentStatus": "Operation", + "type": "RecommendationSystem, PredictiveAnalytics, BehaviorModeling", + "MLTask": "Predict", + "militaryUse": "Intelligence", + "civicUse": "RecommenderSystem", + "MLTasks": "Ranking, Recommendation", + "purpose": "ProducingRecommendation", + "capacity": "Profiling, InformationRetrieval, NamedEntityRecognition, RelationshipExtraction, SensitiveAttributeInference, SentimentAnalysis", + "vair:technique": "LanguageModels", + "output": "Recommendation", + "vair:riskSources": "InaccurateRecommendation, BiasedTrainingData, ErrorInDataCollection, ErrorInDataPreparation, WrongDataDesignChoice, LowAccuracy", + "impact": "PhysicalInjury, WellbeingImpact, PsychologicalHarm", + "hover": "name: Lavender; year: 2023; task: RecommendationSystem, PredictiveAnalytics, BehaviorModeling; AI type: Predict; Military use: Intelligence; Civic use: RecommenderSystem", + "image": "./assets/noun-target-7619584.png", + "nounKey": "ml", + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "WheresDaddy", + "name": "Where's Daddy", + "year": 2023, + "currentStatus": "Operation", + "type": "LocationAwareness", + "MLTask": "Predict", + "militaryUse": "Command", + "civicUse": "Logistics, Delivery, Advertising", + "MLTasks": "PatternRecognition, DataSynthesis, SignalAnalysis, TextAnalysis,", + "purpose": "ProducingRecommendation, DetectingIndividuals", + "capacity": "Geolocation, ComputerVision, ObjectRecognition, SignalTracking", + "vair:technique": null, + "output": "Prediction", + "vair:riskSources": "InaccurateRecommendation, BiasedTrainingData, ErrorInDataCollection, ErrorInDataPreparation, WrongDataDesignChoice, LowAccuracy", + "impact": "PhysicalInjury, WellbeingImpact, PsychologicalHarm", + "hover": "name: Where's Daddy; year: 2023; task: LocationAwareness; AI type: Predict; Military use: Command; Civic use: Logistics, Delivery, Advertising", + "image": "./assets/noun-infrared-drone-4284335.png", + "nounKey": "locationTracking", + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "LegionX", + "name": "LegionX", + "year": 2022, + "currentStatus": "Operation", + "type": "Robotics/Navigation, MultiAgentSystem", + "MLTask": "Automate", + "militaryUse": "Operations, Intelligence", + "civicUse": "Policing, CrowdControl, PrivateSecurity, BehaviorEvaluation", + "MLTasks": "PatternRecognition, ObjectRecognition, PoseEstimation", + "purpose": "ProducingRecommendation, DetectingIndividuals", + "capacity": "ObjectDetection, PoseEstimation, Geolocation", + "vair:technique": null, + "output": "Action, Decision", + "vair:riskSources": null, + "impact": "PhysicalInjury, Overreliance, DistortionInHumanBehavior", + "hover": "name: LegionX; year: 2022; task: Robotics/Navigation, MultiAgentSystem; AI type: Automate; Military use: Operations, Intelligence; Civic use: Policing, CrowdControl, PrivateSecurity, BehaviorEvaluation", + "image": "./assets/noun-drone-strike-75130.png", + "nounKey": "poseRecognition", + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "WolfPack", + "name": "Wolf Pack", + "year": 2018, + "currentStatus": "Operation", + "type": "DataManagement", + "MLTask": "Store", + "militaryUse": "Logistics", + "civicUse": "ConsumerTracking, Marketing, Security, SocialWelfareSystems", + "MLTasks": null, + "purpose": "Monitoring, PerformingBackgroundChecks, RecognizingIndividuals", + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": "PhysicalInjury, WellbeingImpact, PsychologicalHarm, Overreliance, DistortionInHumanBehavior", + "hover": "name: Wolf Pack; year: 2018; task: DataManagement; AI type: Store; Military use: Logistics; Civic use: ConsumerTracking, Marketing, Security, SocialWelfareSystems", + "image": "./assets/noun-ai-training-data-2985134.png", + "nounKey": "trainingData", + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "AIP", + "name": "Artificial Intelligence Platform", + "year": 2022, + "currentStatus": "Operation", + "type": "NLP, GenerativeAI", + "MLTask": "Generate", + "militaryUse": "Command", + "civicUse": "Dashboard, ProjectManagement", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": "Action, Content, Decision, Prediction, Recommendation", + "vair:riskSources": null, + "impact": null, + "hover": "name: Artificial Intelligence Platform; year: 2022; task: NLP, GenerativeAI; AI type: Generate; Military use: Command; Civic use: Dashboard, ProjectManagement", + "image": "./assets/noun-surveillance-monitor-6831349.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "MetaConstellation", + "name": "Meta Constellation", + "year": 2022, + "currentStatus": "Operation", + "type": "PlanningSystem, MultiAgentSystem, RecommenderSystem", + "MLTask": "Assign", + "militaryUse": "Intelligence", + "civicUse": "Dashboard, SupplyChainManagement", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Meta Constellation; year: 2022; task: PlanningSystem, MultiAgentSystem, RecommenderSystem; AI type: Assign; Military use: Intelligence; Civic use: Dashboard, SupplyChainManagement", + "image": "./assets/noun-remote-team-6432341.png", + "nounKey": "locationTracking", + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Clearview", + "name": "Clearview", + "year": 2022, + "currentStatus": "Operation", + "type": "FacialRecognition; ComputerVision", + "MLTask": "Recognize", + "militaryUse": "Intelligence", + "civicUse": "IdentityVerification, AppUnlocking, AccessGranting", + "MLTasks": null, + "purpose": "IdentifyingIndividuals, RecognizingIndividuals, RemoteIdentification", + "capacity": "FaceRecognition", + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Clearview; year: 2022; task: FacialRecognition; ComputerVision; AI type: Recognize; Military use: Intelligence; Civic use: IdentityVerification, AppUnlocking, AccessGranting", + "image": "./assets/noun-facial-recognition-4116350.png", + "nounKey": "faceRecognition", + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Wolly", + "name": "Wolly", + "year": 2022, + "currentStatus": "Operation", + "type": "Robotics/Navigation, ComputerVision, RecommenderSystem", + "MLTask": "Automate", + "militaryUse": "Operations", + "civicUse": "Policing, CrowdControl, PrivateSecurity", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Wolly; year: 2022; task: Robotics/Navigation, ComputerVision, RecommenderSystem; AI type: Automate; Military use: Operations; Civic use: Policing, CrowdControl, PrivateSecurity", + "image": "./assets/noun-turret-6749967.png", + "nounKey": "robotPolicing", + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "FirstPOVDrones", + "name": "First Person View Drones", + "year": 2022, + "currentStatus": "Operation", + "type": "Robotics/Navigation", + "MLTask": "Automate", + "militaryUse": "Operations", + "civicUse": "Policing, Surveillance", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: First Person View Drones; year: 2022; task: Robotics/Navigation; AI type: Automate; Military use: Operations; Civic use: Policing, Surveillance", + "image": "./assets/noun-drone-strike-75130.png", + "nounKey": "uav", + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "MAPLE", + "name": "MAPLE", + "year": 2022, + "currentStatus": "Operation", + "type": "IntelligentControlSystem, Simulation", + "MLTask": "Assign", + "militaryUse": "Command", + "civicUse": "Logistics, Delivery, SupplyChainManagement", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: MAPLE; year: 2022; task: IntelligentControlSystem, Simulation; AI type: Assign; Military use: Command; Civic use: Logistics, Delivery, SupplyChainManagement", + "image": "./assets/noun-surveillance-monitor-6831349.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Gospel", + "name": "The Gospel", + "year": 2021, + "currentStatus": "Operation", + "type": "ExpertSystem, Classification", + "MLTask": "Sort", + "militaryUse": "Command", + "civicUse": "ConsumerTracking, Security, SocialWelfareSystems", + "MLTasks": "Automate", + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: The Gospel; year: 2021; task: ExpertSystem, Classification; AI type: Sort; Military use: Command; Civic use: ConsumerTracking, Security, SocialWelfareSystems", + "image": "./assets/noun-earthquake-damage-6326583.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Alchemist", + "name": "Alchemist", + "year": 2021, + "currentStatus": "Operation", + "type": "LocationAwareness, AnomalyDetection", + "MLTask": "Recognize", + "militaryUse": "Operations, Intelligence", + "civicUse": "Policing, Security, BorderPatrol", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": "realTime", + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Alchemist; year: 2021; task: LocationAwareness, AnomalyDetection; AI type: Recognize; Military use: Operations, Intelligence; Civic use: Policing, Security, BorderPatrol", + "image": "./assets/noun-mobile-tracking-5477710.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Nimbus", + "name": "Project Nimbus", + "year": 2021, + "currentStatus": "Operation", + "type": "DataManagement", + "MLTask": "Store", + "militaryUse": "Logistics", + "civicUse": "CloudComputing", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Project Nimbus; year: 2021; task: DataManagement; AI type: Store; Military use: Logistics; Civic use: CloudComputing", + "image": "./assets/noun-data-center-2301592.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "ARCA", + "name": "Assault Rifle Combat Application System", + "year": 2021, + "currentStatus": "Operation", + "type": "Robotics/Navigation, ComputerVision, BehaviorModeling", + "MLTask": "Automate", + "militaryUse": "Operations", + "civicUse": "Policing, CrowdControl, PrivateSecurity", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Assault Rifle Combat Application System; year: 2021; task: Robotics/Navigation, ComputerVision, BehaviorModeling; AI type: Automate; Military use: Operations; Civic use: Policing, CrowdControl, PrivateSecurity", + "image": "./assets/noun-target-7619584.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "LAW", + "name": "Lethal Autonomous Weapons", + "year": 2021, + "currentStatus": "Operation", + "type": "Robotics/Navigation, IntelligentControlSystem", + "MLTask": "Automate", + "militaryUse": "Operations", + "civicUse": "Policing, CrowdControl, PrivateSecurity", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Lethal Autonomous Weapons; year: 2021; task: Robotics/Navigation, IntelligentControlSystem; AI type: Automate; Military use: Operations; Civic use: Policing, CrowdControl, PrivateSecurity", + "image": "./assets/noun-infrared-drone-4284335.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Gotham", + "name": "Gotham", + "year": 2021, + "currentStatus": "Operation", + "type": "DataManagement, AnomalyDetection, BehaviorModeling", + "MLTask": "Recognize", + "militaryUse": "Command, Logistics, Operations", + "civicUse": "Dashboard, ProjectManagement", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Gotham; year: 2021; task: DataManagement, AnomalyDetection, BehaviorModeling; AI type: Recognize; Military use: Command, Logistics, Operations; Civic use: Dashboard, ProjectManagement", + "image": "./assets/noun-missile-launcher-2052140.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "JEDI", + "name": "JEDI", + "year": 2021, + "currentStatus": "Operation", + "type": "DataManagement", + "MLTask": "Store", + "militaryUse": "Logistics", + "civicUse": "CloudComputing, EdgeComputing", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: JEDI; year: 2021; task: DataManagement; AI type: Store; Military use: Logistics; Civic use: CloudComputing, EdgeComputing", + "image": "./assets/noun-locked-cloud-5565062.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "FireWeaver", + "name": "Fire Weaver", + "year": 2020, + "currentStatus": "Operation", + "type": "MultiAgentSystem, PlanningSystem, RecommenderSystem", + "MLTask": "Assign", + "militaryUse": "Command", + "civicUse": "Unknown", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": "Action", + "vair:riskSources": null, + "impact": null, + "hover": "name: Fire Weaver; year: 2020; task: MultiAgentSystem, PlanningSystem, RecommenderSystem; AI type: Assign; Military use: Command; Civic use: Unknown", + "image": "./assets/noun-virtual-headset-7137401.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "FireFactory", + "name": "Fire Factory", + "year": 2020, + "currentStatus": "Operation", + "type": "Robotics/Navigation, IntelligentControlSystem", + "MLTask": "Automate", + "militaryUse": "Operations", + "civicUse": "Unknown", + "MLTasks": "Prediction", + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Fire Factory; year: 2020; task: Robotics/Navigation, IntelligentControlSystem; AI type: Automate; Military use: Operations; Civic use: Unknown", + "image": "./assets/noun-missile-launcher-2052140.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "DIAS", + "name": "Dialect Recognition Assistant (DIAS)", + "year": 2019, + "currentStatus": "Operation", + "type": "NLP", + "MLTask": "Sort", + "militaryUse": "Intelligence", + "civicUse": "IdentityVerification", + "MLTasks": null, + "purpose": null, + "capacity": "AudioProcessing, DialectRecognition", + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Dialect Recognition Assistant (DIAS); year: 2019; task: NLP; AI type: Sort; Military use: Intelligence; Civic use: IdentityVerification", + "image": "./assets/noun-speech-recognition-1870316.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "AFRS", + "name": "Automated Facial Recognition System", + "year": 2019, + "currentStatus": "Operation", + "type": "FacialRecognition; ComputerVision", + "MLTask": "Recognize", + "militaryUse": "Intelligence", + "civicUse": "IdentityVerification, AppUnlocking, AccessGranting", + "MLTasks": null, + "purpose": null, + "capacity": "FaceRecognition", + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Automated Facial Recognition System; year: 2019; task: FacialRecognition; ComputerVision; AI type: Recognize; Military use: Intelligence; Civic use: IdentityVerification, AppUnlocking, AccessGranting", + "image": "./assets/noun-facial-recognition-4116350.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Starshield", + "name": "Starshield", + "year": 2024, + "currentStatus": "Operation", + "type": "IoT, LocationAwareness", + "MLTask": "Capture", + "militaryUse": "Intelligence", + "civicUse": "InternetAccess, DataDistribution, SecureTransmission", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Starshield; year: 2024; task: IoT, LocationAwareness; AI type: Capture; Military use: Intelligence; Civic use: InternetAccess, DataDistribution, SecureTransmission", + "image": "./assets/noun-satelite-5565092.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Starlink", + "name": "Starlink", + "year": 2019, + "currentStatus": "Operation", + "type": "IoT, LocationAwareness", + "MLTask": "Capture", + "militaryUse": "Intelligence", + "civicUse": "InternetAccess, DataDistribution", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Starlink; year: 2019; task: IoT, LocationAwareness; AI type: Capture; Military use: Intelligence; Civic use: InternetAccess, DataDistribution", + "image": "./assets/noun-satelite-5565092.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Pantir-SM", + "name": "Pantir-SM", + "year": 2019, + "currentStatus": "Operation", + "type": "Robotics/Navigation, IntelligentControlSystem, Classification", + "MLTask": "Automate", + "militaryUse": "Operations", + "civicUse": "Policing, CrowdControl, PrivateSecurity", + "MLTasks": "Classification", + "purpose": null, + "capacity": null, + "vair:technique": "Classification", + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Pantir-SM; year: 2019; task: Robotics/Navigation, IntelligentControlSystem, Classification; AI type: Automate; Military use: Operations; Civic use: Policing, CrowdControl, PrivateSecurity", + "image": "./assets/noun-classification-6860055.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "RedWolf", + "name": "Red Wolf", + "year": 2019, + "currentStatus": "Operation", + "type": "FacialRecognition, ComputerVision", + "MLTask": "Recognize", + "militaryUse": "Operations", + "civicUse": "IdentityVerification, Security, Policing", + "MLTasks": "Classification", + "purpose": null, + "capacity": "FaceRecognition", + "vair:technique": "FaceRecognition", + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Red Wolf; year: 2019; task: FacialRecognition, ComputerVision; AI type: Recognize; Military use: Operations; Civic use: IdentityVerification, Security, Policing", + "image": "./assets/noun-facial-recognition-4116350.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "BlueWolf", + "name": "BlueWolf", + "year": 2018, + "currentStatus": "Operation", + "type": "FacialRecognition, ComputerVision", + "MLTask": "Recognize", + "militaryUse": "Operations", + "civicUse": "IdentityVerification, Security, Policing", + "MLTasks": "Classification", + "purpose": null, + "capacity": "FaceRecognition", + "vair:technique": "FaceRecognition", + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: BlueWolf; year: 2018; task: FacialRecognition, ComputerVision; AI type: Recognize; Military use: Operations; Civic use: IdentityVerification, Security, Policing", + "image": "./assets/noun-face-id-scan-1890640.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Mabat2000", + "name": "Mabat 2000", + "year": 2018, + "currentStatus": "Operation", + "type": "ComputerVision", + "MLTask": "Capture", + "militaryUse": "Intelligence", + "civicUse": "Surveillance, Policing", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Mabat 2000; year: 2018; task: ComputerVision; AI type: Capture; Military use: Intelligence; Civic use: Surveillance, Policing", + "image": "./assets/noun-cctv-5477699.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "URSA", + "name": "URSA", + "year": 2018, + "currentStatus": "Retirement", + "type": "LocationAwareness", + "MLTask": "Recognize", + "militaryUse": "Operations", + "civicUse": "Retired", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: URSA; year: 2018; task: LocationAwareness; AI type: Recognize; Military use: Operations; Civic use: Retired", + "image": "./assets/noun-data-science-6432260.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "TacNet", + "name": "TacNet", + "year": 2017, + "currentStatus": "Operation", + "type": "MultiAgentSystem, PlanningSystem, RecommenderSystem", + "MLTask": "Assign", + "militaryUse": "Command", + "civicUse": "Policing, CrowdControl, PrivateSecurity", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: TacNet; year: 2017; task: MultiAgentSystem, PlanningSystem, RecommenderSystem; AI type: Assign; Military use: Command; Civic use: Policing, CrowdControl, PrivateSecurity", + "image": "./assets/noun-surveillance-monitor-6831349.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Bylina", + "name": "Bylina", + "year": 2017, + "currentStatus": "Operation", + "type": "PredictiveAnalytics", + "MLTask": "Predict", + "militaryUse": "Command", + "civicUse": "Unknown", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Bylina; year: 2017; task: PredictiveAnalytics; AI type: Predict; Military use: Command; Civic use: Unknown", + "image": "./assets/noun-earthquake-damage-6326583.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Maven", + "name": "Maven Smart System", + "year": 2016, + "currentStatus": "Operation", + "type": "ComputerVision", + "MLTask": "Recognize", + "militaryUse": "Intelligence", + "civicUse": "Policing, Security, BorderPatrol, ScientificResearch", + "MLTasks": "ObjectDetection", + "purpose": null, + "capacity": "ObjectDetection", + "vair:technique": "ObjectDetection", + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Maven Smart System; year: 2016; task: ComputerVision; AI type: Recognize; Military use: Intelligence; Civic use: Policing, Security, BorderPatrol, ScientificResearch", + "image": "./assets/noun-object-recognition-6963419.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "PackBot", + "name": "PackBot", + "year": 2016, + "currentStatus": "Operation", + "type": "Robotics/Navigation", + "MLTask": "Automate", + "militaryUse": "Operations", + "civicUse": "SmartHome, Security", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: PackBot; year: 2016; task: Robotics/Navigation; AI type: Automate; Military use: Operations; Civic use: SmartHome, Security", + "image": "./assets/noun-bomb-defusing-robot-1036305.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "GISArta", + "name": "GIS Arta", + "year": 2014, + "currentStatus": "Operation", + "type": "PlanningSystem, MultiAgentSystem, RecommenderSystem", + "MLTask": "Assign", + "militaryUse": "Logistics", + "civicUse": "VehicleTasking, Logistics", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": "dispatch", + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: GIS Arta; year: 2014; task: PlanningSystem, MultiAgentSystem, RecommenderSystem; AI type: Assign; Military use: Logistics; Civic use: VehicleTasking, Logistics", + "image": "./assets/noun-threat-7566001.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "IrisGuard", + "name": "IrisGuard", + "year": 2013, + "currentStatus": "Operation", + "type": "ComputerVision", + "MLTask": "Recognize", + "militaryUse": "Intelligence", + "civicUse": "IdentityVerification, AppUnlocking, AccessGranting", + "MLTasks": null, + "purpose": null, + "capacity": "BiometricIdentification", + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: IrisGuard; year: 2013; task: ComputerVision; AI type: Recognize; Military use: Intelligence; Civic use: IdentityVerification, AppUnlocking, AccessGranting", + "image": "./assets/noun-iris-recognition-6831344.png", + "nounKey": "biometric", + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Skynet-US", + "name": "Skynet-US", + "year": 2012, + "currentStatus": "Operation", + "type": "AnomalyDetection, MultiAgentSystem, BehaviorModeling, RecommenderSystem", + "MLTask": "Predict", + "militaryUse": "Intelligence", + "civicUse": "DataBrokers, Marketing, BehaviorEvaluation", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Skynet-US; year: 2012; task: AnomalyDetection, MultiAgentSystem, BehaviorModeling, RecommenderSystem; AI type: Predict; Military use: Intelligence; Civic use: DataBrokers, Marketing, BehaviorEvaluation", + "image": "./assets/noun-digital-footprint-6806678.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "RobotRiotControl", + "name": "Robot Riot Control", + "year": 2011, + "currentStatus": "Operation", + "type": "AnomalyDetection, LocationAwareness, BehaviorModeling", + "MLTask": "Recognize", + "militaryUse": "Intelligence", + "civicUse": "Policing, Security, BorderPatrol", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Robot Riot Control; year: 2011; task: AnomalyDetection, LocationAwareness, BehaviorModeling; AI type: Recognize; Military use: Intelligence; Civic use: Policing, Security, BorderPatrol", + "image": "./assets/noun-riot-control-national-guards-1584300.png", + "nounKey": "police", + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "PrisonGuard", + "name": "Prison Guard", + "year": 2011, + "currentStatus": "Operation", + "type": "AnomalyDetection, LocationAwareness, BehaviorModeling", + "MLTask": "Recognize", + "militaryUse": "Intelligence", + "civicUse": "Policing, Security, BorderPatrol", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Prison Guard; year: 2011; task: AnomalyDetection, LocationAwareness, BehaviorModeling; AI type: Recognize; Military use: Intelligence; Civic use: Policing, Security, BorderPatrol", + "image": "./assets/noun-police-robot-1119907.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Pegasus", + "name": "Pegasus", + "year": 2011, + "currentStatus": "Operation", + "type": "AnomalyDetection, BehaviorModeling", + "MLTask": "Capture", + "militaryUse": "Intelligence", + "civicUse": "BehaviorEvaluation, Surveillance", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Pegasus; year: 2011; task: AnomalyDetection, BehaviorModeling; AI type: Capture; Military use: Intelligence; Civic use: BehaviorEvaluation, Surveillance", + "image": "./assets/noun-digital-footprint-6806678.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "SentryTech", + "name": "Sentry-Tech", + "year": 2010, + "currentStatus": "Operation", + "type": "Robotics/Navigation, IntelligentControlSystem", + "MLTask": "Automate", + "militaryUse": "Operations", + "civicUse": "Policing, Security, BorderPatrol", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Sentry-Tech; year: 2010; task: Robotics/Navigation, IntelligentControlSystem; AI type: Automate; Military use: Operations; Civic use: Policing, Security, BorderPatrol", + "image": "./assets/noun-turret-6749967.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "SuperAegis", + "name": "Super Aegis", + "year": 2010, + "currentStatus": "Operation", + "type": "Robotics/Navigation, IntelligentControlSystem", + "MLTask": "Automate", + "militaryUse": "Operations", + "civicUse": "Policing, Security, BorderPatrol", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Super Aegis; year: 2010; task: Robotics/Navigation, IntelligentControlSystem; AI type: Automate; Military use: Operations; Civic use: Policing, Security, BorderPatrol", + "image": "./assets/noun-turret-6749967.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "SentryRobot", + "name": "Sentry Robot", + "year": 2010, + "currentStatus": "Operation", + "type": "Robotics/Navigation, IntelligentControlSystem", + "MLTask": "Automate", + "militaryUse": "Operations", + "civicUse": "Policing, Security, BorderPatrol", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Sentry Robot; year: 2010; task: Robotics/Navigation, IntelligentControlSystem; AI type: Automate; Military use: Operations; Civic use: Policing, Security, BorderPatrol", + "image": "./assets/noun-turret-6749967.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "PRISM", + "name": "PRISM/XKEYSCORE", + "year": 2007, + "currentStatus": "Retirement", + "type": "DataManagement, AnomalyDetection", + "MLTask": "Capture, Store", + "militaryUse": "Intelligence", + "civicUse": "BehaviorEvaluation, Surveillance, Marketing, DataBrokers", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: PRISM/XKEYSCORE; year: 2007; task: DataManagement, AnomalyDetection; AI type: Capture, Store; Military use: Intelligence; Civic use: BehaviorEvaluation, Surveillance, Marketing, DataBrokers", + "image": "./assets/noun-digital-footprint-6806678.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "DynaSpeak", + "name": "DynaSpeak", + "year": 2006, + "currentStatus": "Retirement", + "type": "NLP", + "MLTask": "Recognize", + "militaryUse": "Intelligence", + "civicUse": "NaturalLanguageProcessing, TranslationApps", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: DynaSpeak; year: 2006; task: NLP; AI type: Recognize; Military use: Intelligence; Civic use: NaturalLanguageProcessing, TranslationApps", + "image": "./assets/noun-speech-recognition-1870316.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "CALO", + "name": "CALO", + "year": 2003, + "currentStatus": "Retirement", + "type": "Agent", + "MLTask": "Generate", + "militaryUse": "Command", + "civicUse": "AIAssistants", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: CALO; year: 2003; task: Agent; AI type: Generate; Military use: Command; Civic use: AIAssistants", + "image": "./assets/noun-chatbot-7107716.png", + "nounKey": "chatbot", + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "GoldenShield", + "name": "Golden Shield", + "year": 2003, + "currentStatus": "Operation", + "type": "DataManagement, AnomalyDetection", + "MLTask": "Recognize", + "militaryUse": "Intelligence", + "civicUse": "BehaviorEvaluation, Surveillance, Marketing, DataBrokers", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Golden Shield; year: 2003; task: DataManagement, AnomalyDetection; AI type: Recognize; Military use: Intelligence; Civic use: BehaviorEvaluation, Surveillance, Marketing, DataBrokers", + "image": "./assets/noun-cctv-5477699.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "SharpEyes", + "name": "Sharp Eyes", + "year": 2003, + "currentStatus": "Operation", + "type": "FacialRecognition, ComputerVision", + "MLTask": "Recognize", + "militaryUse": "Intelligence", + "civicUse": "IdentityVerification, Security, Policing", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Sharp Eyes; year: 2003; task: FacialRecognition, ComputerVision; AI type: Recognize; Military use: Intelligence; Civic use: IdentityVerification, Security, Policing", + "image": "./assets/noun-cctv-5477699.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Skynet-PRC", + "name": "Skynet-PRC", + "year": 2003, + "currentStatus": "Operation", + "type": "LocationAwareness", + "MLTask": "Recognize", + "militaryUse": "Intelligence", + "civicUse": "Security, Policing, LocationAnalytics", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Skynet-PRC; year: 2003; task: LocationAwareness; AI type: Recognize; Military use: Intelligence; Civic use: Security, Policing, LocationAnalytics", + "image": "./assets/noun-cctv-5477699.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Lattice", + "name": "Lattice", + "year": 2025, + "currentStatus": "Deployment", + "type": "PlanningSystem, MultiAgentSystem, RecommenderSystem", + "MLTask": "Assign", + "militaryUse": "Command", + "civicUse": "Policing, ScientificResearch", + "MLTasks": "ComputerVision, Classification, Tracking, Detection, EdgeComputing, SignalAnalysis, ObjectRecognition", + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": "Action, Content, Decision", + "vair:riskSources": null, + "impact": "PhysicalInjury, Overreliance, DistortionInHumanBehavior", + "hover": "name: Lattice; year: 2025; task: PlanningSystem, MultiAgentSystem, RecommenderSystem; AI type: Assign; Military use: Command; Civic use: Policing, ScientificResearch", + "image": "./assets/noun-surveillance-monitor-6831349.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Foundry", + "name": "Foundry", + "year": 2022, + "currentStatus": "Operation", + "type": "DataManagement, Agent", + "MLTask": "Store", + "militaryUse": "Intelligence", + "civicUse": "Policing, PrivateSecurity, BorderPatrol, BehaviorEvaluation, Surveillance, Marketing, DataBrokers", + "MLTasks": "SemanticSearch, Ontologies, DataAnalysis", + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Foundry; year: 2022; task: DataManagement, Agent; AI type: Store; Military use: Intelligence; Civic use: Policing, PrivateSecurity, BorderPatrol, BehaviorEvaluation, Surveillance, Marketing, DataBrokers", + "image": "./assets/noun-ai-training-data-2985134.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Fortify", + "name": "(Mobile) Fortify", + "year": 2020, + "currentStatus": "Operation", + "type": "DataManagement, FacialRecognition, ComputerVision", + "MLTask": "Recognize", + "militaryUse": "Intelligence", + "civicUse": "IdentityVerification, Security, Policing", + "MLTasks": "Classification", + "purpose": null, + "capacity": "FaceRecognition", + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: (Mobile) Fortify; year: 2020; task: DataManagement, FacialRecognition, ComputerVision; AI type: Recognize; Military use: Intelligence; Civic use: IdentityVerification, Security, Policing", + "image": "./assets/noun-facial-recognition-4116350.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Sentry", + "name": "Sentry", + "year": 2018, + "currentStatus": "Operation", + "type": "IntelligentControlSystem, IoT", + "MLTask": "Automate", + "militaryUse": "Intelligence", + "civicUse": "BorderPatrol, Policing", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Sentry; year: 2018; task: IntelligentControlSystem, IoT; AI type: Automate; Military use: Intelligence; Civic use: BorderPatrol, Policing", + "image": "./assets/noun-tower-111722.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Mantacus", + "name": "Mantacus", + "year": 2022, + "currentStatus": "Development", + "type": "ComputerVision, AnomalyDetection", + "MLTask": "Recognize", + "militaryUse": "Intelligence", + "civicUse": "Policing, CrowdControl, PrivateSecurity", + "MLTasks": "SignalAnalysis", + "purpose": null, + "capacity": "ObjectRecognition", + "vair:technique": null, + "output": "Decision", + "vair:riskSources": null, + "impact": "Overreliance, WellbeingImpact", + "hover": "name: Mantacus; year: 2022; task: ComputerVision, AnomalyDetection; AI type: Recognize; Military use: Intelligence; Civic use: Policing, CrowdControl, PrivateSecurity", + "image": "./assets/noun-pose-estimation-6860082.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "AIVerse", + "name": "AIVerse", + "year": 2021, + "currentStatus": "Deployment", + "type": "GenerativeAI", + "MLTask": "Generate", + "militaryUse": "Command", + "civicUse": "SmartHome, Security", + "MLTasks": "SyntheticData, ObjectRecognition, PoseRecognition, Classification", + "purpose": "Monitoring, DetectingIndividuals", + "capacity": "ObjectDetection, PoseEstimation, Classification", + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: AIVerse; year: 2021; task: GenerativeAI; AI type: Generate; Military use: Command; Civic use: SmartHome, Security", + "image": "./assets/noun-classification-6860055.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Vector", + "name": "Vector", + "year": 2020, + "currentStatus": "Deployment", + "type": "Robotics/Navigation", + "MLTask": "Automate", + "militaryUse": "Operations", + "civicUse": "Policing, Surveillance", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": "Action, Content", + "vair:riskSources": null, + "impact": "PhysicalInjury, WellbeingImpact, PsychologicalHarm", + "hover": "name: Vector; year: 2020; task: Robotics/Navigation; AI type: Automate; Military use: Operations; Civic use: Policing, Surveillance", + "image": "./assets/noun-drone-strike-75130.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "EagleEye", + "name": "Eagle Eye / SBMC Next", + "year": 2025, + "currentStatus": "Development", + "type": "ComputerVision", + "MLTask": "Recognize", + "militaryUse": "Intelligence", + "civicUse": "AR, VR, Games", + "MLTasks": "ObjectClassification, PoseEstimation", + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Eagle Eye / SBMC Next; year: 2025; task: ComputerVision; AI type: Recognize; Military use: Intelligence; Civic use: AR, VR, Games", + "image": "./assets/noun-virtual-headset-7137401.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Thunderforge", + "name": "Project Thunderforge", + "year": 2025, + "currentStatus": "Development", + "type": "Agent, MultiAgentSystem, PlanningSystem", + "MLTask": "Generate", + "militaryUse": "Command", + "civicUse": "AIAssistants, Chatbots", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Project Thunderforge; year: 2025; task: Agent, MultiAgentSystem, PlanningSystem; AI type: Generate; Military use: Command; Civic use: AIAssistants, Chatbots", + "image": "./assets/noun-chatbot-7107716.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Jericho", + "name": "Jericho, StrikeWeb", + "year": 2021, + "currentStatus": "Deployment", + "type": "IntelligentControlSystem, IoT", + "MLTask": "Automate", + "militaryUse": "Intelligence", + "civicUse": "SmartHome, EdgeComputing", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Jericho, StrikeWeb; year: 2021; task: IntelligentControlSystem, IoT; AI type: Automate; Military use: Intelligence; Civic use: SmartHome, EdgeComputing", + "image": "./assets/noun-tower-111722.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Atlas", + "name": "Atlas", + "year": "n.d.", + "currentStatus": "Operation", + "type": "Robotics/Navigation", + "MLTask": "Automate", + "militaryUse": "Operations", + "civicUse": "Policing, CrowdControl, PrivateSecurity, ScientificResearch", + "MLTasks": "SignalAnalysis, ObjectDetection, Classification", + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Atlas; year: n.d.; task: Robotics/Navigation; AI type: Automate; Military use: Operations; Civic use: Policing, CrowdControl, PrivateSecurity, ScientificResearch", + "image": "./assets/noun-drone-strike-75130.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Mithra", + "name": "MithraOS", + "year": 2022, + "currentStatus": "Deployment", + "type": "Robotics/Navigation", + "MLTask": "Automate", + "militaryUse": "Operations", + "civicUse": "SmartHome, Security", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: MithraOS; year: 2022; task: Robotics/Navigation; AI type: Automate; Military use: Operations; Civic use: SmartHome, Security", + "image": "./assets/noun-bomb-defusing-robot-1036305.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Donovan", + "name": "Donovan", + "year": 2023, + "currentStatus": "Development", + "type": "Agent", + "MLTask": "Generate", + "militaryUse": "Command", + "civicUse": "AIAssistants, Chatbots", + "MLTasks": "TextGeneration, TransformerModel, AgentAction, Automation", + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": "DistortionInHumanBehavior, Overreliance, WellbeingImpact", + "hover": "name: Donovan; year: 2023; task: Agent; AI type: Generate; Military use: Command; Civic use: AIAssistants, Chatbots", + "image": "./assets/noun-chatbot-7107716.png", + "nounKey": "assistant", + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Hivemind", + "name": "Hivemind", + "year": 2015, + "currentStatus": "Deployment", + "type": "Agent, Robotics/Navigation", + "MLTask": "Automate", + "militaryUse": "Operations", + "civicUse": "Policing, Security, BorderPatrol", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Hivemind; year: 2015; task: Agent, Robotics/Navigation; AI type: Automate; Military use: Operations; Civic use: Policing, Security, BorderPatrol", + "image": "./assets/noun-drone-strike-75130.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Centaur", + "name": "Centaur", + "year": 2024, + "currentStatus": "Deployment", + "type": "Agent, Robotics/Navigation", + "MLTask": "Automate", + "militaryUse": "Operations", + "civicUse": "Policing, Security, BorderPatrol", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Centaur; year: 2024; task: Agent, Robotics/Navigation; AI type: Automate; Military use: Operations; Civic use: Policing, Security, BorderPatrol", + "image": "./assets/noun-drone-strike-75130.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + }, + { + "id": "Altra", + "name": "Altra", + "year": "n.d.", + "currentStatus": "Operation", + "type": "Robotics/Navigation", + "MLTask": "Automate", + "militaryUse": "Command", + "civicUse": "Policing, Security, BorderPatrol", + "MLTasks": null, + "purpose": null, + "capacity": null, + "vair:technique": null, + "output": null, + "vair:riskSources": null, + "impact": null, + "hover": "name: Altra; year: n.d.; task: Robotics/Navigation; AI type: Automate; Military use: Command; Civic use: Policing, Security, BorderPatrol", + "image": "./assets/noun-drone-strike-75130.png", + "nounKey": null, + "aaaanchor": "", + "anchor": "sarahciston" + } + ], + "N_Civic": [ + { + "id": "Claude", + "name": "Claude", + "year": 2023, + "currentStatus": "Operation", + "type": "Generative", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Claude; year: 2023; type: Generative", + "image": "./assets/noun-text-generator-6059191.png", + "nounKey": "textgenerator" + }, + { + "id": "Roomba", + "name": "Roomba", + "year": 2002, + "currentStatus": "Operation", + "type": "IoT", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Roomba; year: 2002; type: IoT", + "image": "./assets/noun-robot-vacuum-6793770.png", + "nounKey": "smartHome" + }, + { + "id": "Llama", + "name": "Llama", + "year": 2023, + "currentStatus": "Operation", + "type": "Generative", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Llama; year: 2023; type: Generative", + "image": "./assets/noun-text-generator-6059191.png", + "nounKey": "textgenerator" + }, + { + "id": "Facebook", + "name": "Facebook", + "year": 2004, + "currentStatus": "Operation", + "type": "Social", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Facebook; year: 2004; type: Social", + "image": "./assets/noun-social-media-platform-7481620.png", + "nounKey": "platform" + }, + { + "id": "WhatsApp", + "name": "WhatsApp", + "year": 2009, + "currentStatus": "Operation", + "type": "Social", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: WhatsApp; year: 2009; type: Social", + "image": "./assets/noun-social-media-platform-7481620.png", + "nounKey": "platform" + }, + { + "id": "ChatGPT", + "name": "ChatGPT", + "year": 2022, + "currentStatus": "Operation", + "type": "Generative", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: ChatGPT; year: 2022; type: Generative", + "image": "./assets/noun-text-generator-6059191.png", + "nounKey": "textgenerator" + }, + { + "id": "Gemini", + "name": "Gemini/Bard", + "year": 2024, + "currentStatus": "Operation", + "type": "Generative", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Gemini/Bard; year: 2024; type: Generative", + "image": "./assets/noun-text-generator-6059191.png", + "nounKey": "textgenerator" + }, + { + "id": "DoorDash", + "name": "DoorDash", + "year": 2012, + "currentStatus": "Operation", + "type": "App", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: DoorDash; year: 2012; type: App", + "image": "./assets/noun-social-media-platform-7481620.png", + "nounKey": "logistics" + }, + { + "id": "Oculus", + "name": "Oculus Rift", + "year": 2012, + "currentStatus": "Operation", + "type": "XR", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Oculus Rift; year: 2012; type: XR", + "image": "./assets/noun-virtual-headset-7137401.png", + "nounKey": "VR" + }, + { + "id": "Hololens", + "name": "Hololens 2", + "year": 2016, + "currentStatus": "Operation", + "type": "XR", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Hololens 2; year: 2016; type: XR", + "image": "./assets/noun-virtual-headset-7137401.png", + "nounKey": "AR" + }, + { + "id": "Vertex", + "name": "Vertex", + "year": 2019, + "currentStatus": "Development", + "type": "Storage", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Vertex; year: 2019; type: Storage", + "image": "./assets/noun-locked-cloud-5565062.png", + "nounKey": "cloud" + }, + { + "id": "Pokemon", + "name": "Pokemon Go", + "year": 2016, + "currentStatus": "Operation", + "type": "XR", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Pokemon Go; year: 2016; type: XR", + "image": "./assets/noun-photogrammetry-4284363.png", + "nounKey": "game" + }, + { + "id": "Siri", + "name": "Siri", + "year": 2011, + "currentStatus": "Operation", + "type": "Agent", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Siri; year: 2011; type: Agent", + "image": "./assets/noun-chatbot-7107716.png", + "nounKey": "assistant" + }, + { + "id": "Medicare", + "name": "US Medicare Fraud Detection (CMS)", + "year": 2023, + "currentStatus": "Operation", + "type": "App", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: US Medicare Fraud Detection (CMS); year: 2023; type: App", + "image": "./assets/noun-health-insurance-7667596.png", + "nounKey": "system" + }, + { + "id": "Paypal", + "name": "Paypal", + "year": 1998, + "currentStatus": "Operation", + "type": "App", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Paypal; year: 1998; type: App", + "image": "./assets/noun-software-industry-198331.png", + "nounKey": "platform" + }, + { + "id": "Spotify", + "name": "Spotify", + "year": 2006, + "currentStatus": "Operation", + "type": "App", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Spotify; year: 2006; type: App", + "image": "./assets/noun-social-media-platform-7481620.png", + "nounKey": "platform" + }, + { + "id": "Twitter", + "name": "Twitter/X", + "year": 2006, + "currentStatus": "Operation", + "type": "Social", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Twitter/X; year: 2006; type: Social", + "image": "./assets/noun-social-media-platform-7481620.png", + "nounKey": "platform" + }, + { + "id": "Ring", + "name": "Ring", + "year": 2013, + "currentStatus": "Operation", + "type": "Utility", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Ring; year: 2013; type: Utility", + "image": "./assets/noun-cctv-5477699.png", + "nounKey": "surveillanceCamera" + }, + { + "id": "Citizen", + "name": "Citizen", + "year": 2017, + "currentStatus": "Operation", + "type": "Social", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Citizen; year: 2017; type: Social", + "image": "./assets/noun-social-media-platform-7481620.png", + "nounKey": "platform" + }, + { + "id": "Outlier", + "name": "Outlier & Remotetasks", + "year": 2017, + "currentStatus": "Operation", + "type": "App", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Outlier & Remotetasks; year: 2017; type: App", + "image": "./assets/noun-ai-training-data-2985134.png", + "nounKey": "trainingdataset" + }, + { + "id": "Neko", + "name": "Neko Health", + "year": 2018, + "currentStatus": "Deployment", + "type": "Utility", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Neko Health; year: 2018; type: Utility", + "image": "./assets/noun-health-insurance-7667596.png", + "nounKey": "healthcare" + }, + { + "id": "Instagram", + "name": "Instagram", + "year": 2010, + "currentStatus": "Operation", + "type": "Social", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Instagram; year: 2010; type: Social", + "image": "./assets/noun-social-media-platform-7481620.png", + "nounKey": "platform" + }, + { + "id": "TikTok", + "name": "TikTok", + "year": 2017, + "currentStatus": "Operation", + "type": "Social", + "militaryUse": null, + "civicUse": null, + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: TikTok; year: 2017; type: Social", + "image": "./assets/noun-social-media-platform-7481620.png", + "nounKey": "platform" + } + ], + "N_Historical": [ + { + "id": "Dehomag", + "name": "IBM Dehomag", + "year": 1933, + "currentStatus": "Retirement", + "type": "DataManagement", + "militaryUse": "Personnel, Logistics", + "civicUse": "HumanResources, Census", + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: IBM Dehomag; year: 1933; type: DataManagement", + "image": "./assets/noun-punch-card-5134996.png", + "nounKey": null + }, + { + "id": "Translator", + "name": "IBM Simultaneous Translator", + "year": 1945, + "currentStatus": "Retirement", + "type": "Language", + "militaryUse": "Command", + "civicUse": "Translation", + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: IBM Simultaneous Translator; year: 1945; type: Language", + "image": "./assets/noun-speech-recognition-1870316.png", + "nounKey": null + }, + { + "id": "ELIZA", + "name": "ELIZA", + "year": 1966, + "currentStatus": "Retirement", + "type": "Language", + "militaryUse": "Command", + "civicUse": "Communication", + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: ELIZA; year: 1966; type: Language", + "image": "./assets/noun-chatbot-7107716.png", + "nounKey": null + }, + { + "id": "Shoebox", + "name": "Shoebox", + "year": 1964, + "currentStatus": "Retirement", + "type": "Language", + "militaryUse": "Command", + "civicUse": "Communication", + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Shoebox; year: 1964; type: Language", + "image": "./assets/noun-speech-recognition-1870316.png", + "nounKey": null + }, + { + "id": "ARPANET", + "name": "ARPANET", + "year": 1969, + "currentStatus": "Retirement", + "type": "Network", + "militaryUse": "Command", + "civicUse": "Internet", + "MLTask": null, + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: ARPANET; year: 1969; type: Network", + "image": "./assets/noun-networking-2909312.png", + "nounKey": null + }, + { + "id": "Onavo", + "name": "Onavo", + "year": 2010, + "currentStatus": "Retirement", + "type": "Analytics, Potential spyware", + "militaryUse": "Intelligence", + "civicUse": "DataBrokers, Marketing, BehaviorEvaluation", + "MLTask": "Predict", + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Onavo; year: 2010; type: Analytics, Potential spyware", + "image": "./assets/noun-digital-footprint-6806678.png", + "nounKey": null + }, + { + "id": "Wiz", + "name": "Wiz", + "year": 2020, + "currentStatus": "Aquired", + "type": "DataManagement", + "militaryUse": "Store", + "civicUse": "Logistics, Cybersecurity", + "MLTask": "CloudComputing, Cybersecurity", + "purpose": null, + "capacity": null, + "output": null, + "impact": null, + "hover": "name: Wiz; year: 2020; type: DataManagement", + "image": "./assets/noun-locked-cloud-5565062.png", + "nounKey": null + } + ], + "N_Stakeholders": [ + { + "id": "Palestine", + "name": "Palestine", + "type": "Nation", + "airo:type": "AISubject", + "hover": "name: Palestine; stakeholder: Nation; role: AISubject", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "Israel", + "name": "Israel", + "type": "Nation", + "airo:type": "AIDeployer", + "hover": "name: Israel; stakeholder: Nation; role: AIDeployer", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "US", + "name": "United States", + "type": "Nation", + "airo:type": "AIDeployer", + "hover": "name: United States; stakeholder: Nation; role: AIDeployer", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "Ukraine", + "name": "Ukraine", + "type": "Nation", + "airo:type": "AIDeployer, AISubject", + "hover": "name: Ukraine; stakeholder: Nation; role: AIDeployer, AISubject", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "Palantir", + "name": "Palantir", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: Palantir; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "AWS", + "name": "Amazon Web Services", + "type": "TechCompany", + "airo:type": "AIDeveloper, AISupplier", + "hover": "name: Amazon Web Services; stakeholder: TechCompany; role: AIDeveloper, AISupplier", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Russia", + "name": "Russia", + "type": "Nation", + "airo:type": "AIDeployer, AISubject", + "hover": "name: Russia; stakeholder: Nation; role: AIDeployer, AISubject", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "Syria", + "name": "Syria", + "type": "Nation", + "airo:type": "AISubject", + "hover": "name: Syria; stakeholder: Nation; role: AISubject", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "Germany", + "name": "Germany", + "type": "Nation", + "airo:type": "AIDeployer", + "hover": "name: Germany; stakeholder: Nation; role: AIDeployer", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "Rheinmetall", + "name": "Rheinmetall", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: Rheinmetall; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-radiation-205518.png", + "people": null, + "details": null + }, + { + "id": "Hikvision", + "name": "Hikvision", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: Hikvision; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-radiation-205518.png", + "people": null, + "details": null + }, + { + "id": "TKH", + "name": "TKH Security", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: TKH Security; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "SpaceX", + "name": "SpaceX", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: SpaceX; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-radiation-205518.png", + "people": null, + "details": null + }, + { + "id": "India", + "name": "India", + "type": "Nation", + "airo:type": "AIDeployer", + "hover": "name: India; stakeholder: Nation; role: AIDeployer", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "Rafael", + "name": "Rafael", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: Rafael; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-radiation-205518.png", + "people": null, + "details": null + }, + { + "id": "Elbit", + "name": "Elbit Systems", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: Elbit Systems; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-radiation-205518.png", + "people": null, + "details": null + }, + { + "id": "Amazon", + "name": "Amazon", + "type": "TechCompany", + "airo:type": "AIDeveloper, AIProvider", + "hover": "name: Amazon; stakeholder: TechCompany; role: AIDeveloper, AIProvider", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Google", + "name": "Google", + "type": "TechCompany", + "airo:type": "AIDeveloper, AIProvider", + "hover": "name: Google; stakeholder: TechCompany; role: AIDeveloper, AIProvider", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Alphabet", + "name": "Alphabet", + "type": "TechCompany", + "airo:type": "AIDeveloper, AIProvider", + "hover": "name: Alphabet; stakeholder: TechCompany; role: AIDeveloper, AIProvider", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Oracle", + "name": "Oracle", + "type": "TechCompany", + "airo:type": "AIDeveloper, AIProvider", + "hover": "name: Oracle; stakeholder: TechCompany; role: AIDeveloper, AIProvider", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "IBM", + "name": "IBM", + "type": "TechCompany", + "airo:type": "AIDeveloper, AIProvider", + "hover": "name: IBM; stakeholder: TechCompany; role: AIDeveloper, AIProvider", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Libya", + "name": "Libya", + "type": "Nation", + "airo:type": "AIDeployer", + "hover": "name: Libya; stakeholder: Nation; role: AIDeployer", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "Azerbaijan", + "name": "Azerbaijan", + "type": "Nation", + "airo:type": "AIDeployer", + "hover": "name: Azerbaijan; stakeholder: Nation; role: AIDeployer", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "Turkey", + "name": "Turkey", + "type": "Nation", + "airo:type": "AIDeployer", + "hover": "name: Turkey; stakeholder: Nation; role: AIDeployer", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "UK", + "name": "United Kingdom", + "type": "Nation", + "airo:type": "AIDeployer", + "hover": "name: United Kingdom; stakeholder: Nation; role: AIDeployer", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "Vyriy", + "name": "Vyriy", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: Vyriy; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-research-center-198322.png", + "people": null, + "details": null + }, + { + "id": "Roboneers", + "name": "Roboneers", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: Roboneers; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-research-center-198322.png", + "people": null, + "details": null + }, + { + "id": "D3", + "name": "D3", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: D3; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-research-center-198322.png", + "people": null, + "details": null + }, + { + "id": "Helsing", + "name": "Helsing", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: Helsing; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-museum-198296.png", + "people": null, + "details": null + }, + { + "id": "PG", + "name": "PG Robotics", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: PG Robotics; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-radiation-205518.png", + "people": null, + "details": null + }, + { + "id": "Skyeton", + "name": "Skyeton", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: Skyeton; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-radiation-205518.png", + "people": null, + "details": null + }, + { + "id": "Swarmer", + "name": "Swarmer", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: Swarmer; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-radiation-205518.png", + "people": null, + "details": null + }, + { + "id": "ClearviewAI", + "name": "Clearview AI", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: Clearview AI; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Presage", + "name": "Presage", + "type": "Company", + "airo:type": "AIDeveloper", + "hover": "name: Presage; stakeholder: Company; role: AIDeveloper", + "image": "./assets/noun-research-center-198322.png", + "people": null, + "details": null + }, + { + "id": "Altec", + "name": "Altec", + "type": "Company", + "airo:type": "AIDeveloper", + "hover": "name: Altec; stakeholder: Company; role: AIDeveloper", + "image": "./assets/noun-research-center-198322.png", + "people": null, + "details": null + }, + { + "id": "Niantic", + "name": "Niantic Spatial", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: Niantic Spatial; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Arlington", + "name": "Arlington Capital", + "type": "Investor", + "airo:type": "AIDeveloper", + "hover": "name: Arlington Capital; stakeholder: Investor; role: AIDeveloper", + "image": "./assets/noun-museum-198296.png", + "people": null, + "details": null + }, + { + "id": "Jordan", + "name": "Jordan", + "type": "Nation", + "airo:type": "AIDeployer", + "hover": "name: Jordan; stakeholder: Nation; role: AIDeployer", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "SouthKorea", + "name": "South Korea", + "type": "Nation", + "airo:type": "AIDeployer", + "hover": "name: South Korea; stakeholder: Nation; role: AIDeployer", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "China", + "name": "China", + "type": "Nation", + "airo:type": "AIDeployer", + "hover": "name: China; stakeholder: Nation; role: AIDeployer", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "NSO", + "name": "NSO Group", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: NSO Group; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Unit8200", + "name": "Unit 8200", + "type": "Military", + "airo:type": "AIDeveloper", + "hover": "name: Unit 8200; stakeholder: Military; role: AIDeveloper", + "image": "./assets/noun-locked-location-198286.png", + "people": null, + "details": null + }, + { + "id": "DARPA", + "name": "DARPA", + "type": "Military", + "airo:type": "AIDeveloper", + "hover": "name: DARPA; stakeholder: Military; role: AIDeveloper", + "image": "./assets/noun-locked-location-198286.png", + "people": null, + "details": null + }, + { + "id": "Microsoft", + "name": "Microsoft", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: Microsoft; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "SRI", + "name": "SRI: Stanford Research Institute", + "type": "Institution", + "airo:type": "AIDeveloper", + "hover": "name: SRI: Stanford Research Institute; stakeholder: Institution; role: AIDeveloper", + "image": "./assets/noun-research-center-198322.png", + "people": null, + "details": null + }, + { + "id": "KyonggiUniversity", + "name": "Kyonggi University", + "type": "Institution", + "airo:type": "AIDeveloper", + "hover": "name: Kyonggi University; stakeholder: Institution; role: AIDeveloper", + "image": "./assets/noun-research-center-198322.png", + "people": null, + "details": null + }, + { + "id": "HanwhaTechwin-Samsung", + "name": "Hanwha Techwin (formerly Samsung)", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: Hanwha Techwin (formerly Samsung); stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-radiation-205518.png", + "people": null, + "details": null + }, + { + "id": "DoDAAM", + "name": "DoDAAM", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: DoDAAM; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-radiation-205518.png", + "people": null, + "details": null + }, + { + "id": "SwissInstitute", + "name": "Swiss Institute", + "type": "Institution", + "airo:type": "AIDeveloper", + "hover": "name: Swiss Institute; stakeholder: Institution; role: AIDeveloper", + "image": "./assets/noun-research-center-198322.png", + "people": null, + "details": null + }, + { + "id": "UNHCR", + "name": "UNHCR", + "type": "Military", + "airo:type": "AIDeveloper", + "hover": "name: UNHCR; stakeholder: Military; role: AIDeveloper; notes:The Office of the United Nations High Commissioner for Refugees is a United Nations agency mandated to aid and protect refugees, forcibly displaced communities, and stateless people, and to assist in their voluntary repatriation, local integration or resettlement to a third country. (Wikipedia)", + "image": "./assets/noun-museum-198296.png", + "people": "The Office of the United Nations High Commissioner for Refugees is a United Nations agency mandated to aid and protect refugees, forcibly displaced communities, and stateless people, and to assist in their voluntary repatriation, local integration or resettlement to a third country. (Wikipedia)", + "details": null + }, + { + "id": "UKDSTL", + "name": "UKDSTL", + "type": "Military", + "airo:type": "AIDeveloper", + "hover": "name: UK Defence Science and Technology Laboratory; stakeholder: Military; role: AIDeveloper", + "image": "./assets/noun-locked-location-198286.png", + "people": "UK Defence Science and Technology Laboratory", + "details": null + }, + { + "id": "QinetiQ", + "name": "QinetiQ", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: QinetiQ; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-radiation-205518.png", + "people": null, + "details": null + }, + { + "id": "UKDES", + "name": "UKDE&S", + "type": "Military", + "airo:type": "AIDeveloper", + "hover": "name: UK Defense Equipment and Support; stakeholder: Military; role: AIDeveloper", + "image": "./assets/noun-locked-location-198286.png", + "people": "UK Defense Equipment and Support", + "details": null + }, + { + "id": "Endeavor", + "name": "Endeavor", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: Endeavor; stakeholder: TechCompany; role: AIDevelopernotes: formerly iRobot, sold to FLIR Systems (Teledyne) 2019", + "image": "./assets/noun-software-industry-198331.png", + "people": "formerly iRobot, sold to FLIR Systems (Teledyne) 2019", + "details": null + }, + { + "id": "BlackRock", + "name": "BlackRock", + "type": "Investor", + "airo:type": "AIDeveloper", + "hover": "name: BlackRock; stakeholder: Investor; role: AIDeveloper", + "image": "./assets/noun-museum-198296.png", + "people": null, + "details": null + }, + { + "id": "Stanford", + "name": "Stanford University", + "type": "Institution", + "airo:type": "AIDeveloper", + "hover": "name: Stanford University; stakeholder: Institution; role: AIDeveloper", + "image": "./assets/noun-museum-198296.png", + "people": null, + "details": null + }, + { + "id": "Anthropic", + "name": "Anthropic", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: Anthropic; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "iRobot", + "name": "iRobot", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: iRobot; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Meta", + "name": "Meta", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: Meta; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "OpenAI", + "name": "OpenAI", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: OpenAI; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Lebanon", + "name": "Lebanon", + "type": "Nation", + "airo:type": "AISubject", + "hover": "name: Lebanon; stakeholder: Nation; role: AISubject", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "GoogleCloud", + "name": "Google Cloud", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: Google Cloud; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Azure", + "name": "Azure", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: Azure; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Mamram", + "name": "Mamram", + "type": "Military", + "airo:type": "AIDeployer", + "hover": "name: Mamram; stakeholder: Military; role: AIDeployer", + "image": "./assets/noun-locked-location-198286.png", + "people": null, + "details": null + }, + { + "id": "Anduril", + "name": "Anduril", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: Anduril; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-radiation-205518.png", + "people": null, + "details": null + }, + { + "id": "Lockheed", + "name": "Lockheed Martin", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: Lockheed Martin; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-radiation-205518.png", + "people": null, + "details": null + }, + { + "id": "Booz", + "name": "Booz Allen Hamilton", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: Booz Allen Hamilton; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-radiation-205518.png", + "people": null, + "details": null + }, + { + "id": "PLA-PRC", + "name": "People's Liberation Army", + "type": "Military", + "airo:type": "AIDeployer, AIDeveloper", + "hover": "name: People's Liberation Army, China; stakeholder: Military; role: AIDeployer, AIDeveloper", + "image": "./assets/noun-locked-location-198286.png", + "people": "People's Liberation Army China", + "details": null + }, + { + "id": "Deloitte", + "name": "Deloitte", + "type": "Investor", + "airo:type": "AIDeveloper", + "hover": "name: Deloitte; stakeholder: Investor; role: AIDeveloper", + "image": "./assets/noun-museum-198296.png", + "people": null, + "details": null + }, + { + "id": "Accenture", + "name": "Accenture", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: Accenture; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Databricks", + "name": "Databricks", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: Databricks; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Leidos", + "name": "Leidos", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: Leidos; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "ScaleAI", + "name": "ScaleAI", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: ScaleAI; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Snowflake", + "name": "Snowflake", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: Snowflake; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "KKR", + "name": "KKR Investments", + "type": "Investor", + "airo:type": "AIDeveloper", + "hover": "name: KKR Investments; stakeholder: Investor; role: AIDeveloper", + "image": "./assets/noun-museum-198296.png", + "people": null, + "details": null + }, + { + "id": "GTR", + "name": "Global Technical Reality Data Centers", + "type": "TechCompany", + "airo:type": "AIOperator", + "hover": "name: Global Technical Reality; stakeholder: TechCompany; role: AIOperator", + "image": "./assets/noun-software-industry-198331.png", + "people": "Global Technical Reality", + "details": null + }, + { + "id": "Hyperoptic", + "name": "Hyperoptic", + "type": "Utility", + "airo:type": "Stakeholder", + "hover": "name: Hyperoptic; stakeholder: Utility; role: Stakeholder", + "image": "./assets/noun-infrastructure-6195519.png", + "people": null, + "details": null + }, + { + "id": "Vantage", + "name": "Vantage Towers", + "type": "Utility", + "airo:type": "Stakeholder", + "hover": "name: Vantage Towers; stakeholder: Utility; role: Stakeholder", + "image": "./assets/noun-infrastructure-6195519.png", + "people": null, + "details": null + }, + { + "id": "Landeskriminalamt", + "name": "German State Police-NRW, Hesse, Bavaria", + "type": "Police", + "airo:type": "AIDeployer", + "hover": "name: German State Police North Rhine Westphalia; stakeholder: Police; role: AIDeployer", + "image": "./assets/noun-riot-control-national-guards-1584300.png", + "people": "German State Police NRW", + "details": null + }, + { + "id": "DanishNP", + "name": "Danish Police", + "type": "Police", + "airo:type": "AIDeployer", + "hover": "name: Danish National Police; stakeholder: Police; role: AIDeployer", + "image": "./assets/noun-riot-control-national-guards-1584300.png", + "people": "Danish National Police", + "details": null + }, + { + "id": "Denmark", + "name": "Denmark", + "type": "Nation", + "airo:type": "AIDeployer", + "hover": "name: Denmark; stakeholder: Nation; role: AIDeployer", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "Scopley", + "name": "Scopley Games", + "type": "TechCompany", + "airo:type": "AIDeployer", + "hover": "name: Scopley (Savvy Games); stakeholder: TechCompany; role: AIDeployer", + "image": "./assets/noun-software-industry-198331.png", + "people": "Scopley (Savvy Games)", + "details": null + }, + { + "id": "Saudi", + "name": "Saudi Arabia", + "type": "Nation", + "airo:type": "AIDeployer, AIDeveloper", + "hover": "name: Saudi Arabia; stakeholder: Nation; role: AIDeployer, AIDeveloper", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "MIT", + "name": "MIT", + "type": "Institution", + "airo:type": "AIDeveloper", + "hover": "name: MIT; stakeholder: Institution; role: AIDeveloper", + "image": "./assets/noun-research-center-198322.png", + "people": null, + "details": null + }, + { + "id": "Spain", + "name": "Spain", + "type": "Nation", + "airo:type": "AIDeployer", + "hover": "name: Spain; stakeholder: Nation; role: AIDeployer", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "NHS", + "name": "UK NHS", + "type": "Institution", + "airo:type": "AIDeployer", + "hover": "name: UK NHS; stakeholder: Institution; role: AIDeployer", + "image": "./assets/noun-research-center-198322.png", + "people": null, + "details": null + }, + { + "id": "ICE", + "name": "US Immigration (ICE)", + "type": "Police", + "airo:type": "AIDeployer", + "hover": "name: US Immigration (ICE); stakeholder: Police; role: AIDeployer", + "image": "./assets/noun-riot-control-national-guards-1584300.png", + "people": null, + "details": null + }, + { + "id": "DIANA", + "name": "DIANA", + "type": "Military", + "airo:type": "AIDeployer, AIDeveloper", + "hover": "name: Defence Innovation Accelerator for the North Atlantic (DIANA); stakeholder: Military; role: AIDeployer, AIDeveloper", + "image": "./assets/noun-locked-location-198286.png", + "people": null, + "details": null + }, + { + "id": "NATO", + "name": "NATO", + "type": "Military", + "airo:type": "AIDeployer", + "hover": "name: NATO; stakeholder: Military; role: AIDeployer", + "image": "./assets/noun-locked-location-198286.png", + "people": "North Atlantic Treaty Organization", + "details": null + }, + { + "id": "Apple", + "name": "Apple", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: Apple; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "GDIT", + "name": "General Dynamics Information Technologies", + "type": "TechCompany", + "airo:type": "AIDeployer, AIDeveloper", + "hover": "name: General Dynamics Information Technologies; stakeholder: TechCompany; role: AIDeployer, AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Corsight", + "name": "Corsight.AI", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: Corsight.AI; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Vanguard", + "name": "Vanguard", + "type": "Investor", + "airo:type": "AIDeveloper", + "hover": "name: Vanguard; stakeholder: Investor; role: AIDeveloper", + "image": "./assets/noun-museum-198296.png", + "people": null, + "details": null + }, + { + "id": "CBP", + "name": "US Customs and Border Patrol", + "type": "Police", + "airo:type": "AIDeployer", + "hover": "name: US Customs and Border Patrol; stakeholder: Police; role: AIDeployer", + "image": "./assets/noun-riot-control-national-guards-1584300.png", + "people": null, + "details": null + }, + { + "id": "Horizon", + "name": "Horizon Europe", + "type": "Institution", + "airo:type": "Stakeholder", + "hover": "name: Horizon Europe; stakeholder: Institution; role: Stakeholder", + "image": "./assets/noun-research-center-198322.png", + "people": null, + "details": null + }, + { + "id": "QS", + "name": "Quantum Systems", + "type": "DefenseCompany", + "airo:type": "AIDeveloper", + "hover": "name: Quantum Systems; stakeholder: DefenseCompany; role: AIDeveloper", + "image": "./assets/noun-radiation-205518.png", + "people": null, + "details": null + }, + { + "id": "DIU", + "name": "US Defense Innovation Unit", + "type": "Military", + "airo:type": "AIDeployer, AIOperator", + "hover": "name: US Defense Innovation Unit; stakeholder: Military; role: AIDeployer, AIOperator", + "image": "./assets/noun-locked-location-198286.png", + "people": null, + "details": null + }, + { + "id": "Axon", + "name": "Axon", + "type": "DefenseCompany", + "airo:type": "AIDeployer, AIDeveloper", + "hover": "name: Axon; stakeholder: DefenseCompany; role: AIDeployer, AIDeveloper", + "image": "./assets/noun-locked-location-198286.png", + "people": null, + "details": null + }, + { + "id": "USPD", + "name": "US Local Police", + "type": "Police", + "airo:type": "AIDeployer", + "hover": "name: US Local Police; stakeholder: Police; role: AIDeployer", + "image": "./assets/noun-riot-control-national-guards-1584300.png", + "people": null, + "details": null + }, + { + "id": "201V", + "name": "201 Ventures", + "type": "Investor", + "airo:type": "AIDeveloper", + "hover": "name: 201 Ventures; stakeholder: Investor; role: AIDeveloper", + "image": "./assets/noun-museum-198296.png", + "people": null, + "details": null + }, + { + "id": "Delian", + "name": "Delian", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: Delian; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "NIF", + "name": "Nato Innovation Fund", + "type": "Investor", + "airo:type": "AIDeveloper", + "hover": "name: Nato Innovation Fund; stakeholder: Investor; role: AIDeveloper", + "image": "./assets/noun-museum-198296.png", + "people": null, + "details": null + }, + { + "id": "Tekever", + "name": "Tekever", + "type": "AID", + "airo:type": "AIDeveloper", + "hover": "name: Tekever; stakeholder: AID; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Portugal", + "name": "Portugal", + "type": "Nation", + "airo:type": "AIDeployer", + "hover": "name: Portugal; stakeholder: Nation; role: AIDeployer", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "Greece", + "name": "Greece", + "type": "Nation", + "airo:type": "AIDeployer", + "hover": "name: Greece; stakeholder: Nation; role: AIDeployer", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "Airbus", + "name": "Airbus", + "type": "DefenseCompany", + "airo:type": "AIDeployer", + "hover": "name: Airbus; stakeholder: DefenseCompany; role: AIDeployer", + "image": "./assets/noun-radiation-205518.png", + "people": null, + "details": null + }, + { + "id": "Fraunhofer", + "name": "Fraunhofer Institutes", + "type": "Institution", + "airo:type": "AIDeveloper", + "hover": "name: Fraunhofer Institutes; stakeholder: Institution; role: AIDeveloper", + "image": "./assets/noun-research-center-198322.png", + "people": null, + "details": null + }, + { + "id": "ARX", + "name": "ARX Robotics", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: ARX Robotics; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "BailleGifford", + "name": "Baillie Gifford", + "type": "Investor", + "airo:type": "AIDeveloper", + "hover": "name: Baillie Gifford; stakeholder: Investor; role: AIDeveloper", + "image": "./assets/noun-museum-198296.png", + "people": null, + "details": null + }, + { + "id": "ShieldAI", + "name": "Shield AI", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: Shield AI; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "McKinsey", + "name": "McKinsey", + "type": "Investor", + "airo:type": "AIDeveloper", + "hover": "name: McKinsey; stakeholder: Investor; role: AIDeveloper", + "image": "./assets/noun-museum-198296.png", + "people": null, + "details": null + }, + { + "id": "Teledyne", + "name": "Teledyne FLIR", + "type": "TechCompany", + "airo:type": "AIDeveloper", + "hover": "name: Teledyne FLIR; stakeholder: TechCompany; role: AIDeveloper", + "image": "./assets/noun-software-industry-198331.png", + "people": null, + "details": null + }, + { + "id": "Italy", + "name": "Italy", + "type": "Nation", + "airo:type": "AIDeployer", + "hover": "name: Italy; stakeholder: Nation; role: AIDeployer", + "image": "./assets/noun-flagged-location-198290.png", + "people": null, + "details": null + }, + { + "id": "Leonardo", + "name": "Leonardo", + "type": "DefenseCompany", + "airo:type": "AIDeployer", + "hover": "name: Leonardo; stakeholder: DefenseCompany; role: AIDeployer", + "image": "./assets/noun-radiation-205518.png", + "people": null, + "details": null + } + ], + "N_People": [ + { + "id": "Luckey", + "name": "Palmer Luckey", + "type": "Owner, Investor", + "airo:type": null, + "hover": "name: Palmer Luckey; role: Owner, Investor", + "image": "./assets/noun-person-2649456.png", + "source": null, + "details": null + }, + { + "id": "Musk", + "name": "Elon Musk", + "type": "Owner, Investor", + "airo:type": null, + "hover": "name: Elon Musk; role: Owner, Investor", + "image": "./assets/noun-person-2649456.png", + "source": null, + "details": null + }, + { + "id": "Thiel", + "name": "Peter Thiel", + "type": "Owner, Investor", + "airo:type": null, + "hover": "name: Peter Thiel; role: Owner, Investor", + "image": "./assets/noun-person-2649456.png", + "source": null, + "details": null + }, + { + "id": "Ellison", + "name": "Larry Ellison", + "type": "Owner, Investor", + "airo:type": null, + "hover": "name: Larry Ellison; role: Owner, Investor", + "image": "./assets/noun-person-2649456.png", + "source": null, + "details": null + }, + { + "id": "Fink", + "name": "Larry Fink", + "type": "CEO, Investor", + "airo:type": null, + "hover": "name: Larry Fink; role: CEO, Investor", + "image": "./assets/noun-person-2649456.png", + "source": null, + "details": null + }, + { + "id": "Vance", + "name": "JD Vance", + "type": "Investor, Politician", + "airo:type": null, + "hover": "name: JD Vance; role: Investor, Politician", + "image": "./assets/noun-person-2649456.png", + "source": null, + "details": null + }, + { + "id": "Ek", + "name": "Daniel Ek", + "type": "Owner, Investor", + "airo:type": null, + "hover": "name: Daniel Ek; role: Owner, Investor", + "image": "./assets/noun-person-2649456.png", + "source": null, + "details": null + }, + { + "id": "Scherf", + "name": "Gundbert Scherf", + "type": "Owner", + "airo:type": null, + "hover": "name: Gundbert Scherf; role: Owner", + "image": "./assets/noun-person-2649456.png", + "source": null, + "details": null + }, + { + "id": "Reil", + "name": "Torsten Reil", + "type": "Owner", + "airo:type": null, + "hover": "name: Torsten Reil; role: Owner", + "image": "./assets/noun-person-2649456.png", + "source": null, + "details": null + }, + { + "id": "Rosen", + "name": "Guy Rosen", + "type": "Chief Information Security Officer", + "airo:type": null, + "hover": "name: Guy Rosen; role: Chief Information Security Officer", + "image": "./assets/noun-person-2649456.png", + "source": null, + "details": null + }, + { + "id": "Rappaport", + "name": "Assaf Rappaport", + "type": "Owner", + "airo:type": null, + "hover": "name: Assaf Rappaport; role: Owner", + "image": "./assets/noun-person-2649456.png", + "source": null, + "details": null + }, + { + "id": "Karp", + "name": "Alex Karp", + "type": "Owner", + "airo:type": null, + "hover": "name: Alex Karp; role: Owner", + "image": "./assets/noun-person-2649456.png", + "source": null, + "details": null + } + ], + "E_connection": [ + { + "source": "DARPA", + "target": "US", + "label": "part of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Unit8200", + "target": "Israel", + "label": "part of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "UKDSTL", + "target": "UK", + "label": "part of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "UKDES", + "target": "UK", + "label": "part of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Stanford", + "target": "BlackRock", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Stanford", + "target": "SRI", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Palantir", + "target": "Helsing", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "China", + "target": "BlackRock", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Clearview", + "target": "AFRS", + "label": "similar", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Palantir", + "target": "Anthropic", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "AWS", + "target": "Anthropic", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Syria", + "target": "Jordan", + "label": "refugees from", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Microsoft", + "target": "OpenAI", + "label": "invests in", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Israel", + "target": "Oracle", + "label": "contracts", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "GoogleCloud", + "target": "Google", + "label": "part of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "AWS", + "target": "Amazon", + "label": "part of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Google", + "target": "Alphabet", + "label": "part of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Azure", + "target": "Microsoft", + "label": "part of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Mamram", + "target": "Israel", + "label": "part of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Lockheed", + "target": "Llama", + "label": "incorporates", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Booz", + "target": "Llama", + "label": "incorporates", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "PLA-PRC", + "target": "Llama", + "label": "incorporates", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Anduril", + "target": "Llama", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Accenture", + "target": "Llama", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Booz", + "target": "Llama", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Deloitte", + "target": "Llama", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "IBM", + "target": "Llama", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Oracle", + "target": "Llama", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Databricks", + "target": "Llama", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Leidos", + "target": "Llama", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "ScaleAI", + "target": "Llama", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Snowflake", + "target": "Llama", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Gemini", + "target": "Vertex", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "GTR", + "target": "KKR", + "label": "part of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Vantage", + "target": "KKR", + "label": "part of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Hyperoptic", + "target": "KKR", + "label": "part of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Oculus", + "target": "Anduril", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Azure", + "target": "Anduril", + "label": "relies on", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Palantir", + "target": "Landeskriminalamt", + "label": "contracts", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "MIT", + "target": "ELIZA", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Jordan", + "target": "UNHCR", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Syria", + "target": "UNHCR", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Palestine", + "target": "UNHCR", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "China", + "target": "PLA-PRC", + "label": "part of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "NATO", + "target": "DIANA", + "label": "part of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "US", + "target": "ICE", + "label": "part of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "UK", + "target": "NHS", + "label": "part of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "UK", + "target": "NATO", + "label": "part of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "US", + "target": "NATO", + "label": "part of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Germany", + "target": "NATO", + "label": "member of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Denmark", + "target": "NATO", + "label": "member of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Spain", + "target": "NATO", + "label": "member of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "ARPANET", + "target": "Stanford", + "label": "affiliated", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "WhatsApp", + "target": "Lavender", + "label": "provides data to", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "iRobot", + "target": "Endeavor", + "label": "sold part of to", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Pokemon", + "target": "Scopley", + "label": "sold to", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "CALO", + "target": "Siri", + "label": "based on", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Palantir", + "target": "ICE", + "label": "contracts", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Palantir", + "target": "DanishNP", + "label": "contracts", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Palantir", + "target": "NHS", + "label": "contracts", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Palantir", + "target": "Booz", + "label": "subcontracts", + "width": 0, + "hover": 1, + "reference": "sam.gov" + }, + { + "source": "GDIT", + "target": "Palantir", + "label": "subcontracts", + "width": 0, + "hover": 1, + "reference": "sam.gov" + }, + { + "source": "ScaleAI", + "target": "Meta", + "label": "invests in", + "width": 0, + "hover": 1, + "reference": "x" + }, + { + "source": "Blackrock", + "target": "Palantir", + "label": "invests in", + "width": 0, + "hover": 1, + "reference": "UN" + }, + { + "source": "Blackrock", + "target": "Amazon", + "label": "invests in", + "width": 0, + "hover": 1, + "reference": "UN" + }, + { + "source": "Blackrock", + "target": "Microsoft", + "label": "invests in", + "width": 0, + "hover": 1, + "reference": "UN" + }, + { + "source": "Blackrock", + "target": "Alphabet", + "label": "invests in", + "width": 0, + "hover": 1, + "reference": "UN" + }, + { + "source": "Blackrock", + "target": "IBM", + "label": "invests in", + "width": 0, + "hover": 1, + "reference": "UN" + }, + { + "source": "Vanguard", + "target": "Palantir", + "label": "invests in", + "width": 0, + "hover": 1, + "reference": "UN" + }, + { + "source": "IBM", + "target": "Horizon", + "label": "invests in", + "width": 0, + "hover": 1, + "reference": "UN, EU" + }, + { + "source": "DIANA", + "target": "Mantacus", + "label": "invests in", + "width": 0, + "hover": 1, + "reference": "NATO" + }, + { + "source": "DIANA", + "target": "AIVerse", + "label": "invests in", + "width": 0, + "hover": 1, + "reference": "NATO" + }, + { + "source": "DIANA", + "target": "Vector", + "label": "invests in", + "width": 0, + "hover": 1, + "reference": "NATO" + }, + { + "source": "USPD", + "target": "Axon", + "label": "contracts", + "width": 0, + "hover": 1, + "reference": "Press" + }, + { + "source": "Citizen", + "target": "Axon", + "label": "provides data to", + "width": 0, + "hover": 1, + "reference": "Axon" + }, + { + "source": "Ring", + "target": "Axon", + "label": "provides data to", + "width": 0, + "hover": 1, + "reference": "Axon" + }, + { + "source": "Amazon", + "target": "Ring", + "label": "owns", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "201V", + "target": "Delian", + "label": "invests in", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Portugal", + "target": "Tekever", + "label": "contracts", + "width": 0, + "hover": 1, + "reference": "Tekever" + }, + { + "source": "NIF", + "target": "ARX", + "label": "invests in", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Portugal", + "target": "NATO", + "label": "member of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Greece", + "target": "NATO", + "label": "member of", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "NIF", + "target": "Tekever", + "label": "invests in", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Airbus", + "target": "QS", + "label": "partners with", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Fraunhofer", + "target": "QS", + "label": "partners with", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "BailleGifford", + "target": "Tekever", + "label": "invests in", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "BailleGifford", + "target": "Spotify", + "label": "invests in", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Teledyne", + "target": "Endeavor", + "label": "sold to", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "DARPA", + "target": "iRobot", + "label": "contracts", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "DARPA", + "target": "MIT", + "label": "contracts", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "DARPA", + "target": "Stanford", + "label": "contracts", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Arlington", + "target": "PackBot", + "label": "invested in", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Meta", + "target": "Onavo", + "label": "purchased", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Google", + "target": "Wiz", + "label": "purchased", + "width": 0, + "hover": 1, + "reference": null + }, + { + "source": "Italy", + "target": "NATO", + "label": "member of", + "width": 0, + "hover": 1, + "reference": null + } + ], + "E_isDevelopedBy": [ + { + "source": "Niantic", + "target": "LargeGeospatialModels", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "PolygraphPlus", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Unit8200", + "target": "Lavender", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Unit8200", + "target": "WheresDaddy", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Elbit", + "target": "LegionX", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Unit8200", + "target": "WolfPack", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Palantir", + "target": "AIP", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Palantir", + "target": "MetaConstellation", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "ClearviewAI", + "target": "Clearview", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Roboneers", + "target": "Wolly", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Vyriy", + "target": "FirstPOVDrones", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "PG", + "target": "FirstPOVDrones", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "UKDSTL", + "target": "MAPLE", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Unit8200", + "target": "Gospel", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Unit8200", + "target": "Alchemist", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Google", + "target": "Nimbus", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "AWS", + "target": "Nimbus", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Elbit", + "target": "ARCA", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "LAW", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Palantir", + "target": "Gotham", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "DARPA", + "target": "JEDI", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Rafael", + "target": "FireWeaver", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Rafael", + "target": "FireFactory", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Germany", + "target": "DIAS", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "India", + "target": "AFRS", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "SpaceX", + "target": "Starshield", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "SpaceX", + "target": "Starlink", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Russia", + "target": "Pantir-SM", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "RedWolf", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "BlueWolf", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "TKH", + "target": "Mabat2000", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "DARPA", + "target": "URSA", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Rheinmetall", + "target": "TacNet", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Syria", + "target": "Bylina", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Google", + "target": "Maven", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "MIT", + "target": "ARPANET", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Ukraine", + "target": "GISArta", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "Skynet-US", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "China", + "target": "RobotRiotControl", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "KyonggiUniversity", + "target": "PrisonGuard", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "NSO", + "target": "Pegasus", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Rafael", + "target": "SentryTech", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "DoDAAM", + "target": "SuperAegis", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "HanwhaTechwin-Samsung", + "target": "SentryRobot", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "PRISM", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "SRI", + "target": "DynaSpeak", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "DARPA", + "target": "CALO", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "China", + "target": "GoldenShield", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "China", + "target": "SharpEyes", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "China", + "target": "Skynet-PRC", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "SRI", + "target": "CALO", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "SwissInstitute", + "target": "CALO", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "SouthKorea", + "target": "RobotRiotControl", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Russia", + "target": "Bylina", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Hikvision", + "target": "Mabat2000", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Turkey", + "target": "LAW", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "LAW", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Skyeton", + "target": "FirstPOVDrones", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Swarmer", + "target": "FirstPOVDrones", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "D3", + "target": "Wolly", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Presage", + "target": "PolygraphPlus", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Altec", + "target": "PolygraphPlus", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Oracle", + "target": "JEDI", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "IBM", + "target": "JEDI", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "GoogleCloud", + "target": "JEDI", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Microsoft", + "target": "JEDI", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "AWS", + "target": "JEDI", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Helsing", + "target": "Wolly", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "QinetiQ", + "target": "MAPLE", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Endeavor", + "target": "PackBot", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "BlackRock", + "target": "Mabat2000", + "label": "developed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "iRobot", + "target": "Roomba", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Anthropic", + "target": "Claude", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Meta", + "target": "Llama", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Meta", + "target": "Facebook", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Meta", + "target": "WhatsApp", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "iRobot", + "target": "PackBot", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Anduril", + "target": "Lattice", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "OpenAI", + "target": "Lattice", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "OpenAI", + "target": "ChatGPT", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Google", + "target": "Gemini", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "KKR", + "target": "DoorDash", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Microsoft", + "target": "Hololens", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Saudi", + "target": "LargeGeospatialModels", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Niantic", + "target": "Pokemon", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "IBM", + "target": "Dehomag", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "IBM", + "target": "Translator", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "IBM", + "target": "Shoebox", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Palantir", + "target": "Foundry", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "DARPA", + "target": "ARPANET", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Apple", + "target": "Siri", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Palantir", + "target": "Maven", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "GDIT", + "target": "Medicare", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Corsight", + "target": "Fortify", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Anduril", + "target": "Sentry", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Mantacus", + "target": "DIANA", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "QS", + "target": "Vector", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Anduril", + "target": "EagleEye", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "EagleEye", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Delian", + "target": "Jericho", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Tekever", + "target": "Atlas", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "ARX", + "target": "Mithra", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "ScaleAI", + "target": "Donovan", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "DIU", + "target": "Donovan", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "ScaleAI", + "target": "Outlier", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "ShieldAI", + "target": "Hivemind", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "DIU", + "target": "Hivemind", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "ScaleAI", + "target": "Thunderforge", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Microsoft", + "target": "Thunderforge", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Anduril", + "target": "Thunderforge", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Helsing", + "target": "Centaur", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Helsing", + "target": "Altra", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Meta", + "target": "Instagram", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + }, + { + "source": "Meta", + "target": "EagleEye", + "label": "developed", + "weight": 2, + "hover": null, + "reference": null + } + ], + "E_isDeployedBy": [ + { + "source": "US", + "target": "LargeGeospatialModels", + "label": "proposed relationship", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "PolygraphPlus", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "Lavender", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "WheresDaddy", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "LegionX", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "WolfPack", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "AIP", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "MetaConstellation", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "Clearview", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Ukraine", + "target": "Wolly", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Ukraine", + "target": "FirstPOVDrones", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "UK", + "target": "MAPLE", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "Gospel", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "Alchemist", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "Nimbus", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "ARCA", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Libya", + "target": "LAW", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Palantir", + "target": "Gotham", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "JEDI", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "FireWeaver", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "FireFactory", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Germany", + "target": "DIAS", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "India", + "target": "AFRS", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "Starshield", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "Starlink", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Russia", + "target": "Pantir-SM", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "RedWolf", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "BlueWolf", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "Mabat2000", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "URSA", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Germany", + "target": "TacNet", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Syria", + "target": "Bylina", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "Maven", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "PackBot", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Ukraine", + "target": "GISArta", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Jordan", + "target": "IrisGuard", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "Skynet-US", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "China", + "target": "RobotRiotControl", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "SouthKorea", + "target": "PrisonGuard", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "Pegasus", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "SentryTech", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "SouthKorea", + "target": "SuperAegis", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "SouthKorea", + "target": "SentryRobot", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "PRISM", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "DynaSpeak", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "CALO", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "China", + "target": "GoldenShield", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "China", + "target": "SharpEyes", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "China", + "target": "Skynet-PRC", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Ukraine", + "target": "MetaConstellation", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Ukraine", + "target": "Clearview", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "UNHCR", + "target": "IrisGuard", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Russia", + "target": "Bylina", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Russia", + "target": "LAW", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Azerbaijan", + "target": "LAW", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Ukraine", + "target": "Starlink", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "Pegasus", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "MIT", + "target": "ARPANET", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "Lattice", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Lockheed", + "target": "Llama", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Palantir", + "target": "Llama", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Booz", + "target": "Llama", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "ICE", + "target": "Foundry", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "NHS", + "target": "Foundry", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "DanishNP", + "target": "Gotham", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "Medicare", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "ICE", + "target": "Fortify", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Israel", + "target": "Fortify", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Unit8200", + "target": "Fortify", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "CBP", + "target": "Fortify", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Jericho", + "target": "UK", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "UK", + "target": "Atlas", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Airbus", + "target": "Hivemind", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "Hivemind", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "Landeskriminalamt", + "target": "Gotham", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "ICE", + "target": "Axon", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "CBP", + "target": "Sentry", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "CBP", + "target": "Lattice", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + }, + { + "source": "US", + "target": "Donovan", + "label": "employed", + "weight": 1, + "hover": null, + "reference": null + } + ], + "E_place": [ + { + "source": "Lavender", + "target": "Palestine", + "label": "used in", + "weight": 3, + "hover": null + }, + { + "source": "Clearview", + "target": "US", + "label": "used in", + "weight": 3, + "hover": null + }, + { + "source": "IrisGuard", + "target": "Jordan", + "label": "used in", + "weight": 3, + "hover": null + }, + { + "source": "KyonggiUniversity", + "target": "SouthKorea", + "label": "based in", + "weight": 0, + "hover": null + }, + { + "source": "NSO", + "target": "Israel", + "label": "based in", + "weight": 0, + "hover": null + }, + { + "source": "Arlington", + "target": "US", + "label": "based in", + "weight": 0, + "hover": null + }, + { + "source": "FireWeaver", + "target": "Lebanon", + "label": "used in", + "weight": 0, + "hover": null + }, + { + "source": "GTR", + "target": "UK", + "label": "based in", + "weight": 0, + "hover": null + }, + { + "source": "GTR", + "target": "Israel", + "label": "based in", + "weight": 0, + "hover": null + }, + { + "source": "GTR", + "target": "Spain", + "label": "based in", + "weight": 0, + "hover": null + }, + { + "source": "Vantage", + "target": "Germany", + "label": "based in", + "weight": 0, + "hover": null + }, + { + "source": "Hyperoptic", + "target": "UK", + "label": "based in", + "weight": 0, + "hover": null + }, + { + "source": "Vantage", + "target": "Spain", + "label": "based in", + "weight": 0, + "hover": null + }, + { + "source": "Translator", + "target": "Germany", + "label": "used in", + "weight": 0, + "hover": null + }, + { + "source": "Landeskriminalamt", + "target": "Germany", + "label": "based in", + "weight": 0, + "hover": null + }, + { + "source": "DanishNP", + "target": "Denmark", + "label": "based in", + "weight": 0, + "hover": null + }, + { + "source": "Corsight", + "target": "Israel", + "label": "based in", + "weight": 0, + "hover": null + }, + { + "source": "Delian", + "target": "Greece", + "label": "based in", + "weight": 0, + "hover": null + }, + { + "source": "QS", + "target": "Germany", + "label": "based in", + "weight": 0, + "hover": null + }, + { + "source": "Helsing", + "target": "Germany", + "label": "based in", + "weight": 0, + "hover": null + }, + { + "source": "Leonardo", + "target": "Italy", + "label": "based in", + "weight": 0, + "hover": null + } + ], + "E_people": [ + { + "source": "Luckey", + "target": "Oculus", + "label": "founder", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Luckey", + "target": "Anduril", + "label": "founder", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Musk", + "target": "SpaceX", + "label": "owner", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Thiel", + "target": "Paypal", + "label": "founder", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Thiel", + "target": "Palantir", + "label": "owner", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Ellison", + "target": "Oracle", + "label": "founder", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Fink", + "target": "BlackRock", + "label": "founder", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Vance", + "target": "Anduril", + "label": "investor", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Ek", + "target": "Helsing", + "label": "investor", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Ek", + "target": "Spotify", + "label": "founder", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Musk", + "target": "Twitter", + "label": "owner", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Scherf", + "target": "Helsing", + "label": "owner", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Scherf", + "target": "McKinsey", + "label": "former partner", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Reil", + "target": "Helsing", + "label": "owner", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Ek", + "target": "Neko", + "label": "owner", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Ellison", + "target": "TikTok", + "label": "prospective owner", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Rosen", + "target": "Meta", + "label": "employee", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Rosen", + "target": "Unit8200", + "label": "unit vetran", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Rosen", + "target": "Onavo", + "label": "founder", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Rappaport", + "target": "Wiz", + "label": "founder", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Rappaport", + "target": "Unit8200", + "label": "unit vetran", + "weight": null, + "hover": null, + "source.1": null + }, + { + "source": "Karp", + "target": "Palantir", + "label": "CEO", + "weight": null, + "hover": null, + "source.1": null + } + ], + "E_hierarchical": [ + { + "source": "E_isDeployedBy", + "target": "N_Systems" + }, + { + "source": "E_isDevelopedBy", + "target": "N_Stakeholders" + }, + { + "source": "N_Stakeholders", + "target": "type" + }, + { + "source": "N_Systems", + "target": "task" + }, + { + "source": "type", + "target": "Nation" + }, + { + "source": "type", + "target": "TechCompany" + }, + { + "source": "type", + "target": "DefenseCompany" + }, + { + "source": "type", + "target": "Military" + }, + { + "source": "type", + "target": "Investor" + }, + { + "source": "type", + "target": "Institution" + }, + { + "source": "type", + "target": "Utility" + }, + { + "source": "task", + "target": "ObjectRecognition" + }, + { + "source": "task", + "target": "imageGeneration" + }, + { + "source": "task", + "target": "SignalAnalysis" + }, + { + "source": "task", + "target": "PatternRecognition" + }, + { + "source": "task", + "target": "Ranking" + }, + { + "source": "task", + "target": "Classification" + }, + { + "source": "task", + "target": "FaceRecognition" + }, + { + "source": "task", + "target": "ObjectDetection" + }, + { + "source": "task", + "target": "Photogrammetry" + }, + { + "source": "task", + "target": "TransformerModel" + }, + { + "source": "task", + "target": "Recommendation" + }, + { + "source": "task", + "target": "SignalAnalysis" + }, + { + "source": "task", + "target": "TextAnalysis" + }, + { + "source": "task", + "target": "PoseEstimation" + } + ] +} \ No newline at end of file diff --git a/cockpit/public/aiwar_weapons.json b/cockpit/public/aiwar_weapons.json new file mode 100644 index 000000000..9e8f5f4a0 --- /dev/null +++ b/cockpit/public/aiwar_weapons.json @@ -0,0 +1,512 @@ +[ + { + "weapon": "Lattice", + "developed": "2025", + "usedBy": "US, Anduril", + "militaryPurpose": "\"Lattice accelerates complex kill chains by orchestrating machine-to-machine tasks at scales and speeds beyond human capacity\"; \"provides a way to link up and control different robots, sensors and other military equipment, a kind of operating system for war\"; combines with company's sensor towers, d", + "typeOfTech": "VR interface, computer vision, edge computing, natural language processing, autonomous data processing and analysis, \"detect, track, and classify\"", + "repurpose": "US Customs and Border Patrol", + "source": "Anduril", + "sourceType": "Corporate, Press" + }, + { + "weapon": "Large Geospatial Models", + "developed": "2025", + "usedBy": "Niantic Labs", + "militaryPurpose": "(proposed)", + "typeOfTech": "Large generative model combined with 3D photogrammetry of public spaces for enhanced/predictive mapping capacities", + "repurpose": "Pokémon Go", + "source": "404 Media", + "sourceType": "Press" + }, + { + "weapon": "Polygraph+", + "developed": "2024", + "usedBy": "US, Presage, Altec", + "militaryPurpose": "Credibility Assessment, updated polygraph, physiological tracking, biofeedback, AI analysis", + "typeOfTech": "\"standard consumer grade cameras for medical assessment\" \"research and clinical technologies that monitor biosignals\"", + "repurpose": "Interrogation, job interviews, \"vetting new hires, evaluating existing DoD personnel for access to classified information, assisting in determining source credibility, and supporting criminal investig", + "source": "DIU", + "sourceType": "Government" + }, + { + "weapon": "Lavender", + "developed": "2023", + "usedBy": "Israel", + "militaryPurpose": "Creates kill lists. Ranks each person from 1-100 for their similarity to pre-existing targets, based on data found in WhatsApp groups, mobile phones, location targeting, network surveillance, face recognition, and other tracking techniques. collects \"Visual information, cellular information, social ", + "typeOfTech": "Ranking, classification, prediction, text analysis, image analysis", + "repurpose": "Works on similar principles to recommender systems: If you liked this reel, or behaved this way online, you are most like these other internet/mobile users. Uses the hypersurveillance of vast cyber in", + "source": "972 Mag", + "sourceType": "Press" + }, + { + "weapon": "Where's Daddy", + "developed": "2023", + "usedBy": "Israel", + "militaryPurpose": "Determines when people are at home with their families in order to destroy them and their homes", + "typeOfTech": "Geolocation, computer vision (object detection), signal tracking", + "repurpose": "Package delivery, advertising, legal preceedings", + "source": "972 Mag", + "sourceType": "Press" + }, + { + "weapon": "Legion X", + "developed": "2022", + "usedBy": "Israel, Elbit Systems", + "militaryPurpose": "Platform for identifying and targeting people carrying weapons or wearing uniforms, for controlling autonomous drone swarms, \"coordinated strike after human confirmation\"", + "typeOfTech": "Network, object identification, geolocation, weapon, pose estimation", + "repurpose": "Security, identify people in crowds, in shops", + "source": "Elbit Systems", + "sourceType": "Corporate" + }, + { + "weapon": "Artificial Intelligence Platform (AIP)", + "developed": "2022", + "usedBy": "Palantir", + "militaryPurpose": "\"Artificial Intelligence Platform, which allows for the integration of large language models into the company's military products\" \"An Army of AI Agents that do what I say for me\"", + "typeOfTech": "Large language model, natural language processing, +", + "repurpose": "Supply chain management, contracts, infrastructure grid, \"LMNotebook\" dashboards", + "source": "Palantir", + "sourceType": "Corporate, Tenders, Video" + }, + { + "weapon": "MetaConstellation", + "developed": "2022", + "usedBy": "Ukraine, Palantir, USA", + "militaryPurpose": "\"relies on intelligence gathered on enemy troop positions by commercial satellites, heat sensors and reconnaissance drones as well as spies working behind enemy lines and ordinary Ukrainians pin-pointing the locations of Russian troops on the country’s E-Enemy app. The software uses AI to transform ", + "typeOfTech": "Prediction, object detection, \"process imagery, detect, and geolocate objects, and determine any movement\"", + "repurpose": "\"monitor locations across the globe for indications of competitor activities\"", + "source": "Palantir", + "sourceType": "Corporate, Video" + }, + { + "weapon": "Foundry", + "developed": "2022", + "usedBy": "Palantir, USA", + "militaryPurpose": "Data tools likely supporting Gotham and Palantir's other defense products", + "typeOfTech": "\"industry agnostic\" tools to create data structures and algorithms for combining and managing large amounts of information, with tools to perform data analysis and create applications.", + "repurpose": "Contracted by US Immigration and Customs Enforcement and other US government agencies to track migration and financial records, and also by UK NHS agencies to track pandemic health records", + "source": "Palantir", + "sourceType": "Academic, Press" + }, + { + "weapon": "Clearview", + "developed": "2022", + "usedBy": "Ukraine, ClearviewAI", + "militaryPurpose": "Facial recognition to \"identify dead soldiers and to uncover Russian assailants and combat misinformation.\"", + "typeOfTech": "Facial recognition", + "repurpose": "Commercial/policing tool then used for warfare", + "source": "National Defense Magazine", + "sourceType": "Corporate, Video" + }, + { + "weapon": "Wolly", + "developed": "2022", + "usedBy": "Ukraine, Roboneers, D3 (former Google employees, investors), Helsing (investors)", + "militaryPurpose": "Automated machine guns “We could sit in the trench drinking coffee and smoking cigarettes and shoot at the Russians”", + "typeOfTech": "Object identification, computer vision, repurposed video game controllers", + "repurpose": "Security systems, prisons, protests", + "source": "NYT", + "sourceType": "Press" + }, + { + "weapon": "First-Person-View Drones", + "developed": "2022", + "usedBy": "Ukraine, Vyriy, PG Robotics, Skyeton, Swarmer, others", + "militaryPurpose": "Fully automated, weaponized drones, with automated targeting. Some can easily be built with hobby kit like materials.", + "typeOfTech": "Quads, computer vision, deep learning, classification and sorting algorithms", + "repurpose": "Personal drones, sports, already in use. Drones as local police first responders", + "source": "NYT", + "sourceType": "Press" + }, + { + "weapon": "MAPLE", + "developed": "2022", + "usedBy": "United Kingdom", + "militaryPurpose": "Command and control platform for the UK Navy to control an automated fleet of unmanned air, ground, and water vehicles", + "typeOfTech": "Assign, task", + "repurpose": "Driver and delivery apps, logistics apps", + "source": "Breaking Defense", + "sourceType": "Corporate, Press" + }, + { + "weapon": "Mantacus", + "developed": "2022", + "usedBy": "Mantacus, DIANA (NATO)", + "militaryPurpose": "AI software continuously scans and tracks people on CCTV for possible concealed weapons, using radar signals.", + "typeOfTech": "Signal analysis, object detection, classification", + "repurpose": "Private security, crowd control, covert surveillance", + "source": "Mantacus", + "sourceType": "Corporate" + }, + { + "weapon": "The Alchemist", + "developed": "2021", + "usedBy": "Israel", + "militaryPurpose": "Sends real-time data to commanders in field about possible threats, using machine learning", + "typeOfTech": "Transmit, analyse", + "repurpose": "As-yet unknown", + "source": "Jerusalem Post", + "sourceType": "Press" + }, + { + "weapon": "Project Nimbus", + "developed": "2021", + "usedBy": "Israel, Google, Amazon", + "militaryPurpose": "Provides cloud services (storage, compute) \"Nimbus is a flagship project and a key anchor in the implementation of the Israeli Government’s cloud policy, and is intended to provide a comprehensive and in-depth solution to the provision of public cloud services to the Government, the defense establis", + "typeOfTech": "Cloud compute and storage, edge computing", + "repurpose": "Cloud compute and storage, edge computing", + "source": "Tech Workers Coalition Newsletter", + "sourceType": "Press, Tenders" + }, + { + "weapon": "Assault Rifle Combat Application System", + "developed": "2021", + "usedBy": "Israel, Elbit Systems", + "militaryPurpose": "a gunsight sold by the Israeli defense firm Elbit Systems. According to a company spec sheet, the “AI-powered” device is capable of “human target detection” at a range of more than 600 yards, and human target “identification” (presumably, discerning whether a person is someone who could be shot) at ", + "typeOfTech": "Pose estimation, object detection, AR", + "repurpose": "Video games: “We made it very intuitive so it looks like PlayStation’s Fortnite ; it shows range, wind and ammo left, etc.,” said Arie Chernobrov, general manager of Elbit Security Systems.", + "source": "Popular Science", + "sourceType": "Press" + }, + { + "weapon": "Lethal autonomous weapons (LAW)", + "developed": "2021", + "usedBy": "Libya, Azerbaijan (US, Turkey, Israeli-made), Russia (aka Kub & Lancet)", + "militaryPurpose": "\"“loitering munitions” — drones that can autonomously patrol an area and automatically divebomb enemy radar signals. These weapons look like smaller versions of the remote-controlled drones that have been used extensively by the U.S. military in Iraq, Afghanistan and other conflicts. Instead of laun", + "typeOfTech": "Automated drones, hardware, geolocation", + "repurpose": "Consumer drones", + "source": "Washington Post", + "sourceType": "Government, Press" + }, + { + "weapon": "Gotham", + "developed": "2021", + "usedBy": "USA, Palantir", + "militaryPurpose": "An \"AI-powered kill chain,\" this operating system identifies targets and pairs them with weapons. Its command center supports mixed reality and edge computing.", + "typeOfTech": "Sorting, identifying, data analysis, edge computing", + "repurpose": "Miscellaneous business to business applications, \"global project management\"", + "source": "Palantir", + "sourceType": "Corporate" + }, + { + "weapon": "Joint Warfighting Cloud Capability, JEDI", + "developed": "2021", + "usedBy": "USA, Amazon, Microsoft, Google, Oracle, IBM", + "militaryPurpose": "Multi-cloud provider for military use, including Unclassified, Secret and Top Secret (2021, 2019)", + "typeOfTech": "Storage, compute (calculation), \"Commercial Cloud Enterprise\"", + "repurpose": "Cloud compute and storage, edge computing", + "source": "National Defense Magazine", + "sourceType": "Government, Press" + }, + { + "weapon": "AI Verse", + "developed": "2021", + "usedBy": "DIANA (NATO), AI Verse", + "militaryPurpose": "Creates synthetic (generated) image datasets used for training AI to detect people, objects, and weapons", + "typeOfTech": "", + "repurpose": "", + "source": "", + "sourceType": "Corporate, Government" + }, + { + "weapon": "The Gospel (Habsora)", + "developed": "2021", + "usedBy": "Israel", + "militaryPurpose": "Marks homes and public buildings as targets for destruction, for alleged military use, based on \"enormous amounts of data that “tens of thousands of intelligence officers could not process,” and recommends bombing sites in real time. Possible data includes: \"cell phone messages, satellite images, dr", + "typeOfTech": "Classification, data analysis, object recognition", + "repurpose": "Redlining, unequal or biased distribution of resources", + "source": "972 Mag", + "sourceType": "Press" + }, + { + "weapon": "(Mobile) Fortify", + "developed": "2020", + "usedBy": "Corsight, Israel, US", + "militaryPurpose": "Israel's military tech division Unit 8200 uses this facial recognition technology, supplemented by Google Photos, to identify and detain people in Gaza. It runs in parallel to Israel's Blue Wolf program in the West Bank.", + "typeOfTech": "Facial recognition", + "repurpose": "US Immigration and Customs Enforcement (ICE) use Mobile Fortify app to indentify people using the nationwide IDENT biometric database (begun 1994, with data from customs, TSA, law enforcement, and els", + "source": "Corsight.AI", + "sourceType": "Corporate, Government, Press, NGO" + }, + { + "weapon": "Fire Weaver", + "developed": "2020", + "usedBy": "Israel, Rafael", + "militaryPurpose": "Sensor-to-Shooter System. \"The system connects all battlefield elements in real time and instantly selects the most relevant shooter for each target – enabling comprehensive situational awareness and simultaneous, precision strikes. Collecting, filtering, and disseminating data from multiple sources", + "typeOfTech": "Analyzing, filtering, real-time data", + "repurpose": "As-yet unknown", + "source": "Rafael", + "sourceType": "Corporate, Press" + }, + { + "weapon": "Fire Factory", + "developed": "2020", + "usedBy": "Israel, Rafael", + "militaryPurpose": "Calculates necessary bomb strength to destroy \"target\" and schedules aircraft to deliver it. \"uses data about military-approved targets to calculate munition loads, prioritize and assign thousands of targets to aircraft and drones, and propose a schedule.\"", + "typeOfTech": "Sorting, tasking, assign", + "repurpose": "As-yet unknown", + "source": "Bloomberg, Business Standard", + "sourceType": "Corporate, Press" + }, + { + "weapon": "Vector", + "developed": "2020", + "usedBy": "DIANA (NATO), Quantum Systems", + "militaryPurpose": "Dual-use AI drone system (UAS)", + "typeOfTech": "Military surveillance, artillery fire, border patrol, mapping, and swarming", + "repurpose": "\"Public safety applications include search and rescue, disaster management, live situational awareness, law enforcement, disaster control, and area surveillance.\"", + "source": "Quantum Systems", + "sourceType": "Corporate, Government" + }, + { + "weapon": "Dialect Recognition Software (DIAS)", + "developed": "2019", + "usedBy": "Germany", + "militaryPurpose": "Determines \"authenticity\" of migrants' claims to refugee status via computer voice analysis, used by the German Federal Asylum Agency. Claims to detect accent (\"language biometry\") despite high error rate.", + "typeOfTech": "Voice recognition, telephone audio datasets", + "repurpose": "Voice print for identification, verification, entry, and residency permit", + "source": "Algorithm Watch", + "sourceType": "Academic, NGO, Press" + }, + { + "weapon": "Automated Facial Recognition System (AFRS)", + "developed": "2019", + "usedBy": "India", + "militaryPurpose": "Facial recognition used for missing children", + "typeOfTech": "Facial recognition", + "repurpose": "Repurposed for surveillance and crackdowns of peaceful protests", + "source": "Al Jazeera", + "sourceType": "Press" + }, + { + "weapon": "Starshield, Starlink", + "developed": "2024, 2019", + "usedBy": "USA, Ukraine, SpaceX", + "militaryPurpose": "Swarming spy satellites, imaging, reconnaisance", + "typeOfTech": "Infrastructure", + "repurpose": "Commercially available internet access", + "source": "Reuters", + "sourceType": "Press" + }, + { + "weapon": "Pantsir-SM", + "developed": "2019", + "usedBy": "Russia", + "militaryPurpose": "Modifications of existing air defense systems incorporate algorithms to orient, detect, and categorize targets by degree of danger, select a method for defense, \"then open fire without human intervention.\"", + "typeOfTech": "Classify, identify", + "repurpose": "As-yet unknown", + "source": "Hynek, Solovyeva (2022)", + "sourceType": "Academic" + }, + { + "weapon": "Red Wolf", + "developed": "2018", + "usedBy": "Israel", + "militaryPurpose": "Monitors and controls people's movement using facial recognition, scanning all faces that pass through military checkpoints", + "typeOfTech": "Facial recognition, camera infrastructure", + "repurpose": "Dating apps, photo library search, local policing, traffic tickets (BBC), public event security", + "source": "Amnesty Int", + "sourceType": "NGO, Press" + }, + { + "weapon": "Blue Wolf", + "developed": "2018", + "usedBy": "Israel", + "militaryPurpose": "Lets soldiers instantly access and add to face recognition human database (Wolf Pack) via app", + "typeOfTech": "App interface, facial recognition", + "repurpose": "Border patrol, security, restriction of movement", + "source": "Amnesty Int", + "sourceType": "NGO, Press" + }, + { + "weapon": "Wolf Pack", + "developed": "2018", + "usedBy": "Israel", + "militaryPurpose": "\"Vast database containing all available information on Palestinians from the Occupied Palestinian Territories, including places of residence, family members and whether they are wanted for questioning by the Israeli authorities.\"", + "typeOfTech": "Database, data aggregation", + "repurpose": "Social credit systems, biased allocation of resources", + "source": "Amnesty Int", + "sourceType": "NGO, Press" + }, + { + "weapon": "Mabat 2000", + "developed": "2018", + "usedBy": "Israel, TKH Security (Dutch), Hikvision (China)", + "militaryPurpose": "Infrastructure of surveillance cameras in occupied territories and illegally annexed areas that support the Wolf systems ~2 cameras every 5 meters", + "typeOfTech": "Cameras", + "repurpose": "Existing infrastructure to build AI systems on top of", + "source": "Amnesty Int", + "sourceType": "NGO, Press" + }, + { + "weapon": "Urban Reconnaissance through Supervised Autonomy (URSA)", + "developed": "2018", + "usedBy": "USA", + "militaryPurpose": "\"enabled robots and drones to act as forward observers for platoons in urban operations. After input from the project's advisory group on ethical and legal issues, it was decided that the software would only ever designate people as \"persons of interest.\" \"DARPA program to enable improved techniques", + "typeOfTech": "Sorting, identifying, data analysis, behavior analysis", + "repurpose": "Suggested as drones to patrol cities", + "source": "DARPA", + "sourceType": "Government" + }, + { + "weapon": "Sentry", + "developed": "2017", + "usedBy": "Anduril, USA, Israel", + "militaryPurpose": "\"Sentry Tower provides clear, long range surveillance of ground-based objects of interest day or night.\" \"Virtual border walls\"", + "typeOfTech": "Sensors, radar,Lidar, satellite signals, edge computing, AI analysis, infrastructure,", + "repurpose": "US Customs and Border Patrol", + "source": "LA Times", + "sourceType": "Corporate, Press" + }, + { + "weapon": "TacNet", + "developed": "2017", + "usedBy": "Germany, Rheinmetall", + "militaryPurpose": "\"command and control application\" including digital force deployment using AI to decide where and when to place troops. \"By analyzing geo data and the monitored situation on the battlefield, the system automatically provides positions to achieve the mission objective and to eliminate potential risk", + "typeOfTech": "Geolocation, object detection", + "repurpose": "Tasking and tracking gig workers", + "source": "Rheinmetall", + "sourceType": "Corporate" + }, + { + "weapon": "Bylina", + "developed": "2017", + "usedBy": "Russia, Syria", + "militaryPurpose": "Reportedly tested in Ukraine and Syria, this system can independently evaluate the battlefield situation and calculate how to attack structures.", + "typeOfTech": "Info synthesis, predict, assign", + "repurpose": "As-yet unknown", + "source": "Penati and Nunes", + "sourceType": "Academic" + }, + { + "weapon": "Maven Smart System", + "developed": "2017", + "usedBy": "USA, Google, Microsoft, Verizon, Facebook, Skype, YouTube, Apple, Yahoo, etc., later Palantir", + "militaryPurpose": "The results of the widely publicized PROJECT MAVEN, this platform automates target identification from satellite images, using AI image classification. Object detection from satellite images to destroy ground targets. \"a Pentagon program that developed target recognition algorithms for video footage", + "typeOfTech": "Object detection, computer vision, data processing", + "repurpose": "Mapping, location confirmation, surveillance", + "source": "MIT Tech Review", + "sourceType": "Press" + }, + { + "weapon": "PackBot", + "developed": "2016", + "usedBy": "Arlington Capital Partners (iRobot)", + "militaryPurpose": "Search and rescue, and bomb disposal robot", + "typeOfTech": "Site mapping, sensors", + "repurpose": "Roomba", + "source": "New York Magazine", + "sourceType": "Press" + }, + { + "weapon": "GIS Arta", + "developed": "2014", + "usedBy": "Ukraine", + "militaryPurpose": "Pairs a battlefield target to an artillery unit (\"like Uber rider to driver\"", + "typeOfTech": "Tasking, sorting", + "repurpose": "Driver and delivery apps, logistics apps", + "source": "MIT Tech Review", + "sourceType": "Press" + }, + { + "weapon": "IrisGuard", + "developed": "2013", + "usedBy": "Jordan, UNHCR, IrisGuard Inc", + "militaryPurpose": "Iris scanning biometric hardware, software, and storage", + "typeOfTech": "Iris scanning biometric hardware, software, and storage", + "repurpose": "\"Blue-Collar Salary Assurance, Mobile Wallets, SIM Card Registration, Digital ID, Elections, Work Visa Validation, Notary Public, Document Delivery, Medical Education Exams, Electronic Medical Record,", + "source": "Ars Electronica", + "sourceType": "Academic, Press" + }, + { + "weapon": "Skynet (US)", + "developed": "2012", + "usedBy": "USA", + "militaryPurpose": "\"uses phone location and call metadata from bulk phone call records to detect suspicious patterns in the physical movements of suspects and their communication habits, according to a 2012 government presentation The Intercept obtained from Edward Snowden. The presentation indicates that Skynet looks", + "typeOfTech": "Filtering, sorting, pattern matching", + "repurpose": "Leads to AI-DSS used above ^^", + "source": "WIRED", + "sourceType": "Press" + }, + { + "weapon": "Robot Riot Control, Prison Guard", + "developed": "2011", + "usedBy": "China, South Korea", + "militaryPurpose": "\"3D depth cameras, a two-way wireless communication system, and software capable of recognizing certain human behavior patterns\"", + "typeOfTech": "Behavior pattern detection, motion tracking, pose detection", + "repurpose": "Private security robots (in use in US cities)", + "source": "PAX for Peace", + "sourceType": "Academic" + }, + { + "weapon": "Pegasus", + "developed": "2011", + "usedBy": "Many countries", + "militaryPurpose": "Access mobile phones via spyware, targeted journalists, activists, dissidents, heads of state", + "typeOfTech": "Cyber weapon, spyware", + "repurpose": "Continued personal data surveillance", + "source": "Washington Post", + "sourceType": "Academic, Corporate, Press" + }, + { + "weapon": "Sentry-Tech, Super Aegis III, Sentry Robot", + "developed": "2010", + "usedBy": "South Korea, Israel", + "militaryPurpose": "\"\"An automated gun turret that can be mounted with a 12.7 mm (.50 in) machine gun, automatic 40 mm grenade launcher, or portable surface-to-air missile. With a detection range of 2.2 km in total darkness, utilising IR thermal sensors, colour camera with 30x magnification, laser illuminator and laser", + "typeOfTech": "Optical sensors, thermal sensors, tracking, automated firing. Connected to gun turrets", + "repurpose": "Automatic security cameras and sensor activated tech", + "source": "Washington Post", + "sourceType": "Press" + }, + { + "weapon": "PRISM/XKEYSCORE", + "developed": "2007", + "usedBy": "USA, Google, Microsoft, Verizon, Facebook, Skype, YouTube, Apple, Yahoo, etc.", + "militaryPurpose": "Used the US Foreign Intelligence Surveillance Act to collect and store massive amounts of internet data on citizens", + "typeOfTech": "Storage, data collection", + "repurpose": "Common data privacy breaches and personal surveillance in collaboration with private companies", + "source": "Washington Post", + "sourceType": "Government, Press" + }, + { + "weapon": "DynaSpeak", + "developed": "2006", + "usedBy": "SRI, USA", + "militaryPurpose": "Speech recognition engine, used in IraqComm speech translation system, provides speech-to-speech machine translation of English–Arabic for US forces in Iraq.", + "typeOfTech": "Speech recognition, speech synthesis, machine translation \"trained to handle topics of tactical importance\"", + "repurpose": "They also offer the EduSpeak toolkit for developers of second-language learning tools.", + "source": "Sobh et al", + "sourceType": "Academic, Corporate" + }, + { + "weapon": "CALO (Cognitive Agent that Learns and Organizes)", + "developed": "2003-2014", + "usedBy": "USA (DARPA), SRI, Swiss Institute of Technology", + "militaryPurpose": "Automates tasks, predicts and takes action on behalf of field commanders", + "typeOfTech": "Agent, natural language processing, voice regonition, voice synthesis, classification, clustering, information extraction, document classification, sorting, annotating text, entity extraction, semantic extraction", + "repurpose": "Siri (Apple) digital assistant", + "source": "Finn. What Algorithms Want. & pal.sri.com", + "sourceType": "Academic, Corporate" + }, + { + "weapon": "Golden Shield", + "developed": "2003", + "usedBy": "China", + "militaryPurpose": "This part of China's widespread surveillance network combines detects, logs, and blocks online activities deemed illegal or sensitive, using AI to recognize patterns of “undesired” behavior in digital traffic.", + "typeOfTech": "Data collection and analysis", + "repurpose": "Commercial data mining", + "source": "Georgetown CSET", + "sourceType": "Academic" + }, + { + "weapon": "Skynet (PRC), SharpEyes", + "developed": "2003", + "usedBy": "China", + "militaryPurpose": "\"The eyes that safeguard China\" is a network of 600 million surveillance cameras or one camera for every two adults, plus the social incentives built in to view and report on footage. As AI technologies have improved, the system has increased predictive policing and the databases it references. The ", + "typeOfTech": "Cameras, social incentives, reporting, predictive policing, databases", + "repurpose": "Used against Hong Kong protestors (2019); Proposed use as lunar surveillance (2024)", + "source": "Georgetown CSET", + "sourceType": "Academic" + } +] \ No newline at end of file diff --git a/cockpit/public/neural_diagnosis.json b/cockpit/public/neural_diagnosis.json new file mode 100644 index 000000000..cd6f5d48c --- /dev/null +++ b/cockpit/public/neural_diagnosis.json @@ -0,0 +1,1858 @@ +{ + "total_functions": 18763, + "total_files": 78, + "total_dead": 27, + "total_stub": 257, + "total_nan_risk": 160, + "health_pct": 98.48638, + "scan_duration_ms": 32076, + "repos": [ + { + "name": "lance-graph", + "total_functions": 4429, + "total_dead": 3, + "total_stub": 22, + "total_nan_risk": 58, + "health_pct": 99.43554, + "modules": [ + { + "name": "adjacency", + "total": 30, + "alive_or_static": 30, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "blasgraph", + "total": 768, + "alive_or_static": 765, + "dead": 0, + "stub": 3, + "nan_risk": 5, + "health_pct": 99.609375, + "dead_functions": [ + { + "id": "lance-graph::blasgraph::new", + "file": "crates/lance-graph/src/graph/blasgraph/descriptor.rs", + "line": 78, + "signature": "fn new() -> Self", + "state": "stub" + }, + { + "id": "lance-graph::blasgraph::zero", + "file": "crates/lance-graph/src/graph/blasgraph/ndarray_bridge.rs", + "line": 51, + "signature": "fn zero() -> Self", + "state": "stub" + }, + { + "id": "lance-graph::blasgraph::new", + "file": "AdaWorldAPI-lance-graph-d9df43b/crates/lance-graph/src/graph/blasgraph/descriptor.rs", + "line": 78, + "signature": "fn new() -> Self", + "state": "stub" + } + ] + }, + { + "name": "builder", + "total": 102, + "alive_or_static": 102, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "cam_pq", + "total": 51, + "alive_or_static": 51, + "dead": 0, + "stub": 0, + "nan_risk": 1, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "datafusion_planner", + "total": 399, + "alive_or_static": 399, + "dead": 0, + "stub": 0, + "nan_risk": 7, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "elevation", + "total": 68, + "alive_or_static": 68, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "execute", + "total": 6, + "alive_or_static": 6, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "graph", + "total": 153, + "alive_or_static": 153, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "ir", + "total": 44, + "alive_or_static": 44, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "mul", + "total": 25, + "alive_or_static": 25, + "dead": 0, + "stub": 0, + "nan_risk": 1, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "namespace", + "total": 14, + "alive_or_static": 14, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "nars", + "total": 16, + "alive_or_static": 16, + "dead": 0, + "stub": 0, + "nan_risk": 1, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "neighborhood", + "total": 92, + "alive_or_static": 92, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "optimize", + "total": 25, + "alive_or_static": 24, + "dead": 0, + "stub": 1, + "nan_risk": 0, + "health_pct": 96.0, + "dead_functions": [ + { + "id": "lance-graph::optimize::iterative", + "file": "crates/lance-graph-planner/src/optimize/rule.rs", + "line": 33, + "signature": "fn iterative(&self) -> bool", + "state": "stub" + } + ] + }, + { + "name": "physical", + "total": 76, + "alive_or_static": 69, + "dead": 0, + "stub": 7, + "nan_risk": 3, + "health_pct": 90.789474, + "dead_functions": [ + { + "id": "lance-graph::physical::is_pipeline_breaker", + "file": "crates/lance-graph-planner/src/physical/broadcast.rs", + "line": 43, + "signature": "fn is_pipeline_breaker(&self) -> bool", + "state": "stub" + }, + { + "id": "lance-graph::physical::is_pipeline_breaker", + "file": "crates/lance-graph-planner/src/physical/collapse.rs", + "line": 89, + "signature": "fn is_pipeline_breaker(&self) -> bool", + "state": "stub" + }, + { + "id": "lance-graph::physical::cardinality", + "file": "crates/lance-graph-planner/src/physical/collapse.rs", + "line": 153, + "signature": "fn cardinality(&self) -> f64", + "state": "stub" + }, + { + "id": "lance-graph::physical::is_pipeline_breaker", + "file": "crates/lance-graph-planner/src/physical/collapse.rs", + "line": 154, + "signature": "fn is_pipeline_breaker(&self) -> bool", + "state": "stub" + }, + { + "id": "lance-graph::physical::is_pipeline_breaker", + "file": "crates/lance-graph-planner/src/physical/accumulate.rs", + "line": 213, + "signature": "fn is_pipeline_breaker(&self) -> bool", + "state": "stub" + }, + { + "id": "lance-graph::physical::is_pipeline_breaker", + "file": "crates/lance-graph-planner/src/physical/cam_pq_scan.rs", + "line": 171, + "signature": "fn is_pipeline_breaker(&self) -> bool", + "state": "stub" + }, + { + "id": "lance-graph::physical::is_pipeline_breaker", + "file": "crates/lance-graph-planner/src/physical/scan.rs", + "line": 113, + "signature": "fn is_pipeline_breaker(&self) -> bool", + "state": "stub" + } + ] + }, + { + "name": "plan", + "total": 19, + "alive_or_static": 19, + "dead": 0, + "stub": 0, + "nan_risk": 6, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "spo", + "total": 144, + "alive_or_static": 142, + "dead": 0, + "stub": 2, + "nan_risk": 0, + "health_pct": 98.61111, + "dead_functions": [ + { + "id": "lance-graph::spo::one", + "file": "crates/lance-graph/src/graph/spo/semiring.rs", + "line": 42, + "signature": "fn one() -> u32", + "state": "stub" + }, + { + "id": "lance-graph::spo::one", + "file": "AdaWorldAPI-lance-graph-d9df43b/crates/lance-graph/src/graph/spo/semiring.rs", + "line": 42, + "signature": "fn one() -> u32", + "state": "stub" + } + ] + }, + { + "name": "src", + "total": 1645, + "alive_or_static": 1633, + "dead": 3, + "stub": 9, + "nan_risk": 28, + "health_pct": 99.270515, + "dead_functions": [ + { + "id": "lance-graph::src::cardinality", + "file": "crates/lance-graph-planner/src/lib.rs", + "line": 464, + "signature": "fn cardinality(&self) -> f64", + "state": "stub" + }, + { + "id": "lance-graph::src::is_pipeline_breaker", + "file": "crates/lance-graph-planner/src/lib.rs", + "line": 465, + "signature": "fn is_pipeline_breaker(&self) -> bool", + "state": "stub" + }, + { + "id": "lance-graph::src::extract_functions", + "file": "crates/neural-debug/src/scanner.rs", + "line": 168, + "signature": "fn extract_functions(...) -> Vec", + "state": "dead" + }, + { + "id": "lance-graph::src::detects_todo_as_dead", + "file": "crates/neural-debug/src/scanner.rs", + "line": 341, + "signature": "fn detects_todo_as_dead() -> ()", + "state": "dead" + }, + { + "id": "lance-graph::src::broken", + "file": "crates/neural-debug/src/scanner.rs", + "line": 343, + "signature": "fn broken() -> i32", + "state": "dead" + }, + { + "id": "lance-graph::src::stub_fn", + "file": "crates/neural-debug/src/scanner.rs", + "line": 356, + "signature": "fn stub_fn() -> Vec", + "state": "stub" + }, + { + "id": "lance-graph::src::double_quoted_string", + "file": "crates/lance-graph/src/parser.rs", + "line": 929, + "signature": "fn double_quoted_string(input: &str) -> IResult<&str, String>", + "state": "stub" + }, + { + "id": "lance-graph::src::new", + "file": "crates/lance-graph/src/query.rs", + "line": 1091, + "signature": "fn new() -> Self", + "state": "stub" + }, + { + "id": "lance-graph::src::new", + "file": "crates/lance-graph/src/config.rs", + "line": 191, + "signature": "fn new() -> Self", + "state": "stub" + }, + { + "id": "lance-graph::src::double_quoted_string", + "file": "AdaWorldAPI-lance-graph-d9df43b/crates/lance-graph/src/parser.rs", + "line": 928, + "signature": "fn double_quoted_string(input: &str) -> IResult<&str, String>", + "state": "stub" + }, + { + "id": "lance-graph::src::new", + "file": "AdaWorldAPI-lance-graph-d9df43b/crates/lance-graph/src/query.rs", + "line": 1089, + "signature": "fn new() -> Self", + "state": "stub" + }, + { + "id": "lance-graph::src::new", + "file": "AdaWorldAPI-lance-graph-d9df43b/crates/lance-graph/src/config.rs", + "line": 191, + "signature": "fn new() -> Self", + "state": "stub" + } + ] + }, + { + "name": "strategy", + "total": 106, + "alive_or_static": 106, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "tests", + "total": 615, + "alive_or_static": 615, + "dead": 0, + "stub": 0, + "nan_risk": 6, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "thinking", + "total": 31, + "alive_or_static": 31, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + } + ] + }, + { + "name": "ndarray", + "total_functions": 4814, + "total_dead": 3, + "total_stub": 32, + "total_nan_risk": 102, + "health_pct": 99.27296, + "modules": [ + { + "name": "backend", + "total": 131, + "alive_or_static": 131, + "dead": 0, + "stub": 0, + "nan_risk": 4, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "bf16_test_src", + "total": 17, + "alive_or_static": 17, + "dead": 0, + "stub": 0, + "nan_risk": 2, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "dimension", + "total": 243, + "alive_or_static": 237, + "dead": 0, + "stub": 6, + "nan_risk": 0, + "health_pct": 97.53087, + "dead_functions": [ + { + "id": "ndarray::dimension::index_unchecked", + "file": "src/dimension/ndindex.rs", + "line": 49, + "signature": "fn index_unchecked(&self, _strides: &Ix0) -> isize", + "state": "stub" + }, + { + "id": "ndarray::dimension::len", + "file": "src/dimension/sequence.rs", + "line": 81, + "signature": "fn len(&self) -> usize;\n}\n\n/// Indexable sequence with length (mut)\npub(in crate::dimension) trait SequenceMut: Sequence + IndexMut", + "state": "stub" + }, + { + "id": "ndarray::dimension::insert_axis", + "file": "src/dimension/dimension_trait.rs", + "line": 393, + "signature": "fn insert_axis(&self, axis: Axis) -> Self::Larger;\n\n #[doc(hidden)]\n fn try_remove_axis(&self, axis: Axis) -> Self::Smaller;\n\n private_decl!", + "state": "stub" + }, + { + "id": "ndarray::dimension::ndim", + "file": "src/dimension/dimension_trait.rs", + "line": 424, + "signature": "fn ndim(&self) -> usize", + "state": "stub" + }, + { + "id": "ndarray::dimension::into_pattern", + "file": "src/dimension/dimension_trait.rs", + "line": 444, + "signature": "fn into_pattern(self) -> Self::Pattern", + "state": "stub" + }, + { + "id": "ndarray::dimension::next_for", + "file": "src/dimension/dimension_trait.rs", + "line": 452, + "signature": "fn next_for(&self, _index: Self) -> Option", + "state": "stub" + } + ] + }, + { + "name": "doc", + "total": 0, + "alive_or_static": 0, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "examples", + "total": 47, + "alive_or_static": 39, + "dead": 0, + "stub": 8, + "nan_risk": 0, + "health_pct": 82.97873, + "dead_functions": [ + { + "id": "ndarray::examples::main", + "file": "examples/sort-axis.rs", + "line": 188, + "signature": "fn main() -> ()", + "state": "stub" + }, + { + "id": "ndarray::examples::takes_layout", + "file": "examples/functions_and_traits.rs", + "line": 132, + "signature": "fn takes_layout(_arr: &LayoutRef) -> ()", + "state": "stub" + }, + { + "id": "ndarray::examples::takes_layout_mut", + "file": "examples/functions_and_traits.rs", + "line": 136, + "signature": "fn takes_layout_mut(_arr: &mut LayoutRef) -> ()", + "state": "stub" + }, + { + "id": "ndarray::examples::main", + "file": "examples/functions_and_traits.rs", + "line": 202, + "signature": "fn main() -> ()", + "state": "stub" + }, + { + "id": "ndarray::examples::main", + "file": "examples/bounds_check_elim.rs", + "line": 114, + "signature": "fn main() -> ()", + "state": "stub" + }, + { + "id": "ndarray::examples::main", + "file": "examples/column_standardize.rs", + "line": 27, + "signature": "fn main() -> ()", + "state": "stub" + }, + { + "id": "ndarray::examples::main", + "file": "examples/convo.rs", + "line": 67, + "signature": "fn main() -> ()", + "state": "stub" + }, + { + "id": "ndarray::examples::main", + "file": "examples/type_conversion.rs", + "line": 120, + "signature": "fn main() -> ()", + "state": "stub" + } + ] + }, + { + "name": "extension", + "total": 1, + "alive_or_static": 1, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "hpc", + "total": 2296, + "alive_or_static": 2295, + "dead": 0, + "stub": 1, + "nan_risk": 81, + "health_pct": 99.95644, + "dead_functions": [ + { + "id": "ndarray::hpc::new", + "file": "src/hpc/substrate.rs", + "line": 241, + "signature": "fn new() -> Self", + "state": "stub" + } + ] + }, + { + "name": "impl_views", + "total": 46, + "alive_or_static": 46, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "iterators", + "total": 155, + "alive_or_static": 155, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "jitson", + "total": 103, + "alive_or_static": 103, + "dead": 0, + "stub": 0, + "nan_risk": 2, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "jitson_cranelift", + "total": 61, + "alive_or_static": 60, + "dead": 0, + "stub": 1, + "nan_risk": 0, + "health_pct": 98.36066, + "dead_functions": [ + { + "id": "ndarray::jitson_cranelift::assert_send_sync", + "file": "src/hpc/jitson_cranelift/noise_jit.rs", + "line": 450, + "signature": "fn assert_send_sync() -> ()", + "state": "stub" + } + ] + }, + { + "name": "layout", + "total": 16, + "alive_or_static": 16, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "linalg", + "total": 41, + "alive_or_static": 40, + "dead": 1, + "stub": 0, + "nan_risk": 0, + "health_pct": 97.560974, + "dead_functions": [ + { + "id": "ndarray::linalg::general_dot_shape_error", + "file": "src/linalg/impl_linalg.rs", + "line": 351, + "signature": "fn general_dot_shape_error(...) -> !", + "state": "dead" + } + ] + }, + { + "name": "ndarray_for_numpy_users", + "total": 0, + "alive_or_static": 0, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "numeric", + "total": 22, + "alive_or_static": 22, + "dead": 0, + "stub": 0, + "nan_risk": 2, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "parallel", + "total": 40, + "alive_or_static": 37, + "dead": 0, + "stub": 3, + "nan_risk": 0, + "health_pct": 92.5, + "dead_functions": [ + { + "id": "ndarray::parallel::opt_len", + "file": "src/parallel/par.rs", + "line": 154, + "signature": "fn opt_len(&self) -> Option", + "state": "stub" + }, + { + "id": "ndarray::parallel::opt_len", + "file": "src/parallel/par.rs", + "line": 263, + "signature": "fn opt_len(&self) -> Option", + "state": "stub" + }, + { + "id": "ndarray::parallel::opt_len", + "file": "src/parallel/par.rs", + "line": 349, + "signature": "fn opt_len(&self) -> Option", + "state": "stub" + } + ] + }, + { + "name": "scripts", + "total": 10, + "alive_or_static": 10, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "src", + "total": 942, + "alive_or_static": 932, + "dead": 2, + "stub": 8, + "nan_risk": 10, + "health_pct": 98.93843, + "dead_functions": [ + { + "id": "ndarray::src::contiguous_stride", + "file": "src/indexes.rs", + "line": 223, + "signature": "fn contiguous_stride(&self) -> Self::Stride", + "state": "stub" + }, + { + "id": "ndarray::src::in_ndim", + "file": "src/slice.rs", + "line": 329, + "signature": "fn in_ndim(&self) -> usize;\n\n /// Returns the number of axes in the output array.\n fn out_ndim(&self) -> usize;\n\n private_decl!", + "state": "stub" + }, + { + "id": "ndarray::src::multi_slice_move", + "file": "src/slice.rs", + "line": 927, + "signature": "fn multi_slice_move(&self, view: ArrayViewMut<'a, A, D>) -> Self::Output;\n\n private_decl!", + "state": "stub" + }, + { + "id": "ndarray::src::multi_slice_move", + "file": "src/slice.rs", + "line": 938, + "signature": "fn multi_slice_move(&self, _view: ArrayViewMut<'a, A, D>) -> Self::Output", + "state": "stub" + }, + { + "id": "ndarray::src::broadcast_panic", + "file": "src/lib.rs", + "line": 1824, + "signature": "fn broadcast_panic(from: &D, to: &E) -> !\n where\n D: Dimension,\n E: Dimension,", + "state": "dead" + }, + { + "id": "ndarray::src::_is_pointer_inbounds", + "file": "src/data_traits.rs", + "line": 44, + "signature": "fn _is_pointer_inbounds(&self, ptr: *const Self::Elem) -> bool;\n\n private_decl!", + "state": "stub" + }, + { + "id": "ndarray::src::try_is_unique", + "file": "src/data_traits.rs", + "line": 216, + "signature": "fn try_is_unique(&mut self) -> Option", + "state": "stub" + }, + { + "id": "ndarray::src::new", + "file": "src/data_traits.rs", + "line": 518, + "signature": "fn new(elements: Vec) -> Self;\n\n /// Converts the data representation to a shared (copy on write)\n /// representation, cloning the array elements if necessary.\n #[doc(hidden)]\n #[allow(clippy::wrong_self_convention)]\n fn into_shared(self_: ArrayBase) -> ArcArray\n where\n Self::Elem: Clone,\n D: Dimension;\n}\n\n/// Array representation trait.\n///\n/// A representation that is a lightweight view.\n///\n/// ***Internal trait, see `Data`.***\n#[allow(clippy::missing_safety_doc)] // not implementable downstream\npub unsafe trait DataShared: Clone + Data + RawDataClone", + "state": "stub" + }, + { + "id": "ndarray::src::array_out_of_bounds", + "file": "src/arraytraits.rs", + "line": 34, + "signature": "fn array_out_of_bounds() -> !", + "state": "dead" + }, + { + "id": "ndarray::src::test_no_swap_via_doctests", + "file": "src/impl_ref_types.rs", + "line": 410, + "signature": "fn test_no_swap_via_doctests() -> ()", + "state": "stub" + } + ] + }, + { + "name": "tests", + "total": 566, + "alive_or_static": 563, + "dead": 0, + "stub": 3, + "nan_risk": 0, + "health_pct": 99.46996, + "dead_functions": [ + { + "id": "ndarray::tests::is_send", + "file": "tests/array-construct.rs", + "line": 43, + "signature": "fn is_send(_t: &T) -> ()", + "state": "stub" + }, + { + "id": "ndarray::tests::is_sync", + "file": "tests/array-construct.rs", + "line": 44, + "signature": "fn is_sync(_t: &T) -> ()", + "state": "stub" + }, + { + "id": "ndarray::tests::_send_sync", + "file": "tests/iterators.rs", + "line": 786, + "signature": "fn _send_sync(_: &T) -> ()", + "state": "stub" + } + ] + }, + { + "name": "zip", + "total": 77, + "alive_or_static": 75, + "dead": 0, + "stub": 2, + "nan_risk": 1, + "health_pct": 97.402596, + "dead_functions": [ + { + "id": "ndarray::zip::as_ptr", + "file": "src/zip/ndproducer.rs", + "line": 86, + "signature": "fn as_ptr(&self) -> Self::Ptr;\n #[doc(hidden)]\n unsafe fn as_ref(&self, ptr: Self::Ptr) -> Self::Item;\n #[doc(hidden)]\n unsafe fn uget_ptr(&self, i: &Self::Dim) -> Self::Ptr;\n #[doc(hidden)]\n fn stride_of(&self, axis: Axis) -> ::Stride;\n #[doc(hidden)]\n fn contiguous_stride(&self) -> Self::Stride;\n #[doc(hidden)]\n fn split_at(self, axis: Axis, index: usize) -> (Self, Self)\n where Self: Sized;\n\n private_decl!", + "state": "stub" + }, + { + "id": "ndarray::zip::broadcast_unwrap", + "file": "src/zip/mod.rs", + "line": 49, + "signature": "fn broadcast_unwrap(self, shape: E) -> Self::Output;\n private_decl!", + "state": "stub" + } + ] + } + ] + }, + { + "name": "q2", + "total_functions": 9488, + "total_dead": 21, + "total_stub": 203, + "total_nan_risk": 0, + "health_pct": 97.63912, + "modules": [ + { + "name": "aiwar", + "total": 17, + "alive_or_static": 17, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "assertions", + "total": 98, + "alive_or_static": 97, + "dead": 0, + "stub": 1, + "nan_risk": 0, + "health_pct": 98.97959, + "dead_functions": [ + { + "id": "q2::assertions::test_extract_stylesheet_hrefs_skips_external", + "file": "crates/quarto-test/src/assertions/css_regex.rs", + "line": 209, + "signature": "fn test_extract_stylesheet_hrefs_skips_external() -> ()", + "state": "stub" + } + ] + }, + { + "name": "bin", + "total": 18, + "alive_or_static": 18, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "call", + "total": 2, + "alive_or_static": 2, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "commands", + "total": 27, + "alive_or_static": 27, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "conversions", + "total": 216, + "alive_or_static": 215, + "dead": 0, + "stub": 1, + "nan_risk": 0, + "health_pct": 99.53704, + "dead_functions": [ + { + "id": "q2::conversions::apply_fixes", + "file": "crates/qmd-syntax-helper/src/conversions/q_2_11.rs", + "line": 88, + "signature": "fn apply_fixes(...) -> Result", + "state": "stub" + } + ] + }, + { + "name": "diagnostics", + "total": 21, + "alive_or_static": 21, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "engine", + "total": 125, + "alive_or_static": 120, + "dead": 0, + "stub": 5, + "nan_risk": 0, + "health_pct": 96.0, + "dead_functions": [ + { + "id": "q2::engine::name", + "file": "crates/quarto-core/src/engine/traits.rs", + "line": 65, + "signature": "fn name(&self) -> &str;\n\n /// Execute code cells in the input content.\n ///\n /// # Arguments\n ///\n /// * `input` - QMD text with executable code cells\n /// * `ctx` - Execution context with paths, config, and options\n ///\n /// # Returns\n ///\n /// `ExecuteResult` containing:\n /// - Transformed markdown with execution outputs\n /// - Paths to any supporting files created\n /// - Filters to apply during rendering\n /// - Content to inject into the document\n ///\n /// # Errors\n ///\n /// Returns `ExecutionError` if:\n /// - The engine runtime is not available\n /// - Code execution fails\n /// - IO operations fail\n fn execute(&self, input: &str, ctx: &ExecutionContext)\n -> Result;\n\n /// Whether this engine supports freeze/thaw caching.\n ///\n /// If true, execution results can be cached in the `_freeze/`\n /// directory and reused on subsequent renders when source\n /// code hasn't changed.\n ///\n /// Default: `false`\n fn can_freeze(&self) -> bool", + "state": "stub" + }, + { + "id": "q2::engine::intermediate_files", + "file": "crates/quarto-core/src/engine/traits.rs", + "line": 114, + "signature": "fn intermediate_files(&self, _input_path: &Path) -> Vec", + "state": "stub" + }, + { + "id": "q2::engine::assert_send_sync", + "file": "crates/quarto-core/src/engine/traits.rs", + "line": 202, + "signature": "fn assert_send_sync() -> ()", + "state": "stub" + }, + { + "id": "q2::engine::can_freeze", + "file": "crates/quarto-core/src/engine/markdown.rs", + "line": 57, + "signature": "fn can_freeze(&self) -> bool", + "state": "stub" + }, + { + "id": "q2::engine::assert_send_sync", + "file": "crates/quarto-core/src/engine/markdown.rs", + "line": 180, + "signature": "fn assert_send_sync() -> ()", + "state": "stub" + } + ] + }, + { + "name": "examples", + "total": 15, + "alive_or_static": 15, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "extension", + "total": 55, + "alive_or_static": 55, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "fuzz_targets", + "total": 0, + "alive_or_static": 0, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "jupyter", + "total": 121, + "alive_or_static": 119, + "dead": 0, + "stub": 2, + "nan_risk": 0, + "health_pct": 98.34711, + "dead_functions": [ + { + "id": "q2::jupyter::execute_inline_expressions", + "file": "crates/quarto-core/src/engine/jupyter/transform.rs", + "line": 215, + "signature": "fn execute_inline_expressions(...) -> Result>", + "state": "stub" + }, + { + "id": "q2::jupyter::assert_send_sync", + "file": "crates/quarto-core/src/engine/jupyter/mod.rs", + "line": 252, + "signature": "fn assert_send_sync() -> ()", + "state": "stub" + } + ] + }, + { + "name": "knitr", + "total": 164, + "alive_or_static": 162, + "dead": 0, + "stub": 2, + "nan_risk": 0, + "health_pct": 98.78049, + "dead_functions": [ + { + "id": "q2::knitr::assert_send_sync", + "file": "crates/quarto-core/src/engine/knitr/mod.rs", + "line": 384, + "signature": "fn assert_send_sync() -> ()", + "state": "stub" + }, + { + "id": "q2::knitr::test_engine_execute_special_characters", + "file": "crates/quarto-core/src/engine/knitr/mod.rs", + "line": 1162, + "signature": "fn test_engine_execute_special_characters() -> ()", + "state": "stub" + } + ] + }, + { + "name": "lint", + "total": 21, + "alive_or_static": 21, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "lua", + "total": 915, + "alive_or_static": 914, + "dead": 0, + "stub": 1, + "nan_risk": 0, + "health_pct": 99.89071, + "dead_functions": [ + { + "id": "q2::lua::register_pandoc_path", + "file": "crates/pampa/src/lua/path.rs", + "line": 31, + "signature": "fn register_pandoc_path(...) -> Result<()>", + "state": "stub" + } + ] + }, + { + "name": "pandoc", + "total": 115, + "alive_or_static": 114, + "dead": 0, + "stub": 1, + "nan_risk": 0, + "health_pct": 99.13043, + "dead_functions": [ + { + "id": "q2::pandoc::none", + "file": "crates/pampa/src/pandoc/location.rs", + "line": 155, + "signature": "fn none() -> Self", + "state": "stub" + } + ] + }, + { + "name": "parsers", + "total": 14, + "alive_or_static": 14, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "quarto-citeproc", + "total": 5, + "alive_or_static": 5, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "quarto-sass", + "total": 3, + "alive_or_static": 3, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "readers", + "total": 51, + "alive_or_static": 51, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "runtime", + "total": 0, + "alive_or_static": 0, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "rust", + "total": 27, + "alive_or_static": 27, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "schema", + "total": 123, + "alive_or_static": 123, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "src", + "total": 4365, + "alive_or_static": 4307, + "dead": 2, + "stub": 56, + "nan_risk": 0, + "health_pct": 98.67125, + "dead_functions": [ + { + "id": "q2::src::new", + "file": "crates/quarto-doctemplate/src/context.rs", + "line": 157, + "signature": "fn new() -> Self", + "state": "stub" + }, + { + "id": "q2::src::get_partial", + "file": "crates/quarto-doctemplate/src/resolver.rs", + "line": 53, + "signature": "fn get_partial(&self, _name: &str, _base_path: &Path) -> Option", + "state": "stub" + }, + { + "id": "q2::src::assert_error", + "file": "crates/quarto-yaml/src/error.rs", + "line": 145, + "signature": "fn assert_error(_: &T) -> ()", + "state": "stub" + }, + { + "id": "q2::src::html_escape", + "file": "crates/quarto/src/publisher.rs", + "line": 227, + "signature": "fn html_escape(s: &str) -> String", + "state": "stub" + }, + { + "id": "q2::src::new", + "file": "crates/quarto-ast-reconcile/src/types.rs", + "line": 244, + "signature": "fn new() -> Self", + "state": "stub" + }, + { + "id": "q2::src::new", + "file": "crates/quarto-ast-reconcile/src/types.rs", + "line": 263, + "signature": "fn new() -> Self", + "state": "stub" + }, + { + "id": "q2::src::new", + "file": "crates/quarto-lsp-core/src/document.rs", + "line": 117, + "signature": "fn new() -> Self", + "state": "stub" + }, + { + "id": "q2::src::analyze_document_with_errors", + "file": "crates/quarto-lsp-core/src/analysis.rs", + "line": 670, + "signature": "fn analyze_document_with_errors() -> ()", + "state": "stub" + }, + { + "id": "q2::src::parse_document_with_invalid_yaml", + "file": "crates/quarto-lsp-core/src/diagnostics.rs", + "line": 219, + "signature": "fn parse_document_with_invalid_yaml() -> ()", + "state": "stub" + }, + { + "id": "q2::src::new", + "file": "crates/pampa/src/filters.rs", + "line": 80, + "signature": "fn new() -> Filter<'static>", + "state": "stub" + }, + { + "id": "q2::src::make_executable", + "file": "crates/pampa/src/json_filter.rs", + "line": 203, + "signature": "fn make_executable(_path: &std::path::Path) -> ()", + "state": "stub" + }, + { + "id": "q2::src::file_write", + "file": "crates/quarto-core/src/filter_resolve.rs", + "line": 310, + "signature": "fn file_write(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::src::path_metadata", + "file": "crates/quarto-core/src/filter_resolve.rs", + "line": 330, + "signature": "fn path_metadata(&self,\n _path: &std::path::Path,) -> quarto_system_runtime::RuntimeResult", + "state": "dead" + }, + { + "id": "q2::src::file_copy", + "file": "crates/quarto-core/src/filter_resolve.rs", + "line": 336, + "signature": "fn file_copy(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::src::path_rename", + "file": "crates/quarto-core/src/filter_resolve.rs", + "line": 343, + "signature": "fn path_rename(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::src::file_remove", + "file": "crates/quarto-core/src/filter_resolve.rs", + "line": 350, + "signature": "fn file_remove(&self, _path: &std::path::Path) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::src::dir_create", + "file": "crates/quarto-core/src/filter_resolve.rs", + "line": 353, + "signature": "fn dir_create(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::src::dir_remove", + "file": "crates/quarto-core/src/filter_resolve.rs", + "line": 360, + "signature": "fn dir_remove(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::src::env_get", + "file": "crates/quarto-core/src/filter_resolve.rs", + "line": 404, + "signature": "fn env_get(&self, _name: &str) -> quarto_system_runtime::RuntimeResult>", + "state": "stub" + }, + { + "id": "q2::src::cpu_time", + "file": "crates/quarto-core/src/filter_resolve.rs", + "line": 424, + "signature": "fn cpu_time(&self) -> quarto_system_runtime::RuntimeResult", + "state": "stub" + } + ] + }, + { + "name": "stage", + "total": 182, + "alive_or_static": 153, + "dead": 2, + "stub": 27, + "nan_risk": 0, + "health_pct": 84.06593, + "dead_functions": [ + { + "id": "q2::stage::file_write", + "file": "crates/quarto-core/src/stage/context.rs", + "line": 236, + "signature": "fn file_write(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stage::path_metadata", + "file": "crates/quarto-core/src/stage/context.rs", + "line": 259, + "signature": "fn path_metadata(&self,\n _path: &std::path::Path,) -> quarto_system_runtime::RuntimeResult", + "state": "dead" + }, + { + "id": "q2::stage::file_copy", + "file": "crates/quarto-core/src/stage/context.rs", + "line": 266, + "signature": "fn file_copy(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stage::path_rename", + "file": "crates/quarto-core/src/stage/context.rs", + "line": 274, + "signature": "fn path_rename(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stage::file_remove", + "file": "crates/quarto-core/src/stage/context.rs", + "line": 282, + "signature": "fn file_remove(&self, _path: &std::path::Path) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stage::dir_create", + "file": "crates/quarto-core/src/stage/context.rs", + "line": 286, + "signature": "fn dir_create(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stage::dir_remove", + "file": "crates/quarto-core/src/stage/context.rs", + "line": 294, + "signature": "fn dir_remove(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stage::env_get", + "file": "crates/quarto-core/src/stage/context.rs", + "line": 342, + "signature": "fn env_get(&self, _name: &str) -> quarto_system_runtime::RuntimeResult>", + "state": "stub" + }, + { + "id": "q2::stage::cpu_time", + "file": "crates/quarto-core/src/stage/context.rs", + "line": 367, + "signature": "fn cpu_time(&self) -> quarto_system_runtime::RuntimeResult", + "state": "stub" + }, + { + "id": "q2::stage::stdout_write", + "file": "crates/quarto-core/src/stage/context.rs", + "line": 379, + "signature": "fn stdout_write(&self, _data: &[u8]) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stage::stderr_write", + "file": "crates/quarto-core/src/stage/context.rs", + "line": 383, + "signature": "fn stderr_write(&self, _data: &[u8]) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stage::file_write", + "file": "crates/quarto-core/src/stage/mod.rs", + "line": 131, + "signature": "fn file_write(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stage::path_metadata", + "file": "crates/quarto-core/src/stage/mod.rs", + "line": 154, + "signature": "fn path_metadata(&self,\n _path: &std::path::Path,) -> quarto_system_runtime::RuntimeResult", + "state": "dead" + }, + { + "id": "q2::stage::file_copy", + "file": "crates/quarto-core/src/stage/mod.rs", + "line": 161, + "signature": "fn file_copy(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stage::path_rename", + "file": "crates/quarto-core/src/stage/mod.rs", + "line": 169, + "signature": "fn path_rename(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stage::file_remove", + "file": "crates/quarto-core/src/stage/mod.rs", + "line": 177, + "signature": "fn file_remove(&self, _path: &std::path::Path) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stage::dir_create", + "file": "crates/quarto-core/src/stage/mod.rs", + "line": 181, + "signature": "fn dir_create(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stage::dir_remove", + "file": "crates/quarto-core/src/stage/mod.rs", + "line": 189, + "signature": "fn dir_remove(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stage::env_get", + "file": "crates/quarto-core/src/stage/mod.rs", + "line": 239, + "signature": "fn env_get(&self, _name: &str) -> quarto_system_runtime::RuntimeResult>", + "state": "stub" + }, + { + "id": "q2::stage::cpu_time", + "file": "crates/quarto-core/src/stage/mod.rs", + "line": 264, + "signature": "fn cpu_time(&self) -> quarto_system_runtime::RuntimeResult", + "state": "stub" + } + ] + }, + { + "name": "stages", + "total": 389, + "alive_or_static": 275, + "dead": 12, + "stub": 102, + "nan_risk": 0, + "health_pct": 70.69409, + "dead_functions": [ + { + "id": "q2::stages::file_write", + "file": "crates/quarto-core/src/stage/stages/user_filters.rs", + "line": 179, + "signature": "fn file_write(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stages::path_metadata", + "file": "crates/quarto-core/src/stage/stages/user_filters.rs", + "line": 199, + "signature": "fn path_metadata(&self,\n _path: &std::path::Path,) -> quarto_system_runtime::RuntimeResult", + "state": "dead" + }, + { + "id": "q2::stages::file_copy", + "file": "crates/quarto-core/src/stage/stages/user_filters.rs", + "line": 205, + "signature": "fn file_copy(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stages::path_rename", + "file": "crates/quarto-core/src/stage/stages/user_filters.rs", + "line": 212, + "signature": "fn path_rename(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stages::file_remove", + "file": "crates/quarto-core/src/stage/stages/user_filters.rs", + "line": 219, + "signature": "fn file_remove(&self, _path: &std::path::Path) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stages::dir_create", + "file": "crates/quarto-core/src/stage/stages/user_filters.rs", + "line": 222, + "signature": "fn dir_create(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stages::dir_remove", + "file": "crates/quarto-core/src/stage/stages/user_filters.rs", + "line": 229, + "signature": "fn dir_remove(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stages::env_get", + "file": "crates/quarto-core/src/stage/stages/user_filters.rs", + "line": 268, + "signature": "fn env_get(&self, _name: &str) -> quarto_system_runtime::RuntimeResult>", + "state": "stub" + }, + { + "id": "q2::stages::cpu_time", + "file": "crates/quarto-core/src/stage/stages/user_filters.rs", + "line": 288, + "signature": "fn cpu_time(&self) -> quarto_system_runtime::RuntimeResult", + "state": "stub" + }, + { + "id": "q2::stages::stdout_write", + "file": "crates/quarto-core/src/stage/stages/user_filters.rs", + "line": 298, + "signature": "fn stdout_write(&self, _data: &[u8]) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stages::stderr_write", + "file": "crates/quarto-core/src/stage/stages/user_filters.rs", + "line": 301, + "signature": "fn stderr_write(&self, _data: &[u8]) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stages::file_write", + "file": "crates/quarto-core/src/stage/stages/render_html.rs", + "line": 143, + "signature": "fn file_write(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stages::path_metadata", + "file": "crates/quarto-core/src/stage/stages/render_html.rs", + "line": 163, + "signature": "fn path_metadata(&self,\n _path: &std::path::Path,) -> quarto_system_runtime::RuntimeResult", + "state": "dead" + }, + { + "id": "q2::stages::file_copy", + "file": "crates/quarto-core/src/stage/stages/render_html.rs", + "line": 169, + "signature": "fn file_copy(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stages::path_rename", + "file": "crates/quarto-core/src/stage/stages/render_html.rs", + "line": 176, + "signature": "fn path_rename(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stages::file_remove", + "file": "crates/quarto-core/src/stage/stages/render_html.rs", + "line": 183, + "signature": "fn file_remove(&self, _path: &std::path::Path) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stages::dir_create", + "file": "crates/quarto-core/src/stage/stages/render_html.rs", + "line": 186, + "signature": "fn dir_create(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stages::dir_remove", + "file": "crates/quarto-core/src/stage/stages/render_html.rs", + "line": 193, + "signature": "fn dir_remove(...) -> quarto_system_runtime::RuntimeResult<()>", + "state": "stub" + }, + { + "id": "q2::stages::env_get", + "file": "crates/quarto-core/src/stage/stages/render_html.rs", + "line": 232, + "signature": "fn env_get(&self, _name: &str) -> quarto_system_runtime::RuntimeResult>", + "state": "stub" + }, + { + "id": "q2::stages::cpu_time", + "file": "crates/quarto-core/src/stage/stages/render_html.rs", + "line": 252, + "signature": "fn cpu_time(&self) -> quarto_system_runtime::RuntimeResult", + "state": "stub" + } + ] + }, + { + "name": "stubs", + "total": 0, + "alive_or_static": 0, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "task", + "total": 13, + "alive_or_static": 13, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "template", + "total": 86, + "alive_or_static": 86, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "tests", + "total": 1429, + "alive_or_static": 1420, + "dead": 5, + "stub": 4, + "nan_risk": 0, + "health_pct": 99.370186, + "dead_functions": [ + { + "id": "q2::tests::load_template", + "file": "crates/quarto-doctemplate/tests/integration_tests.rs", + "line": 18, + "signature": "fn load_template(name: &str) -> Template", + "state": "dead" + }, + { + "id": "q2::tests::load_template", + "file": "crates/quarto-doctemplate/tests/pandoc_equiv_tests.rs", + "line": 24, + "signature": "fn load_template(name: &str) -> Template", + "state": "dead" + }, + { + "id": "q2::tests::main", + "file": "crates/comrak-to-pandoc/tests/debug_comrak.rs", + "line": 5, + "signature": "fn main() -> ()", + "state": "stub" + }, + { + "id": "q2::tests::plain_text", + "file": "crates/comrak-to-pandoc/tests/generators.rs", + "line": 52, + "signature": "fn plain_text() -> Self", + "state": "stub" + }, + { + "id": "q2::tests::para_only", + "file": "crates/comrak-to-pandoc/tests/generators.rs", + "line": 195, + "signature": "fn para_only() -> Self", + "state": "stub" + }, + { + "id": "q2::tests::main", + "file": "crates/comrak-to-pandoc/tests/debug.rs", + "line": 1, + "signature": "fn main() -> ()", + "state": "stub" + }, + { + "id": "q2::tests::get_first_paragraph_inlines", + "file": "crates/pampa/tests/test_code_span.rs", + "line": 20, + "signature": "fn get_first_paragraph_inlines(pandoc: &pampa::pandoc::Pandoc) -> &Vec", + "state": "dead" + }, + { + "id": "q2::tests::str_text", + "file": "crates/pampa/tests/inline_span_investigation.rs", + "line": 118, + "signature": "fn str_text(inline: &Inline) -> &str", + "state": "dead" + }, + { + "id": "q2::tests::get_first_paragraph_inlines", + "file": "crates/pampa/tests/test_shortcode.rs", + "line": 24, + "signature": "fn get_first_paragraph_inlines(pandoc: &pampa::pandoc::Pandoc) -> &Vec", + "state": "dead" + } + ] + }, + { + "name": "transforms", + "total": 336, + "alive_or_static": 336, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "tree-sitter-doctemplate", + "total": 1, + "alive_or_static": 1, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "treesitter_utils", + "total": 39, + "alive_or_static": 38, + "dead": 0, + "stub": 1, + "nan_risk": 0, + "health_pct": 97.4359, + "dead_functions": [ + { + "id": "q2::treesitter_utils::is_escapable_punctuation", + "file": "crates/pampa/src/pandoc/treesitter_utils/text_helpers.rs", + "line": 164, + "signature": "fn is_escapable_punctuation(ch: char) -> bool", + "state": "stub" + } + ] + }, + { + "name": "utils", + "total": 80, + "alive_or_static": 80, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "wasm_entry_points", + "total": 8, + "alive_or_static": 8, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + }, + { + "name": "writers", + "total": 407, + "alive_or_static": 407, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + } + ] + }, + { + "name": "aiwar-neo4j-harvest", + "total_functions": 32, + "total_dead": 0, + "total_stub": 0, + "total_nan_risk": 0, + "health_pct": 100.0, + "modules": [ + { + "name": "src", + "total": 32, + "alive_or_static": 32, + "dead": 0, + "stub": 0, + "nan_risk": 0, + "health_pct": 100.0, + "dead_functions": [] + } + ] + } + ] +} \ No newline at end of file diff --git a/cockpit/src/App.tsx b/cockpit/src/App.tsx new file mode 100644 index 000000000..b987a87cb --- /dev/null +++ b/cockpit/src/App.tsx @@ -0,0 +1,4 @@ +// App.tsx is preserved for backwards compatibility. +// The actual implementation is in DemoApp.tsx. +// This file re-exports DemoApp as App so existing imports continue to work. +export { DemoApp as App } from './DemoApp'; diff --git a/cockpit/src/DemoApp.tsx b/cockpit/src/DemoApp.tsx new file mode 100644 index 000000000..f996c136a --- /dev/null +++ b/cockpit/src/DemoApp.tsx @@ -0,0 +1,109 @@ +import { useEffect, useMemo } from 'react'; +import { useStore } from './store'; +import { connectSSE } from './transport'; +import { QueryBar } from './components/QueryBar'; +import { GraphPanel } from './components/GraphPanel'; +import { Inspector } from './components/Inspector'; +import { ResultTable } from './components/ResultTable'; +import { CellStrip } from './components/CellStrip'; +import { LeftRail } from './components/LeftRail'; + +export function DemoApp() { + const connected = useStore((s) => s.connected); + const nodes = useStore((s) => s.nodes); + const edges = useStore((s) => s.edges); + const cells = useStore((s) => s.cells); + const executing = useStore((s) => s.executing); + + useEffect(() => { + connectSSE(); + }, []); + + const cellCount = useMemo(() => { + const running = cells.filter((c) => c.execution_state === 'running').length; + return { total: cells.length, running }; + }, [cells]); + + // Detect fallback-mode mount: route /demo-fallback is the explicit + // outage-fallback entrypoint. We preserve this surface (do NOT delete) + // but make it visually obvious that the live engine is unavailable. + const isFallbackMode = + typeof window !== 'undefined' && + window.location.pathname.startsWith('/demo-fallback'); + + return ( +
+ {isFallbackMode && ( +
+ FALLBACK MODE — live shader stream and lance-graph engine + unavailable. Showing seed data. +
+ )} + {/* Row 1: Top bar */} +
+
+ q2 graph notebook +

Cockpit

+
+ +
+ + {connected ? 'mcp /sse live' : 'disconnected'} + + export PDF + notebook saved +
+
+ + {/* Row 2: Left rail / Graph / Inspector */} + + + + + {/* Row 3: Result table */} + + + {/* Row 4: Notebook cells */} + + + {/* Status bar (bottom) */} +
+
+ + {connected ? 'Connected' : 'Offline'} + + lance-graph v0.4.2 + + {nodes.length} vertices · {edges.length} edges + + 3.2ms +
+
+ {executing && executing…} + Cell [{cellCount.total}] {cellCount.running > 0 ? 'running' : 'idle'} + + MCP: 3 tools + + localhost:2718 +
+
+ + {/* Tooltip container */} +
+
+ ); +} diff --git a/cockpit/src/NeuralDebuggerPage.tsx b/cockpit/src/NeuralDebuggerPage.tsx new file mode 100644 index 000000000..3f9ad5f82 --- /dev/null +++ b/cockpit/src/NeuralDebuggerPage.tsx @@ -0,0 +1,10 @@ +import { useCallback } from 'react'; +import { NeuralDebugger } from './components/debug/NeuralDebugger'; + +export function NeuralDebuggerPage() { + const handleBack = useCallback(() => { + window.location.href = '/'; + }, []); + + return ; +} diff --git a/cockpit/src/PalantirApp.tsx b/cockpit/src/PalantirApp.tsx new file mode 100644 index 000000000..a85bf8373 --- /dev/null +++ b/cockpit/src/PalantirApp.tsx @@ -0,0 +1,256 @@ +import { useEffect, useMemo, useState, useRef } from 'react'; +import { useStore, type GraphNode, type GraphEdge } from './store'; +import { connectSSE, executeQuery, hydrateCockpit } from './transport'; +import { QueryBar } from './components/QueryBar'; +import { GraphPanel } from './components/GraphPanel'; +import { Inspector } from './components/Inspector'; +import { ResultTable } from './components/ResultTable'; +import { CellStrip } from './components/CellStrip'; +import { LeftRail } from './components/LeftRail'; +import { DataStatusBar } from './components/DataStatusBar'; +import { AnalystPanel } from './components/AnalystPanel'; +import { ErrorBoundary } from './components/ErrorBoundary'; +import { DiagnosticsBadge, DiagnosticsOverlay } from './components/DiagnosticsOverlay'; +import { useEndpointHealth } from './hooks/useEndpointHealth'; +import { convertAiwarGraph } from './data/aiwar-seed'; + +interface DataSource { + name: string; + file: string; + status: 'loading' | 'loaded' | 'error' | 'not_found' | 'found' | 'embedded' | 'empty' | 'static'; + detail: string; + elapsed_ms?: number; + count?: number; +} + +/** + * PalantirApp — IDENTICAL Palantir layout, hydrated through lance-graph. + * + * Hydration order: + * 1. Try MCP: MATCH (n) RETURN n → lance-graph returns graph_json + * 2. Fallback: fetch /aiwar_graph.json → static JSON + * 3. Fallback: keep seed data (24 infra nodes) + */ +export function PalantirApp() { + const connected = useStore((s) => s.connected); + const nodes = useStore((s) => s.nodes); + const edges = useStore((s) => s.edges); + const cells = useStore((s) => s.cells); + const executing = useStore((s) => s.executing); + const setGraphData = useStore((s) => s.setGraphData); + + const [showAnalyst, setShowAnalyst] = useState(false); + const [dataSources, setDataSources] = useState([ + { name: 'Aiwar Graph', file: 'aiwar_graph.json', status: 'loading', detail: 'Connecting...' }, + { name: 'Enrichment Cypher', file: 'cypher/*.cypher', status: 'loading', detail: 'Checking...' }, + { name: 'Neural Diagnosis', file: 'neural_diagnosis.json', status: 'loading', detail: 'Checking...' }, + { name: 'Aiwar CSV', file: 'aiwarcloud-table.csv', status: 'loading', detail: 'Checking...' }, + ]); + const loadedRef = useRef(false); + + useEffect(() => { connectSSE(); }, []); + + // Poll endpoint health every 8s + useEndpointHealth(8000); + + // Hydrate data through MCP → static JSON fallback → seed data + useEffect(() => { + if (loadedRef.current) return; + loadedRef.current = true; + + const updateSource = (name: string, update: Partial) => { + setDataSources(prev => prev.map(s => s.name === name ? { ...s, ...update } : s)); + }; + + (async () => { + // Strategy 0: Try live graph engine API (direct Rust, no MCP overhead) + let hydrated = await hydrateCockpit(); + if (hydrated) { + updateSource('Aiwar Graph', { + status: 'loaded', + detail: 'live graph engine (neo4j-emulating, NARS-enabled)', + }); + } + + // Strategy 1: Try MCP Cypher query for live data from lance-graph + try { + const cell = await executeQuery('MATCH (n) RETURN n LIMIT 500', 'cypher'); + const graphOutput = cell.outputs.find(o => o.type === 'graph'); + if (graphOutput) { + const data = JSON.parse(graphOutput.content); + if (data.nodes?.length > 0) { + setGraphData(data.nodes as GraphNode[], data.edges as GraphEdge[]); + updateSource('Aiwar Graph', { + status: 'loaded', + detail: `${data.nodes.length} nodes via lance-graph MCP`, + }); + hydrated = true; + } + } + if (!hydrated) { + const textOut = cell.outputs.find(o => o.type === 'text'); + updateSource('Aiwar Graph', { + status: 'loaded', + detail: `MCP returned: ${textOut?.content?.slice(0, 60) || 'no graph data'}`, + }); + } + } catch { + // MCP not available — try static JSON fallback + } + + // Strategy 2: Fetch static JSON if MCP didn't hydrate + if (!hydrated) { + try { + const res = await fetch('/aiwar_graph.json'); + if (res.ok) { + const raw = await res.json(); + const { nodes: gNodes, edges: gEdges } = convertAiwarGraph(raw); + if (gNodes.length > 0) { + setGraphData(gNodes, gEdges); + updateSource('Aiwar Graph', { + status: 'loaded', + detail: `${gNodes.length} nodes from static JSON`, + }); + hydrated = true; + } + } else { + updateSource('Aiwar Graph', { + status: 'not_found', + detail: `HTTP ${res.status} — aiwar_graph.json not served`, + }); + } + } catch (err) { + updateSource('Aiwar Graph', { + status: 'error', + detail: err instanceof Error ? err.message : 'JSON parse failed', + }); + } + } + + if (!hydrated) { + updateSource('Aiwar Graph', { + status: 'error', + detail: 'Using 24-node seed data (aiwar not available)', + }); + } + + // Check other data sources via /api/data/status + try { + const res = await fetch('/api/data/status'); + if (res.ok) { + const status = await res.json(); + if (status.sources) { + for (const src of status.sources) { + updateSource(src.name, { + status: src.status, + detail: src.detail, + elapsed_ms: src.elapsed_ms, + count: src.count, + }); + } + } + } + } catch { + // /api/data/status not available (Node demo server) + // Check static files individually + for (const file of ['neural_diagnosis.json', 'aiwar_weapons.json']) { + try { + const r = await fetch(`/${file}`, { method: 'HEAD' }); + const name = file === 'neural_diagnosis.json' ? 'Neural Diagnosis' : 'Aiwar CSV'; + updateSource(name, { + status: r.ok ? 'found' : 'not_found', + detail: r.ok ? `Served from static` : `HTTP ${r.status}`, + }); + } catch { + // ignore + } + } + } + })(); + }, [setGraphData]); + + const cellCount = useMemo(() => { + const running = cells.filter((c) => c.execution_state === 'running').length; + return { total: cells.length, running }; + }, [cells]); + + return ( +
+ {/* Row 1: Top bar */} +
+
+ q2 graph engine +

AIWAR

+
+ +
+ + {connected ? 'mcp /sse live' : 'disconnected'} + + + Φ→Γ reasoning + neural debug + infra demo + + notebook saved +
+
+ + {/* Row 2: Left rail / Graph / Inspector — each wrapped so a crash doesn't kill the shell */} + + + + + {/* Row 3: Result table OR Analyst panel */} + {showAnalyst ? ( +
+
+
+

Political Analyst

+ NARS causality chains · 6 analysis buckets · thinking styles +
+
+ +
+ ) : ( + + )} + + {/* Row 4: Notebook cells */} + + + {/* Status bar with data source indicators */} +
+
+ + {connected ? 'Connected' : 'Offline'} + + lance-graph v0.4.2 + + {nodes.length} vertices · {edges.length} edges + + +
+
+ {executing && executing…} + Cell [{cellCount.total}] {cellCount.running > 0 ? 'running' : 'idle'} + + MCP: 3 tools + + localhost:2718 +
+
+ +
+ + {/* Diagnostics overlay — Shift+D to toggle */} + +
+ ); +} diff --git a/cockpit/src/ReasoningPage.tsx b/cockpit/src/ReasoningPage.tsx new file mode 100644 index 000000000..a0ad940f5 --- /dev/null +++ b/cockpit/src/ReasoningPage.tsx @@ -0,0 +1,174 @@ +import { useState } from 'react'; +import { useShaderStream } from './hooks/useShaderStream'; +import { EnergyField } from './components/EnergyField'; +import { BusTicker } from './components/BusTicker'; +import { ThoughtLog } from './components/ThoughtLog'; +import { SceneBreadcrumb } from './components/SceneBreadcrumb'; +import { FreeEnergyDial } from './components/FreeEnergyDial'; +import { StyleSelector } from './components/StyleSelector'; +import { ErrorBoundary } from './components/ErrorBoundary'; +import { DiagnosticsBadge, DiagnosticsOverlay } from './components/DiagnosticsOverlay'; +import { useEndpointHealth } from './hooks/useEndpointHealth'; +import { fmt, safeNum, safeStr } from './diagnostics/safe'; +import { setShaderStyle } from './transport'; + +/** + * ReasoningPage — live AGI shader stream. + * + * Layout: + * [SceneBreadcrumb — top bar] + * [EnergyField Ψ] [BusTicker B] [FreeEnergyDial F] + * [ThoughtLog Γ — full width] + */ +export function ReasoningPage() { + const stream = useShaderStream('/v1/shader/stream'); + useEndpointHealth(8000); + + // Phase 3 A2: locally-tracked active style (optimistic). Backend is the + // source of truth — `stream.lastDispatch.style` confirms the round-trip + // and is rendered inside the StyleSelector head. + const [activeStyle, setActiveStyle] = useState(null); + const [styleError, setStyleError] = useState(null); + + const handleStyleSelect = (style: string | null) => { + setActiveStyle(style); + setStyleError(null); + // null → "Auto" → keep optimistic state but skip the POST. Backend + // already falls back to its automatic picker when no override is set; + // the manual clear-override hook isn't owned by Agent #A2. + if (style === null) return; + setShaderStyle(style).then((ok) => { + if (!ok) { + setStyleError(`POST /v1/shader/style failed for "${style}"`); + } + }); + }; + + const lastDispatchStyle = stream.lastDispatch + ? safeStr(stream.lastDispatch.style, '', 'dispatch.style') || null + : null; + + return ( +
+ {/* Top bar */} +
+
+ cognitive shader +

REASONING

+
+
+ +
+
+ + {stream.connected ? 'Φ→Ψ→B→Γ live' : 'stream offline'} + + {!stream.connected && ( + + )} + {safeNum(stream.eventCount, 0, 'stream.eventCount')} events + + ← cockpit +
+
+ + {/* Style selector row: 36-brain cognitive lens picker (Phase 3 A2) */} +
+ + + +
+ + {/* Main row: EnergyField · BusTicker · FreeEnergyDial */} +
+
+ + + +
+
+ + + +
+
+ + + + {/* Dispatch info — defensive against missing fields */} + {stream.lastDispatch ? ( +
+
Φ last dispatch
+
+ style: {safeStr(stream.lastDispatch.style, 'unknown', 'dispatch.style')} +
+
+ radius: {fmt(stream.lastDispatch.radius, 2, 'dispatch.radius')} + {' · '} + max_cycles: {safeNum(stream.lastDispatch.max_cycles, 0, 'dispatch.max_cycles')} +
+
+ ) : ( +
+ Φ awaiting first dispatch event +
+ )} +
+
+ + {/* Crystal log — full width */} +
+ + + +
+ + {/* Status bar */} +
+
+ + {stream.connected ? 'streaming' : 'offline'} + + Φ→Ψ→B→Γ pipeline + + {stream.crystalHistory.length} crystals · {stream.busHistory.length} bus commits + {stream.currentScene && ( + <> + + + act {stream.currentScene.act}/{stream.currentScene.total} · {stream.currentScene.name} + + + )} +
+
+ {stream.freeEnergy ? ( + + F={fmt(stream.freeEnergy.free_energy, 3, 'freeEnergy.free_energy')} + + ) : ( + F=— + )} + + /v1/shader/stream + + localhost:2718 +
+
+ + {/* Diagnostics overlay — Shift+D to toggle */} + +
+ ); +} diff --git a/cockpit/src/RenderPage.tsx b/cockpit/src/RenderPage.tsx new file mode 100644 index 000000000..a6e04f30d --- /dev/null +++ b/cockpit/src/RenderPage.tsx @@ -0,0 +1,122 @@ +import { useState } from 'react'; +import { useNeuralDiagnosis } from './hooks/useNeuralDiagnosis'; +import { BrainMriMode, type OrbitMode } from './components/debug/viz/BrainMriMode'; +import { WaveformMode } from './components/debug/viz/WaveformMode'; +import { useEffect } from 'react'; + +/** + * /render — Creative visualization sandbox. + * + * Full-viewport Brain MRI with orbit selector + waveform overlay. + * Demoscene-style pre-baked camera paths, real OSINT pipeline data. + * Future: Unity WebGL embed, shader experiments, VR mode. + */ +export function RenderPage() { + const { diagnosis, loading, load } = useNeuralDiagnosis(); + const [orbit, setOrbit] = useState('render'); + const [showWaveform, setShowWaveform] = useState(true); + + useEffect(() => { load(); }, [load]); + + if (loading || !diagnosis) { + return ( +
+ Loading brain... +
+ ); + } + + return ( +
+ {/* Brain MRI — full viewport */} +
+ +
+ + {/* Waveform overlay — bottom strip */} + {showWaveform && ( +
+ +
+ )} + + {/* Controls — top right */} +
+ {(['render', 'orbit', 'flight'] as OrbitMode[]).map((m) => ( + + ))} + + + ← cockpit + +
+ + {/* Title — top left */} +
+ q2 render · brain mri · {orbit} +
+
+ ); +} + +/** /orbit — direct link to close orbit mode. */ +export function OrbitPage() { + const { diagnosis, loading, load } = useNeuralDiagnosis(); + useEffect(() => { load(); }, [load]); + if (loading || !diagnosis) return
; + return ( +
+ + ← render +
+ ); +} + +/** /flight — direct link to demoscene flythrough. */ +export function FlightPage() { + const { diagnosis, loading, load } = useNeuralDiagnosis(); + useEffect(() => { load(); }, [load]); + if (loading || !diagnosis) return
; + return ( +
+ + ← render +
+ ); +} diff --git a/cockpit/src/components/AiwarExplorer.tsx b/cockpit/src/components/AiwarExplorer.tsx new file mode 100644 index 000000000..e6d724e42 --- /dev/null +++ b/cockpit/src/components/AiwarExplorer.tsx @@ -0,0 +1,431 @@ +import { useState, useMemo, useEffect, useRef, useCallback } from 'react'; +import { Network, type Options } from 'vis-network'; +import { DataSet } from 'vis-data'; +import type { GraphNode, GraphEdge } from '../store'; +import type { AiwarWeapon } from '../hooks/useAiwarData'; +import { NarsPanel } from './NarsPanel'; +import { CypherConsole } from './CypherConsole'; +import { AIWAR_TYPE_COLORS, type ReasoningResult } from '../data/aiwar-seed'; + +interface AiwarExplorerProps { + nodes: GraphNode[]; + edges: GraphEdge[]; + weapons: AiwarWeapon[]; + onBack: () => void; +} + +type ViewMode = 'table' | 'graph'; +type FilterKey = 'all' | 'System' | 'Stakeholder' | 'CivicSystem' | 'Person' | 'HistoricalSystem'; + +const FILTERS: { key: FilterKey; label: string }[] = [ + { key: 'all', label: 'All' }, + { key: 'System', label: 'Systems' }, + { key: 'Stakeholder', label: 'Stakeholders' }, + { key: 'CivicSystem', label: 'Civic' }, + { key: 'Person', label: 'People' }, + { key: 'HistoricalSystem', label: 'Historical' }, +]; + +const MILITARY_FILTERS = ['Intelligence', 'Command', 'Robot', 'Weapon', 'Logistics', 'Prediction', 'Mapping']; + +const GRAPH_OPTIONS: Options = { + nodes: { + shape: 'dot', + font: { color: '#d9e9f9', face: 'Inter, system-ui, sans-serif', size: 11, strokeWidth: 3, strokeColor: '#0a0e17' }, + borderWidth: 2.5, + shadow: { enabled: true, color: 'rgba(0,0,0,0.5)', size: 14, x: 0, y: 4 }, + }, + edges: { + color: { color: 'rgba(125,162,186,0.30)', highlight: '#00d4ff', hover: 'rgba(0,212,255,0.5)' }, + font: { color: 'rgba(147,169,191,0.55)', size: 8, face: 'Inter, system-ui, sans-serif', strokeWidth: 0, align: 'middle' }, + width: 1, + smooth: { enabled: true, type: 'continuous', roundness: 0.12 }, + arrows: { to: { enabled: true, scaleFactor: 0.4, type: 'arrow' } }, + }, + physics: { + solver: 'forceAtlas2Based', + forceAtlas2Based: { gravitationalConstant: -80, centralGravity: 0.005, springLength: 150, springConstant: 0.025, damping: 0.4, avoidOverlap: 0.3 }, + stabilization: { iterations: 200, fit: true }, + }, + interaction: { hover: true, tooltipDelay: 80, zoomView: true, dragView: true, dragNodes: true }, + layout: { improvedLayout: true }, +}; + +export function AiwarExplorer({ nodes, edges, weapons, onBack }: AiwarExplorerProps) { + const [view, setView] = useState('table'); + const [filter, setFilter] = useState('all'); + const [milFilter, setMilFilter] = useState(null); + const [selectedId, setSelectedId] = useState(null); + const [search, setSearch] = useState(''); + const [sortKey, setSortKey] = useState('label'); + const [sortDir, setSortDir] = useState<1 | -1>(1); + const [enrichedNodes, setEnrichedNodes] = useState([]); + const [enrichedEdges, setEnrichedEdges] = useState([]); + const graphRef = useRef(null); + const networkRef = useRef(null); + + // Combine official + enrichment nodes + const allNodes = useMemo(() => { + const seen = new Set(nodes.map((n) => n.id)); + return [...nodes, ...enrichedNodes.filter((n) => !seen.has(n.id))]; + }, [nodes, enrichedNodes]); + + const allEdges = useMemo(() => [...edges, ...enrichedEdges], [edges, enrichedEdges]); + + // Filter + const filtered = useMemo(() => { + let result = allNodes; + if (filter !== 'all') result = result.filter((n) => n.type === filter); + if (milFilter) result = result.filter((n) => String(n.properties.militaryUse || '').includes(milFilter)); + if (search) { + const q = search.toLowerCase(); + result = result.filter((n) => + [n.id, n.label, n.type, ...Object.values(n.properties).map(String)].join(' ').toLowerCase().includes(q), + ); + } + return result; + }, [allNodes, filter, milFilter, search]); + + const filteredIds = useMemo(() => new Set(filtered.map((n) => n.id)), [filtered]); + const filteredEdges = useMemo( + () => allEdges.filter((e) => filteredIds.has(e.source) && filteredIds.has(e.target)), + [allEdges, filteredIds], + ); + + const selectedNode = allNodes.find((n) => n.id === selectedId) || null; + + // Filter weapons from CSV + const filteredWeapons = useMemo(() => { + if (weapons.length === 0) return []; + if (!search) return weapons; + const q = search.toLowerCase(); + return weapons.filter((w) => + [w.weapon, w.developed, w.usedBy, w.militaryPurpose, w.source, w.sourceType] + .join(' ').toLowerCase().includes(q), + ); + }, [weapons, search]); + + // Nation counts + const nationCounts = useMemo(() => { + const counts: Record = {}; + for (const e of edges) { + if (e.label === 'developed' || e.label === 'employed') { + const stakeholder = nodes.find((n) => n.id === e.source); + if (stakeholder?.type === 'Stakeholder' && stakeholder.properties.subtype === 'Nation') { + counts[stakeholder.label] = (counts[stakeholder.label] || 0) + 1; + } + } + } + return Object.entries(counts).sort((a, b) => b[1] - a[1]).slice(0, 8); + }, [nodes, edges]); + + // Systems count + const systemCount = nodes.filter((n) => n.type === 'System').length; + + // Sort + const sorted = useMemo(() => { + return [...filtered].sort((a, b) => { + let va: string | number, vb: string | number; + if (sortKey === 'label') { va = a.label; vb = b.label; } + else if (sortKey === 'type') { va = a.type; vb = b.type; } + else if (sortKey === 'year') { va = Number(a.properties.year) || 0; vb = Number(b.properties.year) || 0; } + else { va = String(a.properties[sortKey] || ''); vb = String(b.properties[sortKey] || ''); } + if (typeof va === 'number' && typeof vb === 'number') return (va - vb) * sortDir; + return String(va).localeCompare(String(vb)) * sortDir; + }); + }, [filtered, sortKey, sortDir]); + + const handleSort = (key: string) => { + if (sortKey === key) setSortDir((d) => (d === 1 ? -1 : 1) as 1 | -1); + else { setSortKey(key); setSortDir(1); } + }; + + // Graph rendering + useEffect(() => { + if (view !== 'graph' || !graphRef.current || filtered.length === 0) { + if (networkRef.current) { networkRef.current.destroy(); networkRef.current = null; } + return; + } + + const isEnriched = new Set(enrichedNodes.map((n) => n.id)); + const visNodes = new DataSet( + filtered.map((n) => { + const typeColor = AIWAR_TYPE_COLORS[n.type] || '#00d4ff'; + const enriched = isEnriched.has(n.id); + return { + id: n.id, + label: n.label, + color: { + background: enriched ? 'rgba(255, 171, 0, 0.15)' : 'rgba(10, 14, 23, 0.85)', + border: enriched ? '#ffab00' : typeColor, + highlight: { background: 'rgba(10, 14, 23, 0.95)', border: '#00d4ff' }, + hover: { background: 'rgba(10, 14, 23, 0.80)', border: typeColor }, + }, + size: n.type === 'System' ? 14 : n.type === 'Person' ? 10 : 12, + title: `${n.label}\n${n.type}${n.properties.year ? ` (${n.properties.year})` : ''}${n.properties.militaryUse ? `\n${n.properties.militaryUse}` : ''}`, + }; + }), + ); + + const visEdges = new DataSet( + filteredEdges.map((e, i) => ({ + id: `e-${i}`, + from: e.source, + to: e.target, + label: e.label, + })), + ); + + const network = new Network(graphRef.current, { nodes: visNodes, edges: visEdges }, GRAPH_OPTIONS); + network.on('click', (params) => { + setSelectedId(params.nodes.length > 0 ? (params.nodes[0] as string) : null); + }); + networkRef.current = network; + + return () => { network.destroy(); networkRef.current = null; }; + }, [view, filtered, filteredEdges, enrichedNodes]); + + // Sync selection in graph + useEffect(() => { + if (networkRef.current) { + networkRef.current.selectNodes(selectedId ? [selectedId] : []); + } + }, [selectedId]); + + const handleFit = useCallback(() => { networkRef.current?.fit({ animation: true }); }, []); + + const handleEnrich = (result: ReasoningResult) => { + const newNodes: GraphNode[] = result.enrichmentNodes.map((n) => ({ + id: n.id, + label: n.label, + type: n.type, + properties: n.properties, + })); + const newEdges: GraphEdge[] = result.enrichmentEdges.map((e) => ({ + source: e.source, + target: e.target, + label: e.label, + })); + setEnrichedNodes((prev) => { + const seen = new Set(prev.map((n) => n.id)); + return [...prev, ...newNodes.filter((n) => !seen.has(n.id))]; + }); + setEnrichedEdges((prev) => [...prev, ...newEdges]); + }; + + const columns = [ + { key: 'label', label: 'Name' }, + { key: 'type', label: 'Type' }, + { key: 'year', label: 'Year' }, + { key: 'militaryUse', label: 'Military Use' }, + { key: 'status', label: 'Status' }, + ]; + + return ( +
+ {/* Top bar */} +
+
+ +

Q2 › AIWAR — AI in Warfare Research

+ {systemCount} systems + {enrichedNodes.length > 0 && ( + +{enrichedNodes.length} discovered + )} +
+
+ + +
+
+ +
+ {/* Left sidebar */} +
+
+
+

Filters

+
+
+
+
+
entity type
+
+ {FILTERS.map((f) => ( + + ))} +
+
+ +
+
military use
+
+ + {MILITARY_FILTERS.map((m) => ( + + ))} +
+
+ +
+
by nation
+
+ {nationCounts.map(([name, count]) => ( + + ))} +
+
+
+
+ + {/* Center: table or graph */} +
+ {view === 'table' ? ( +
+
+ setSearch(e.target.value)} + /> + + {weapons.length > 0 ? `${filteredWeapons.length} weapons` : `${filtered.length} rows`} + +
+
+ {weapons.length > 0 ? ( + /* Official CSV weapons table — the "innocent" view */ + + + + + + + + + + + + {filteredWeapons.map((w, i) => { + // Find matching graph node for selection + const matchNode = nodes.find((n) => + n.label.toLowerCase() === w.weapon.toLowerCase() || + n.id.toLowerCase().replace(/\s/g, '') === w.weapon.toLowerCase().replace(/\s/g, ''), + ); + return ( + matchNode && setSelectedId(matchNode.id === selectedId ? null : matchNode.id)} + > + + + + + + + ); + })} + +
handleSort('weapon')}> + Weapon{sortKey === 'weapon' && {sortDir === 1 ? '\u2191' : '\u2193'}} + handleSort('developed')}> + Year{sortKey === 'developed' && {sortDir === 1 ? '\u2191' : '\u2193'}} + handleSort('usedBy')}> + Used By{sortKey === 'usedBy' && {sortDir === 1 ? '\u2191' : '\u2193'}} + Military PurposeSource
{w.weapon}{w.developed}{w.usedBy} + {w.militaryPurpose.length > 120 ? w.militaryPurpose.slice(0, 120) + '...' : w.militaryPurpose} + {w.source}
+ ) : ( + /* Fallback: graph node table */ + + + + {columns.map((col) => ( + + ))} + + + + {sorted.map((node) => ( + setSelectedId(node.id === selectedId ? null : node.id)} + > + + + + + + + ))} + +
handleSort(col.key)}> + {col.label} + {sortKey === col.key && {sortDir === 1 ? '\u2191' : '\u2193'}} +
{node.label} + + {node.type} + + {String(node.properties.year || '')}{String(node.properties.militaryUse || '')}{String(node.properties.status || '')}
+ )} +
+
+ ) : ( +
+
+ {filtered.length === 0 ? ( +
+
No nodes match current filters
+
+ ) : ( +
+ )} +
+
+
+ system + stakeholder + civic + person + historical + {enrichedNodes.length > 0 && ( + discovered ({enrichedNodes.length}) + )} +
+
+ {filtered.length} nodes · {filteredEdges.length} edges + +
+
+
+ )} + + {/* Cypher console below */} + +
+ + {/* Right: NARS panel */} + +
+ + {/* Footer hint */} +
+ Select any weapon system and click Reason About This to discover + connections the AI finds through NARS inference. +
+
+ ); +} diff --git a/cockpit/src/components/AnalystPanel.tsx b/cockpit/src/components/AnalystPanel.tsx new file mode 100644 index 000000000..da5b77d68 --- /dev/null +++ b/cockpit/src/components/AnalystPanel.tsx @@ -0,0 +1,265 @@ +import { useState, useCallback } from 'react'; +import { TruthBadge } from './TruthBadge'; + +interface AnalysisResult { + bucket: string; + label: string; + description: string; + thinking_style: string | null; + elapsed_us: number; + thinking_steps: { + step: number; + action: string; + detail: string; + edges_before: number; + edges_after: number; + new_inferences: number; + }[]; + projections: { + label: string; + confidence: number; + basis: string; + implication: string; + }[]; + causality_chains: { + name: string; + confidence: number; + inference_type: string; + narrative: string; + edges: TruthEdge[]; + }[]; + summary: { + total_nodes_involved: number; + total_edges_found: number; + total_inferred: number; + avg_confidence: number; + key_findings: string[]; + blind_spots: string[]; + }; +} + +interface TruthEdge { + source: string; + target: string; + rel_type: string; + truth: { frequency: number; confidence: number }; + inferred: boolean; + inference_type: string | null; +} + +const BUCKETS = [ + { id: 'economic_review', label: 'Economic Review', color: '#ffb547', icon: '\uD83D\uDCB0' }, + { id: 'civil_engineering', label: 'Civil Engineering', color: '#4caf50', icon: '\uD83C\uDFD7\uFE0F' }, + { id: 'political_dynamics', label: 'Political Dynamics', color: '#e040fb', icon: '\uD83C\uDFDB\uFE0F' }, + { id: 'ai_development_impact', label: 'AI Development', color: '#00d4ff', icon: '\uD83E\uDD16' }, + { id: 'kill_chain_analysis', label: 'Kill Chain', color: '#ff637d', icon: '\u26A0\uFE0F' }, + { id: 'surveillance_ecosystem', label: 'Surveillance', color: '#ff9800', icon: '\uD83D\uDC41\uFE0F' }, +]; + +export function AnalystPanel() { + const [selectedBucket, setSelectedBucket] = useState(null); + const [result, setResult] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const runAnalysis = useCallback(async (bucketId: string) => { + setSelectedBucket(bucketId); + setLoading(true); + setError(null); + setResult(null); + + try { + const res = await fetch(`/api/analyst/analyze/${bucketId}`); + if (!res.ok) throw new Error(`HTTP ${res.status}`); + const data = await res.json(); + if (data.error) throw new Error(data.error); + setResult(data); + } catch (e) { + setError(e instanceof Error ? e.message : 'Analysis failed'); + } finally { + setLoading(false); + } + }, []); + + const selectedInfo = BUCKETS.find(b => b.id === selectedBucket); + + return ( +
+ {/* Bucket selector */} +
+ {BUCKETS.map((bucket) => ( + + ))} +
+ + {/* Loading */} + {loading && ( +
+
+ Running {selectedInfo?.label} analysis... + + Cypher queries → NARS inference → causality chains + +
+ )} + + {/* Error */} + {error && ( +
+ Analysis error: {error} +
+ The analyst runs Cypher queries through lance-graph. In demo mode (Node server), + queries return stub data. Deploy with Dockerfile (Rust binary) for live analysis. +
+
+ )} + + {/* Results */} + {result && ( +
+ {/* Header */} +
+
+

{result.label}

+ {result.description} +
+
+ {(result.elapsed_us / 1000).toFixed(0)}ms + {result.thinking_style && ( + + {result.thinking_style} + + )} +
+
+ + {/* Summary */} +
+
+
+ {result.summary.total_nodes_involved} + nodes +
+
+ {result.summary.total_edges_found} + edges +
+
+ + {result.summary.total_inferred} + + inferred +
+
+ + {(result.summary.avg_confidence * 100).toFixed(0)}% + + confidence +
+
+ + {/* Key findings */} +
+
key findings
+ {result.summary.key_findings.map((f, i) => ( +
{f}
+ ))} +
+ + {/* Blind spots */} + {result.summary.blind_spots.length > 0 && ( +
+
blind spots
+ {result.summary.blind_spots.map((f, i) => ( +
{f}
+ ))} +
+ )} +
+ + {/* Causality chains */} + {result.causality_chains.length > 0 && ( +
+
causality chains
+ {result.causality_chains.map((chain, i) => ( +
+
+ {chain.name} + 0.5 ? 'FLOW' : chain.confidence > 0.2 ? 'HOLD' : 'BLOCK'} + /> +
+
{chain.narrative}
+
+ {chain.edges.map((e, j) => ( + + {e.source} → {e.target} + {e.inferred && inferred} + + ))} +
+
+ ))} +
+ )} + + {/* Thinking steps */} +
+
thinking trace
+ {result.thinking_steps.map((step, i) => ( +
+
+ + {step.action} + + Step {step.step} +
+
{step.detail}
+
+ {step.edges_after > 0 && {step.edges_after} edges} + {step.new_inferences > 0 && +{step.new_inferences} inferred} +
+
+ ))} +
+ + {/* Projections */} + {result.projections.length > 0 && ( +
+
projections
+ {result.projections.map((p, i) => ( +
+
+ {p.label} + 0.3 ? 'FLOW' : 'HOLD'} /> +
+
{p.basis}
+
{p.implication}
+
+ ))} +
+ )} +
+ )} + + {/* Empty state */} + {!selectedBucket && !loading && ( +
+ Select an analysis bucket to create thinking through the aiwar graph. + Each bucket runs Cypher queries, applies NARS inference, and builds causality chains. +
+ )} +
+ ); +} diff --git a/cockpit/src/components/BusTicker.tsx b/cockpit/src/components/BusTicker.tsx new file mode 100644 index 000000000..68e4f0d44 --- /dev/null +++ b/cockpit/src/components/BusTicker.tsx @@ -0,0 +1,87 @@ +import { useEffect, useRef } from 'react'; +import type { WireShaderBus } from '../hooks/useShaderStream'; +import { clamp, fmt, safeNum, safeStr } from '../diagnostics/safe'; + +interface BusTickerProps { + items: WireShaderBus[]; + maxItems?: number; +} + +/** Format a u64-like fingerprint hash as a short hex tag. */ +function fpHex(n: number): string { + if (!Number.isFinite(n)) return '????????'; + // JS numbers can't hold full u64 — the bridge folds to a hash anyway. + // Take low 32 bits of the absolute value as a stable display tag. + const u = (n >>> 0).toString(16).padStart(8, '0'); + return u; +} + +export function BusTicker({ items, maxItems = 20 }: BusTickerProps) { + const listRef = useRef(null); + + useEffect(() => { + if (listRef.current) { + listRef.current.scrollTop = listRef.current.scrollHeight; + } + }, [items]); + + const safeItems = Array.isArray(items) ? items : []; + const visible = safeItems.slice(-maxItems); + + return ( +
+
+
+ B bus commits + + {safeItems.length} total + +
+
+
+ {visible.length === 0 ? ( +
+ waiting for stream… (Shift+D for diagnostics) +
+ ) : ( + visible.map((bus, i) => { + if (!bus || typeof bus !== 'object') return null; + const fpHash = safeNum(bus.cycle_fingerprint_hash, 0, 'bus.cycle_fingerprint_hash'); + const fpTag = fpHex(fpHash); + const top = Array.isArray(bus.resonance?.top_k) ? bus.resonance.top_k : []; + const energy = clamp(top[0]?.resonance, 0, 1, 'bus.resonance.top_k[0].resonance'); + const cyclesUsed = safeNum(bus.resonance?.cycles_used, 0, 'bus.resonance.cycles_used'); + const merge = safeStr(bus.gate?.merge, '—', 'bus.gate.merge'); + const edges = safeNum(bus.emitted_edge_count, 0, 'bus.emitted_edge_count'); + const tip = top + .slice(0, 5) + .map((h) => { + if (!h || typeof h !== 'object') return null; + return `${safeNum(h.row, 0)}=${fmt(h.resonance, 2)}`; + }) + .filter(Boolean) + .join(', '); + return ( +
+ + [{fpTag}] + + + + + {fmt(energy, 3, 'bus.resonance.top_k[0].resonance')} + {cyclesUsed}c + + {merge} + +
+ ); + }) + )} +
+
+ ); +} diff --git a/cockpit/src/components/CellStrip.tsx b/cockpit/src/components/CellStrip.tsx new file mode 100644 index 000000000..5b852dacd --- /dev/null +++ b/cockpit/src/components/CellStrip.tsx @@ -0,0 +1,231 @@ +import { useEffect, useState, useRef, useMemo } from 'react'; +import { useStore } from '../store'; +import { deleteCell } from '../transport'; + +// Seed notebook cells that always render (matching screenshot 2) +const SEED_CELLS = [ + { + id: 'seed-md', + language: 'markdown', + source: '', + index: 0, + }, + { + id: 'seed-gremlin', + language: 'gremlin', + source: `g.V().hasLabel('server') + .project('name', 'region', 'cpu') + .by('name') + .by('region') + .by('cpu_avg')`, + index: 1, + }, + { + id: 'seed-r', + language: 'r', + source: `library(ggplot2) + +cpu_data <- as.data.frame(cell[1]) +ggplot(cpu_data, aes(x = name, y = cpu, fill = region)) + + geom_col() + + theme_minimal() + + labs(title = "CPU Usage by Server")`, + index: 2, + }, + { + id: 'seed-sparql', + language: 'sparql', + source: `SELECT ?server ?uptime +WHERE { + ?server a :Server ; + :hasUptime ?uptime ; + :inRegion ?region . + FILTER(?region = "us-east-1") +} +ORDER BY DESC(?uptime)`, + index: 3, + }, +]; + +const LANG_COLORS: Record = { + gremlin: '#4dd0e1', + cypher: '#4dd0e1', + r: '#66bb6a', + sparql: '#ab47bc', + markdown: '#93a9bf', + python: '#ffd166', +}; + +export function CellStrip() { + const cells = useStore((s) => s.cells); + const nodes = useStore((s) => s.nodes); + const executing = useStore((s) => s.executing); + const selectedNode = useStore((s) => s.nodes.find((n) => n.id === s.selectedNodeId)); + const [runningCells, setRunningCells] = useState>(new Set()); + const prevExecuting = useRef(executing); + + // Reactive cascade animation + useEffect(() => { + if (prevExecuting.current && !executing && cells.length > 0) { + const ids = cells.map((c) => c.id); + ids.forEach((id, i) => { + setTimeout(() => { + setRunningCells((prev) => new Set([...prev, id])); + setTimeout(() => { + setRunningCells((prev) => { + const next = new Set(prev); + next.delete(id); + return next; + }); + }, 1200); + }, i * 260); + }); + } + prevExecuting.current = executing; + }, [executing, cells]); + + // Status summary + const statusSummary = useMemo(() => { + if (nodes.length === 0) return null; + const healthy = nodes.filter((n) => n.properties.status === 'healthy').length; + const warning = nodes.filter((n) => n.properties.status === 'warning').length; + const critical = nodes.filter((n) => n.properties.status === 'critical').length; + return { healthy, warning, critical, total: nodes.length }; + }, [nodes]); + + // Combine seed cells with real cells + const displayCells = useMemo(() => { + if (cells.length > 0) { + return cells.map((c, i) => ({ ...c, index: i + 1, seed: false })); + } + // Show seed cells when no real cells exist + return SEED_CELLS.map((c, i) => ({ ...c, execution_state: 'idle', outputs: [] as never[], index: i, seed: true })); + }, [cells]); + + // Take first 4 cells for the strip + const visibleCells = displayCells.slice(0, 4); + + if (visibleCells.length === 0) { + return ( +
+
+ Execute a query to populate cells +
+
+ ); + } + + return ( +
+
+
+

Notebook

+
+ +
+
+ {visibleCells.map((cell) => { + const isRunning = runningCells.has(cell.id) || (executing && cell.index === 1); + const langColor = LANG_COLORS[cell.language] || '#4dd0e1'; + const isMd = cell.language === 'markdown'; + + return ( +
+
+
+
+ {isMd ? 'MD' : cell.language === 'gremlin' ? 'GR' : cell.language === 'sparql' ? 'SQ' : cell.language.toUpperCase().slice(0, 2)} +
+ {cell.language} +
+ + {cell.index <= 1 + ? 'upstream' + : cell.index === 2 + ? 'downstream' + : 'document view'} + +
+
+ {isMd ? ( +
+

Network Topology Analysis

+

+ {selectedNode + ? <>Selected node {selectedNode.label} belongs to {String(selectedNode.properties.region || 'unknown')}. Exporting to PDF should preserve this exact state: code, graph, table, note. + : 'Notebook is the report, not a second-class export target. Panels stay visible; no wandering through tabs.'} +

+
    +
  • Every click is a tiny orchestral cue for the rest of the interface.
  • +
  • Reactive cells re-run when upstream data changes.
  • +
+
+ ) : ( + <> +
{cell.source}
+
+ {cell.language === 'r' && statusSummary ? ( + <> + Reactive summary +

+ This cell re-runs whenever the upstream graph cell changes. In the real + product, the R kernel would emit structured output and charts without + a manual run-all ritual. +

+ + + + + + +
healthy{statusSummary.healthy} / {statusSummary.total}
warning{statusSummary.warning} / {statusSummary.total}
critical{statusSummary.critical} / {statusSummary.total}
+ + ) : cell.language === 'gremlin' ? ( + <> + Graph result +

+ Local force view renders the queried subgraph as SVG/HTML. This would be supplied + by notebook-render and hydrated into the cockpit panel above. +

+ + + + + + +
Nodes returned{nodes.length}
Edges returned{useStore.getState().edges.length}
Primary focus{selectedNode?.label || 'none'}
+ + ) : ( + <> + SPARQL result +

+ Federated query against the knowledge graph. Results would populate + the table panel above with semantic triples. +

+ + )} + {!cell.seed && ( + + )} +
+ + )} +
+
+ ); + })} +
+
+ ); +} diff --git a/cockpit/src/components/CypherConsole.tsx b/cockpit/src/components/CypherConsole.tsx new file mode 100644 index 000000000..18cd3a326 --- /dev/null +++ b/cockpit/src/components/CypherConsole.tsx @@ -0,0 +1,75 @@ +import { useState } from 'react'; +import { AIWAR_QUERIES } from '../data/aiwar-seed'; +import { executeQuery } from '../transport'; + +export function CypherConsole() { + const [activeCell, setActiveCell] = useState(0); + const [results, setResults] = useState>({}); + const [running, setRunning] = useState(null); + + const handleRun = async (index: number) => { + setRunning(index); + try { + const cell = await executeQuery(AIWAR_QUERIES[index].code, 'cypher'); + const textOutput = cell.outputs.find((o) => o.type === 'text' || o.type === 'table'); + setResults((prev) => ({ + ...prev, + [index]: textOutput?.content || 'Query executed successfully', + })); + } catch (err) { + setResults((prev) => ({ + ...prev, + [index]: `Error: ${err instanceof Error ? err.message : 'Unknown error'}`, + })); + } finally { + setRunning(null); + } + }; + + return ( +
+
+
+

Cypher Console

+ pre-loaded analytical queries +
+ {AIWAR_QUERIES.length} queries +
+
+ {AIWAR_QUERIES.map((q, i) => ( +
setActiveCell(i)} + > +
+ [{i + 1}] + {q.title} +
+ +
+
+ {activeCell === i && ( + <> +
{q.description}
+
{q.code}
+ {results[i] && ( +
+ Result +
{results[i]}
+
+ )} + + )} +
+ ))} +
+
+ ); +} diff --git a/cockpit/src/components/DataSourceCard.tsx b/cockpit/src/components/DataSourceCard.tsx new file mode 100644 index 000000000..f48f356de --- /dev/null +++ b/cockpit/src/components/DataSourceCard.tsx @@ -0,0 +1,44 @@ +interface DataSourceCardProps { + title: string; + subtitle: string; + nodeCount: string; + edgeCount: string; + description: string; + accent: string; + onLaunch: () => void; + actionLabel?: string; +} + +export function DataSourceCard({ + title, + subtitle, + nodeCount, + edgeCount, + description, + accent, + onLaunch, + actionLabel = 'Launch', +}: DataSourceCardProps) { + return ( +
+
+

{title}

+ {subtitle} +
+
+
+ {nodeCount} + nodes +
+
+ {edgeCount} + edges +
+
+

{description}

+ +
+ ); +} diff --git a/cockpit/src/components/DataStatusBar.tsx b/cockpit/src/components/DataStatusBar.tsx new file mode 100644 index 000000000..284e7c38e --- /dev/null +++ b/cockpit/src/components/DataStatusBar.tsx @@ -0,0 +1,67 @@ +interface DataSource { + name: string; + file: string; + status: 'loading' | 'loaded' | 'error' | 'not_found' | 'found' | 'embedded' | 'empty' | 'static'; + detail: string; + elapsed_ms?: number; + count?: number; +} + +interface DataStatusBarProps { + sources: DataSource[]; +} + +const STATUS_ICONS: Record = { + loading: { color: '#93a9bf', label: 'loading' }, + loaded: { color: '#35d07f', label: 'loaded' }, + found: { color: '#35d07f', label: 'found' }, + embedded: { color: '#35d07f', label: 'embedded' }, + static: { color: '#4dd0e1', label: 'static' }, + error: { color: '#ff637d', label: 'error' }, + not_found: { color: '#ffb547', label: 'not found' }, + empty: { color: '#ffb547', label: 'empty' }, +}; + +function buildTooltip(src: DataSource): string { + const elapsed = src.elapsed_ms ? ` (${src.elapsed_ms}ms)` : ''; + // Make fallback / live state explicit so the user is never misled + // by a raw HTTP code or a generic "loaded" label. + switch (src.status) { + case 'error': + case 'not_found': + case 'empty': + return `${src.name}: FALLBACK / using seed data — ${src.detail}${elapsed}`; + case 'loaded': + return `${src.name}: LIVE / loaded from live graph engine — ${src.detail}${elapsed}`; + case 'found': + return `${src.name}: LIVE / found on live graph engine — ${src.detail}${elapsed}`; + case 'embedded': + return `${src.name}: embedded seed bundle — ${src.detail}${elapsed}`; + case 'static': + return `${src.name}: static asset — ${src.detail}${elapsed}`; + case 'loading': + return `${src.name}: loading… — ${src.detail}${elapsed}`; + default: + return `${src.name}: ${src.detail}${elapsed}`; + } +} + +export function DataStatusBar({ sources }: DataStatusBarProps) { + return ( + + {sources.map((src) => { + const info = STATUS_ICONS[src.status] || STATUS_ICONS.loading; + return ( + + + {src.file.split('/').pop()?.split('.')[0]} + + ); + })} + + ); +} diff --git a/cockpit/src/components/DiagnosticsOverlay.tsx b/cockpit/src/components/DiagnosticsOverlay.tsx new file mode 100644 index 000000000..11c065990 --- /dev/null +++ b/cockpit/src/components/DiagnosticsOverlay.tsx @@ -0,0 +1,262 @@ +import { useEffect, useMemo } from 'react'; +import { useDiagnostics, diagSummary, type DiagEntry, type EndpointHealth } from '../diagnostics/store'; + +const LEVEL_COLORS: Record = { + info: '#4dd0e1', + warn: '#ffb547', + error: '#ff637d', +}; + +const STATUS_COLORS: Record = { + healthy: '#35d07f', + degraded: '#ffb547', + offline: '#ff637d', + unknown: '#666', +}; + +function fmtTs(ts: number): string { + if (!ts) return '—'; + const d = new Date(ts); + return d.toLocaleTimeString('en-US', { hour12: false }) + '.' + String(d.getMilliseconds()).padStart(3, '0'); +} + +function age(ts: number): string { + if (!ts) return '—'; + const s = Math.round((Date.now() - ts) / 1000); + if (s < 60) return `${s}s`; + if (s < 3600) return `${Math.round(s / 60)}m`; + return `${Math.round(s / 3600)}h`; +} + +export function DiagnosticsBadge() { + // NOTE: subscribe to the stable `entries` array, NOT to `diagSummary(s)`. + // zustand v5 (on React's useSyncExternalStore) compares the selector result + // with Object.is after every render. `diagSummary` allocates a fresh object + // each call, so the comparison is always false → React thinks the store + // changed → re-render → re-select → new object → infinite loop (React #185, + // "Maximum update depth exceeded"). Derive the summary with useMemo instead. + const entries = useDiagnostics((s) => s.entries); + const summary = useMemo(() => diagSummary({ entries }), [entries]); + const sse = useDiagnostics((s) => s.sse); + const endpoints = useDiagnostics((s) => s.endpoints); + const toggle = useDiagnostics((s) => s.toggleOverlay); + + // Aggregate worst endpoint state + const worstEndpoint = useMemo(() => { + const order: Record = { healthy: 0, unknown: 1, degraded: 2, offline: 3 }; + let worst = 'healthy'; + for (const e of Object.values(endpoints)) { + if ((order[e.status] ?? 0) > (order[worst] ?? 0)) worst = e.status; + } + return worst; + }, [endpoints]); + + // Combined level: take the worst of (entries, endpoints, sse) + const level: 'good' | 'warn' | 'error' = useMemo(() => { + if (summary.level === 'error' || worstEndpoint === 'offline') return 'error'; + if (summary.level === 'warn' || worstEndpoint === 'degraded' || !sse.connected) return 'warn'; + return 'good'; + }, [summary, worstEndpoint, sse.connected]); + + const dotColor = level === 'error' ? '#ff637d' : level === 'warn' ? '#ffb547' : '#35d07f'; + const text = level === 'error' + ? `${summary.errorCount} ERR` + : level === 'warn' + ? `${summary.warnCount + summary.errorCount} warn` + : 'healthy'; + + return ( + + ); +} + +function EndpointRow({ ep }: { ep: EndpointHealth }) { + return ( + + + + {ep.label} + + {ep.url} + {ep.lastStatus ? `HTTP ${ep.lastStatus}` : '—'} + {ep.lastDurationMs ? `${ep.lastDurationMs}ms` : '—'} + {age(ep.lastChecked)} + + {ep.lastError ?? (ep.status === 'healthy' ? 'ok' : '')} + + + ); +} + +function EntryRow({ e }: { e: DiagEntry }) { + return ( + + {fmtTs(e.ts)} + + + {e.level} + + {e.source} + {e.category} + {e.field ?? e.endpoint ?? '—'} + + {e.message} + {e.expected && ( +
+ expected: {e.expected} · received: {e.received} +
+ )} + + + ); +} + +export function DiagnosticsOverlay() { + const open = useDiagnostics((s) => s.overlayOpen); + const setOpen = useDiagnostics((s) => s.setOverlayOpen); + const entries = useDiagnostics((s) => s.entries); + const endpoints = useDiagnostics((s) => s.endpoints); + const sse = useDiagnostics((s) => s.sse); + const fieldNaN = useDiagnostics((s) => s.fieldNaNCount); + const clear = useDiagnostics((s) => s.clear); + const paused = useDiagnostics((s) => s.paused); + const setPaused = useDiagnostics((s) => s.setPaused); + + // Keyboard shortcut: Shift+D opens/closes + useEffect(() => { + const onKey = (e: KeyboardEvent) => { + if (e.shiftKey && (e.key === 'D' || e.key === 'd')) { + e.preventDefault(); + setOpen(!open); + } else if (e.key === 'Escape' && open) { + setOpen(false); + } + }; + window.addEventListener('keydown', onKey); + return () => window.removeEventListener('keydown', onKey); + }, [open, setOpen]); + + if (!open) return null; + + const recent = [...entries].reverse().slice(0, 200); + const endpointList = Object.values(endpoints).sort((a, b) => a.label.localeCompare(b.label)); + const nanFields = Object.entries(fieldNaN).sort((a, b) => b[1] - a[1]); + + return ( +
+
+
+
+

Diagnostics — wiring map

+ Shift+D to toggle · Esc to close +
+
+ + + +
+
+ +
+ {/* SSE state */} +
+

SSE — /v1/shader/stream

+
+
+ + {sse.connected ? 'connected' : 'disconnected'} +
+
reconnects: {sse.reconnectCount}
+
last event: {sse.lastEventType} · {age(sse.lastEventTs)} ago
+
bytes: {sse.bytesReceived}
+
url: {sse.url}
+
+
+ + {/* Endpoints */} +
+

Endpoints ({endpointList.length})

+ {endpointList.length === 0 ? ( +
No endpoint probes registered yet.
+ ) : ( + + + + + + + + {endpointList.map((ep) => )} + +
labelurlstatuslatcheckedlast error / shape
+ )} +
+ + {/* NaN field tracker */} + {nanFields.length > 0 && ( +
+

NaN / shape mismatches by field

+ + + + + + {nanFields.map(([k, v]) => ( + + + + + ))} + +
fieldcount
{k}{v}
+
+ )} + + {/* Recent entries */} +
+

Recent ({entries.length} total · showing {recent.length})

+ {recent.length === 0 ? ( +
No diagnostic entries yet. All systems quiet.
+ ) : ( + + + + + + + + {recent.map((e) => )} + +
timelvlsrccatfield/epmessage
+ )} +
+
+
+
+ ); +} diff --git a/cockpit/src/components/EnergyField.tsx b/cockpit/src/components/EnergyField.tsx new file mode 100644 index 000000000..3b7f486f7 --- /dev/null +++ b/cockpit/src/components/EnergyField.tsx @@ -0,0 +1,119 @@ +import { useEffect, useRef } from 'react'; +import type { WireShaderResonance } from '../hooks/useShaderStream'; +import { safeNum, clamp } from '../diagnostics/safe'; + +interface EnergyFieldProps { + resonance: WireShaderResonance | null; + width?: number; + height?: number; +} + +const COLS = 64; +const ROWS = 64; + +export function EnergyField({ resonance, width = 256, height = 200 }: EnergyFieldProps) { + const canvasRef = useRef(null); + + useEffect(() => { + const canvas = canvasRef.current; + if (!canvas) return; + const ctx = canvas.getContext('2d'); + if (!ctx) return; + + const cellW = width / COLS; + const cellH = height / ROWS; + + // Build a sparse energy map from top_k — defensively handle bad shape + const energyMap = new Float32Array(COLS * ROWS); + if (resonance && Array.isArray(resonance.top_k)) { + for (const hit of resonance.top_k) { + if (!hit || typeof hit !== 'object') continue; + const idx = safeNum(hit.row, 0, 'resonance.top_k[].row'); + const energy = clamp(hit.resonance, 0, 1, 'resonance.top_k[].resonance'); + if (energy <= 0) continue; + const cell = Math.floor(idx) % (COLS * ROWS); + if (cell < 0 || cell >= COLS * ROWS) continue; + energyMap[cell] = Math.max(energyMap[cell], energy); + // Gaussian spread to neighbors + const cx = cell % COLS; + const cy = Math.floor(cell / COLS); + for (let dy = -2; dy <= 2; dy++) { + for (let dx = -2; dx <= 2; dx++) { + const nx = cx + dx, ny = cy + dy; + if (nx < 0 || nx >= COLS || ny < 0 || ny >= ROWS) continue; + const dist = Math.sqrt(dx * dx + dy * dy); + const spread = energy * Math.exp(-dist * 1.5); + energyMap[ny * COLS + nx] = Math.max(energyMap[ny * COLS + nx], spread); + } + } + } + } + + // Draw cells + ctx.clearRect(0, 0, width, height); + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const e = energyMap[r * COLS + c]; + if (e < 0.01) continue; + const alpha = Math.min(e, 1.0); + const hue = 175 - e * 55; + ctx.fillStyle = `hsla(${hue}, 100%, 55%, ${alpha.toFixed(2)})`; + ctx.fillRect(c * cellW, r * cellH, cellW - 0.5, cellH - 0.5); + } + } + + // Draw "no data" placeholder + if (!resonance || !Array.isArray(resonance.top_k) || resonance.top_k.length === 0) { + ctx.font = '11px monospace'; + ctx.fillStyle = '#444'; + ctx.textAlign = 'center'; + ctx.fillText('Ψ no resonance events', width / 2, height / 2); + ctx.fillStyle = '#333'; + ctx.font = '9px monospace'; + ctx.fillText('Shift+D for diagnostics', width / 2, height / 2 + 14); + ctx.textAlign = 'left'; + return; + } + + // Draw top-k labels — show row + cycle_index + ctx.font = '8px monospace'; + ctx.fillStyle = '#ffffff99'; + for (const hit of resonance.top_k.slice(0, 3)) { + if (!hit || typeof hit !== 'object') continue; + const idx = safeNum(hit.row, 0, 'resonance.top_k_label.row'); + const cycleIdx = safeNum(hit.cycle_index, 0, 'resonance.top_k_label.cycle_index'); + const cell = Math.floor(idx) % (COLS * ROWS); + const cx = (cell % COLS) * cellW + 2; + const cy = Math.floor(cell / COLS) * cellH + 8; + ctx.fillText(`${Math.floor(idx)}@${cycleIdx}`, cx, cy); + } + }, [resonance, width, height]); + + const cyclesUsed = resonance ? safeNum(resonance.cycles_used, 0, 'resonance.cycles_used') : 0; + const hitCount = resonance ? safeNum(resonance.hit_count, 0, 'resonance.hit_count') : 0; + const entropy = resonance ? safeNum(resonance.entropy, 0, 'resonance.entropy') : 0; + const stdDev = resonance ? safeNum(resonance.std_dev, 0, 'resonance.std_dev') : 0; + + return ( +
+
+
+ Ψ resonance field + {resonance ? ( + + cycles {cyclesUsed} · {hitCount} hits · H={entropy.toFixed(2)} · σ={stdDev.toFixed(2)} + + ) : ( + · awaiting + )} +
+
+ +
+ ); +} diff --git a/cockpit/src/components/ErrorBoundary.tsx b/cockpit/src/components/ErrorBoundary.tsx new file mode 100644 index 000000000..3fcf8a1e6 --- /dev/null +++ b/cockpit/src/components/ErrorBoundary.tsx @@ -0,0 +1,57 @@ +import { Component, type ReactNode, type ErrorInfo } from 'react'; +import { useDiagnostics } from '../diagnostics/store'; + +interface Props { + children: ReactNode; + /** Identifier shown in the diagnostics log and the error UI. */ + scope: string; + /** Render override when crashed. Default = inline error card. */ + fallback?: (err: Error, scope: string, reset: () => void) => ReactNode; +} + +interface State { + error: Error | null; +} + +export class ErrorBoundary extends Component { + state: State = { error: null }; + + static getDerivedStateFromError(error: Error): State { + return { error }; + } + + componentDidCatch(error: Error, info: ErrorInfo) { + useDiagnostics.getState().add({ + source: 'boundary', + level: 'error', + category: 'crash', + field: this.props.scope, + message: `[${this.props.scope}] ${error.message}`, + detail: { stack: error.stack, componentStack: info.componentStack }, + }); + } + + reset = () => this.setState({ error: null }); + + render() { + if (this.state.error) { + if (this.props.fallback) return this.props.fallback(this.state.error, this.props.scope, this.reset); + return ( +
+
+ + {this.props.scope} crashed + +
+
{this.state.error.message}
+
+ See diagnostics overlay (Shift+D) for full stack & wiring map. +
+
+ ); + } + return this.props.children; + } +} diff --git a/cockpit/src/components/FreeEnergyDial.tsx b/cockpit/src/components/FreeEnergyDial.tsx new file mode 100644 index 000000000..2a2445244 --- /dev/null +++ b/cockpit/src/components/FreeEnergyDial.tsx @@ -0,0 +1,93 @@ +import type { WireFreeEnergy } from '../hooks/useShaderStream'; +import { clamp, fmt, safeNum } from '../diagnostics/safe'; + +interface FreeEnergyDialProps { + freeEnergy: WireFreeEnergy | null; +} + +function arc(cx: number, cy: number, r: number, startDeg: number, endDeg: number): string { + const toRad = (d: number) => (d * Math.PI) / 180; + const x1 = cx + r * Math.cos(toRad(startDeg)); + const y1 = cy + r * Math.sin(toRad(startDeg)); + const x2 = cx + r * Math.cos(toRad(endDeg)); + const y2 = cy + r * Math.sin(toRad(endDeg)); + const large = Math.abs(endDeg - startDeg) > 180 ? 1 : 0; + return `M ${x1} ${y1} A ${r} ${r} 0 ${large} 1 ${x2} ${y2}`; +} + +export function FreeEnergyDial({ freeEnergy }: FreeEnergyDialProps) { + // Safe coercion — every numeric field reports NaN/missing to diagnostics + const fe = clamp(freeEnergy?.free_energy, 0, 2, 'freeEnergy.free_energy'); + const likelihood = clamp(freeEnergy?.likelihood, 0, 1, 'freeEnergy.likelihood'); + const kl = clamp(freeEnergy?.kl, 0, 1, 'freeEnergy.kl'); + const belowHomeostasis = freeEnergy?.below_homeostasis === true; + const stale = freeEnergy === null; + + // Dial: 240° span, 0=low (good), 1=high (bad) + const START = 210; + const SPAN = 240; + // fe is clamped to [0, 2] — the dial saturates above 1 + const dialPos = clamp(fe / 1.0, 0, 1, 'freeEnergy.dialPos'); + const needleDeg = START - dialPos * SPAN; + + const cx = 60, cy = 60, r = 48; + const needleRad = (needleDeg * Math.PI) / 180; + const needleX = safeNum(cx + 38 * Math.cos(needleRad), cx, 'dial.needleX'); + const needleY = safeNum(cy + 38 * Math.sin(needleRad), cy, 'dial.needleY'); + + const color = stale ? '#666' : belowHomeostasis ? '#35d07f' : fe > 0.7 ? '#e53935' : fe > 0.4 ? '#ffb547' : '#35d07f'; + + return ( +
+
+
+ F free energy + {stale && ( + + · awaiting + + )} +
+
+
+ + {/* Background arc */} + + {/* Likelihood arc (green) */} + + {/* KL arc (yellow) */} + + {/* Needle */} + + + {/* Labels */} + + {stale ? '—' : fmt(fe, 3, 'freeEnergy.free_energy')} + + L + KL + +
+
L {fmt(likelihood, 3, 'freeEnergy.likelihood')}
+
KL {fmt(kl, 3, 'freeEnergy.kl')}
+ {belowHomeostasis && ( +
⊕ homeostasis
+ )} + {stale && ( +
no /v1/shader/stream events yet
+ )} +
+
+
+ ); +} diff --git a/cockpit/src/components/GraphPanel.tsx b/cockpit/src/components/GraphPanel.tsx new file mode 100644 index 000000000..95e24f95d --- /dev/null +++ b/cockpit/src/components/GraphPanel.tsx @@ -0,0 +1,265 @@ +import { useEffect, useRef, useCallback, useMemo } from 'react'; +import { Network, type Options } from 'vis-network'; +import { DataSet } from 'vis-data'; +import { useStore } from '../store'; + +const TYPE_COLORS: Record = { + Server: '#4dd0e1', + Gateway: '#4dd0e1', + Database: '#ffd166', + Cache: '#ff7043', + LoadBalancer: '#66bb6a', + Monitor: '#ab47bc', + Queue: '#ef5350', + CDN: '#42a5f5', + DNS: '#78909c', + Secrets: '#8d6e63', + Search: '#7e57c2', + Service: '#9b8cff', + Worker: '#9ccc65', +}; + +const STATUS_COLORS: Record = { + healthy: '#35d07f', + warning: '#ffb547', + critical: '#ff637d', +}; + +const NETWORK_OPTIONS: Options = { + nodes: { + shape: 'dot', + font: { + color: '#d9e9f9', + face: 'Inter, ui-sans-serif, system-ui, sans-serif', + size: 12, + strokeWidth: 3, + strokeColor: '#0a0e17', + }, + borderWidth: 2.5, + shadow: { enabled: true, color: 'rgba(0,0,0,0.5)', size: 14, x: 0, y: 4 }, + }, + edges: { + color: { color: 'rgba(125,162,186,0.35)', highlight: '#4dd0e1', hover: 'rgba(77,208,225,0.6)' }, + font: { + color: 'rgba(147,169,191,0.65)', + size: 9, + face: 'Inter, ui-sans-serif, system-ui, sans-serif', + strokeWidth: 0, + align: 'middle', + }, + width: 1.2, + smooth: { enabled: true, type: 'continuous', roundness: 0.12 }, + selectionWidth: 2.5, + hoverWidth: 0.6, + arrows: { to: { enabled: true, scaleFactor: 0.5, type: 'arrow' } }, + }, + physics: { + solver: 'forceAtlas2Based', + forceAtlas2Based: { + gravitationalConstant: -90, + centralGravity: 0.005, + springLength: 170, + springConstant: 0.03, + damping: 0.42, + avoidOverlap: 0.3, + }, + stabilization: { iterations: 200, fit: true }, + }, + interaction: { + hover: true, + tooltipDelay: 80, + zoomView: true, + dragView: true, + dragNodes: true, + multiselect: false, + navigationButtons: false, + keyboard: false, + }, + layout: { improvedLayout: true }, +}; + +export function GraphPanel() { + const containerRef = useRef(null); + const networkRef = useRef(null); + const nodes = useStore((s) => s.nodes); + const edges = useStore((s) => s.edges); + const filter = useStore((s) => s.filter); + const selectedNodeId = useStore((s) => s.selectedNodeId); + const selectNode = useStore((s) => s.selectNode); + + // Filter nodes based on left rail selection + const filteredNodes = useMemo(() => { + if (filter === 'all') return nodes; + if (filter === 'warning') return nodes.filter((n) => n.properties.status !== 'healthy'); + return nodes.filter((n) => n.type === filter); + }, [nodes, filter]); + + const filteredIds = useMemo(() => new Set(filteredNodes.map((n) => n.id)), [filteredNodes]); + const filteredEdges = useMemo( + () => edges.filter((e) => filteredIds.has(e.source) && filteredIds.has(e.target)), + [edges, filteredIds], + ); + + // Derive legend from visible node types + const legendTypes = useMemo(() => { + const types = new Set(filteredNodes.map((n) => n.type)); + return Array.from(types).slice(0, 7); + }, [filteredNodes]); + + // Status counts for footer badges + const statusCounts = useMemo(() => { + const healthy = filteredNodes.filter((n) => n.properties.status === 'healthy').length; + const warning = filteredNodes.filter((n) => n.properties.status === 'warning').length; + const critical = filteredNodes.filter((n) => n.properties.status === 'critical').length; + return { healthy, warning, critical }; + }, [filteredNodes]); + + useEffect(() => { + if (!containerRef.current || filteredNodes.length === 0) { + if (networkRef.current) { + networkRef.current.destroy(); + networkRef.current = null; + } + return; + } + + const visNodes = new DataSet( + filteredNodes.map((n) => { + const typeColor = TYPE_COLORS[n.type] || '#4dd0e1'; + const statusColor = STATUS_COLORS[String(n.properties.status)] || '#35d07f'; + const conns = typeof n.properties.connections === 'number' ? n.properties.connections : 4; + const cpu = typeof n.properties.cpu === 'number' ? n.properties.cpu : 0.3; + // Size scales with connections, databases and caches get a boost + const baseSize = n.type === 'Database' || n.type === 'Cache' ? 16 : 12; + const size = baseSize + Math.min(conns, 12) * 1.8; + return { + id: n.id, + label: n.label, + color: { + background: `rgba(10, 14, 23, ${0.85 + cpu * 0.12})`, + border: statusColor, + highlight: { background: 'rgba(10, 14, 23, 0.95)', border: '#4dd0e1' }, + hover: { background: 'rgba(10, 14, 23, 0.80)', border: typeColor }, + }, + size, + title: `${n.label}\n${n.type} \u00b7 ${n.properties.status}\n${n.properties.region}\nCPU: ${(cpu * 100).toFixed(0)}%`, + font: { + color: statusColor === '#ff637d' ? '#ff637d' : '#d9e9f9', + }, + }; + }), + ); + + const visEdges = new DataSet( + filteredEdges.map((e, i) => ({ + id: `e-${i}`, + from: e.source, + to: e.target, + label: e.label, + })), + ); + + const network = new Network( + containerRef.current, + { nodes: visNodes, edges: visEdges }, + NETWORK_OPTIONS, + ); + + network.on('click', (params) => { + if (params.nodes.length > 0) { + selectNode(params.nodes[0] as string); + } else { + selectNode(null); + } + }); + + networkRef.current = network; + + return () => { + network.destroy(); + networkRef.current = null; + }; + }, [filteredNodes, filteredEdges, selectNode]); + + useEffect(() => { + if (!networkRef.current) return; + networkRef.current.selectNodes(selectedNodeId ? [selectedNodeId] : []); + }, [selectedNodeId]); + + const handleFit = useCallback(() => { + networkRef.current?.fit({ animation: true }); + }, []); + + const selectedNode = nodes.find((n) => n.id === selectedNodeId); + + return ( +
+
+
+

Graph

+ force-directed · linked to sidebar + table + cells +
+
+ {filteredNodes.length} nodes · {filteredEdges.length} edges +
selection drives all views
+
+
+
+ {filteredNodes.length === 0 ? ( +
+ + + + + + + +
Run a query to see the graph
+
+ ) : ( + <> +
+ {/* Overlay cards */} +
+
+ Auto mode +

+ {selectedNode + ? `${selectedNode.label} is the focus node across the cockpit.` + : 'Click a node to propagate selection through all panels.'} +

+
+
+ Viewport +

Wheel to zoom. Drag nodes. Layout settles with a soft spring and low-gravity drift.

+
+
+ + )} +
+
+
+ {legendTypes.map((type) => ( + + {type.toLowerCase()} + + ))} +
+
+ {selectedNode && ( + selected / {selectedNode.label} + )} + {statusCounts.warning > 0 && ( + {statusCounts.warning} warning + )} + {statusCounts.critical > 0 && ( + {statusCounts.critical} critical + )} + +
+
+
+ ); +} diff --git a/cockpit/src/components/Inspector.tsx b/cockpit/src/components/Inspector.tsx new file mode 100644 index 000000000..9354830ea --- /dev/null +++ b/cockpit/src/components/Inspector.tsx @@ -0,0 +1,238 @@ +import { useEffect, useRef, useMemo } from 'react'; +import { useStore } from '../store'; + +const TYPE_COLORS: Record = { + Server: '#4dd0e1', Gateway: '#4dd0e1', Database: '#ffd166', Cache: '#ff7043', + LoadBalancer: '#66bb6a', Monitor: '#ab47bc', Queue: '#ef5350', CDN: '#42a5f5', + DNS: '#78909c', Secrets: '#8d6e63', Search: '#7e57c2', Service: '#9b8cff', Worker: '#9ccc65', +}; + +const STATUS_COLORS: Record = { + healthy: '#35d07f', warning: '#ffb547', critical: '#ff637d', +}; + +function drawSparkline(canvas: HTMLCanvasElement, values: number[], status: string) { + const ctx = canvas.getContext('2d'); + if (!ctx) return; + const w = canvas.width; + const h = canvas.height; + const dpr = window.devicePixelRatio || 1; + canvas.width = w * dpr; + canvas.height = h * dpr; + ctx.scale(dpr, dpr); + canvas.style.width = w + 'px'; + canvas.style.height = h + 'px'; + + ctx.clearRect(0, 0, w, h); + const color = STATUS_COLORS[status] || '#4dd0e1'; + const max = Math.max(...values) + 4; + const min = Math.min(...values) - 4; + + // Grid lines + ctx.strokeStyle = 'rgba(77, 208, 225, 0.08)'; + ctx.lineWidth = 0.5; + for (let i = 1; i <= 3; i++) { + const y = (h / 4) * i; + ctx.beginPath(); + ctx.moveTo(0, y); + ctx.lineTo(w, y); + ctx.stroke(); + } + + // Fill area under curve + const gradient = ctx.createLinearGradient(0, 0, 0, h); + gradient.addColorStop(0, color.replace(')', ', 0.15)').replace('rgb', 'rgba')); + gradient.addColorStop(1, 'rgba(0,0,0,0)'); + ctx.fillStyle = gradient; + ctx.beginPath(); + values.forEach((v, i) => { + const x = (w - 16) * (i / (values.length - 1)) + 8; + const y = h - 10 - ((v - min) / (max - min)) * (h - 20); + if (i === 0) ctx.moveTo(x, y); + else ctx.lineTo(x, y); + }); + const lastX = (w - 16) + 8; + ctx.lineTo(lastX, h); + ctx.lineTo(8, h); + ctx.closePath(); + ctx.fill(); + + // Line + ctx.strokeStyle = color; + ctx.lineWidth = 2; + ctx.lineJoin = 'round'; + ctx.lineCap = 'round'; + ctx.beginPath(); + values.forEach((v, i) => { + const x = (w - 16) * (i / (values.length - 1)) + 8; + const y = h - 10 - ((v - min) / (max - min)) * (h - 20); + if (i === 0) ctx.moveTo(x, y); + else ctx.lineTo(x, y); + }); + ctx.stroke(); + + // Terminal dot (latest point) + const lastVal = values[values.length - 1]; + const lx = (w - 16) + 8; + const ly = h - 10 - ((lastVal - min) / (max - min)) * (h - 20); + ctx.fillStyle = color; + ctx.beginPath(); + ctx.arc(lx, ly, 3.5, 0, Math.PI * 2); + ctx.fill(); + // Glow ring + ctx.strokeStyle = color; + ctx.lineWidth = 1; + ctx.globalAlpha = 0.4; + ctx.beginPath(); + ctx.arc(lx, ly, 6, 0, Math.PI * 2); + ctx.stroke(); + ctx.globalAlpha = 1; +} + +export function Inspector() { + const selectedNodeId = useStore((s) => s.selectedNodeId); + const nodes = useStore((s) => s.nodes); + const edges = useStore((s) => s.edges); + const selectNode = useStore((s) => s.selectNode); + const sparkRef = useRef(null); + + const node = nodes.find((n) => n.id === selectedNodeId); + + const connections = useMemo(() => { + if (!selectedNodeId) return []; + return edges + .filter((e) => e.source === selectedNodeId || e.target === selectedNodeId) + .map((e) => { + const isOutbound = e.source === selectedNodeId; + return { + kind: e.label, + peer: isOutbound ? e.target : e.source, + direction: isOutbound ? 'outbound' : 'inbound', + arrow: isOutbound ? '\u2192' : '\u2190', + }; + }); + }, [edges, selectedNodeId]); + + // Compute degree + const degree = useMemo(() => { + if (!selectedNodeId) return 0; + return edges.filter((e) => e.source === selectedNodeId || e.target === selectedNodeId).length; + }, [edges, selectedNodeId]); + + // Generate sparkline data from CPU property + const sparkData = useMemo(() => { + if (!node) return []; + const cpu = typeof node.properties.cpu === 'number' ? node.properties.cpu * 100 : 40; + return Array.from({ length: 12 }, (_, i) => + Math.round(cpu + (Math.sin(i * 0.7) * 8) + (Math.cos(i * 0.3) * 4) + (i * 0.8)), + ); + }, [node]); + + useEffect(() => { + if (sparkRef.current && sparkData.length > 0 && node) { + drawSparkline(sparkRef.current, sparkData, String(node.properties.status || 'healthy')); + } + }, [sparkData, node]); + + if (!node) { + return ( +
+
+
+

Properties

+ properties · metadata · neighbors · sparkline +
+
+
+ + + + + + + +
+ Select a node to view intelligence +
+
+
+ ); + } + + const color = TYPE_COLORS[node.type] || '#4dd0e1'; + const statusStr = String(node.properties.status || 'healthy'); + const statusColor = STATUS_COLORS[statusStr] || '#35d07f'; + + return ( +
+
+
+

Properties

+ properties · metadata · neighbors · sparkline +
+
live linked
+
+
+ {/* Node identity card */} +
+
+
+ {node.type.slice(0, 2).toUpperCase()} +
+
+

{node.label}

+ + {node.type} · {statusStr} + +
+
+
+ + {/* Attributes */} +
+
attributes
+
+
id
{node.id}
+
region
{String(node.properties.region || '')}
+
status
{statusStr}
+
compute
{typeof node.properties.cpu === 'number' ? `${(node.properties.cpu * 100).toFixed(0)}% cpu, degree ${degree}` : 'n/a'}
+
memory
{typeof node.properties.memory_gb === 'number' ? `${node.properties.memory_gb} GB` : 'n/a'}
+
connections
{String(node.properties.connections || degree)}
+
+
+ + {/* Connections */} + {connections.length > 0 && ( +
+
connections ({connections.length})
+
+ {connections.map((c, i) => ( + + ))} +
+
+ )} + + {/* Sparkline */} +
+
latency trend
+ +
single-click updates every instrument on screen
+
+
+
+ ); +} diff --git a/cockpit/src/components/LeftRail.tsx b/cockpit/src/components/LeftRail.tsx new file mode 100644 index 000000000..39d6297ee --- /dev/null +++ b/cockpit/src/components/LeftRail.tsx @@ -0,0 +1,119 @@ +import { useMemo } from 'react'; +import { useStore } from '../store'; +import { executeQuery } from '../transport'; + +const FILTERS = [ + { key: 'all', label: 'all' }, + { key: 'Server', label: 'servers' }, + { key: 'Database', label: 'databases' }, + { key: 'Service', label: 'services' }, + { key: 'warning', label: 'at risk' }, +]; + +const EXAMPLES = [ + { + title: 'Infrastructure path', + code: "g.V().hasLabel('server').outE().inV().path()", + lang: 'gremlin', + }, + { + title: 'Cypher service fanout', + code: "MATCH (s:Server)-[:CALLS]->(svc:Service) RETURN s, svc LIMIT 25", + lang: 'cypher', + }, + { + title: 'R rollup', + code: 'services %>% count(status) %>% arrange(desc(n))', + lang: 'r', + }, + { + title: 'SPARQL dependency', + code: 'PREFIX app: \nSELECT ?service ?db WHERE { ?service app:dependsOn ?db . }', + lang: 'sparql', + }, +]; + +export function LeftRail() { + const nodes = useStore((s) => s.nodes); + const edges = useStore((s) => s.edges); + const filter = useStore((s) => s.filter); + const setFilter = useStore((s) => s.setFilter); + + const metrics = useMemo(() => { + const healthy = nodes.filter( + (n) => n.properties.status === 'healthy', + ).length; + const alerts = nodes.length - healthy; + return { nodes: nodes.length, edges: edges.length, healthy, alerts }; + }, [nodes, edges]); + + return ( +
+
+
+

Situation

+ overview · filters · quick jumps +
+
healthy
+
+
+ {/* Metrics */} +
+
+
Nodes
+
{metrics.nodes}
+
live graph scope
+
+
+
Edges
+
{metrics.edges}
+
visible paths
+
+
+
Healthy
+
{metrics.healthy}
+
green signals
+
+
+
Alerts
+
{metrics.alerts}
+
amber + red
+
+
+ + {/* Filters */} +
+
filters
+
+ {FILTERS.map((f) => ( + + ))} +
+
+ + {/* Example queries */} +
+
example cells
+
+ {EXAMPLES.map((ex) => ( + + ))} +
+
+
+
+ ); +} diff --git a/cockpit/src/components/NarsPanel.tsx b/cockpit/src/components/NarsPanel.tsx new file mode 100644 index 000000000..0f4d7433d --- /dev/null +++ b/cockpit/src/components/NarsPanel.tsx @@ -0,0 +1,233 @@ +import { useState } from 'react'; +import type { GraphNode, GraphEdge } from '../store'; +import { TruthBadge } from './TruthBadge'; +import { ENRICHMENT_INDEX, getDefaultReasoning, type ReasoningResult, type EnrichmentEdge } from '../data/aiwar-seed'; +import { runNarsForNode } from '../transport'; + +interface NarsPanelProps { + selectedNode: GraphNode | null; + edges: GraphEdge[]; + onEnrich: (result: ReasoningResult) => void; +} + +export function NarsPanel({ selectedNode, edges, onEnrich }: NarsPanelProps) { + const [reasoning, setReasoning] = useState(null); + const [running, setRunning] = useState(false); + const [showChina, setShowChina] = useState(false); + + if (!selectedNode) { + return ( +
+
+
+

NARS Inference

+ select a system to reason +
+
+
+
+ Select a weapon system and click
Reason About This to discover
connections through NARS inference. +
+
+
+ ); + } + + const nodeEdges = edges.filter( + (e) => e.source === selectedNode.id || e.target === selectedNode.id, + ); + + const handleReason = async () => { + setRunning(true); + setShowChina(false); + + // Try live NARS engine first; fall back to stub enrichment + const live = await runNarsForNode(selectedNode.id, 0.3, 3); + if (live && live.inferences.length > 0) { + const enrichmentEdges: EnrichmentEdge[] = live.inferences.map((inf) => ({ + source: inf.source, + target: inf.target, + label: inf.relation, + truthValue: { f: inf.truth_f, c: inf.truth_c }, + gate: inf.truth_c >= 0.6 ? 'FLOW' : inf.truth_c >= 0.35 ? 'HOLD' : 'BLOCK', + inference: inf.inference_type.toLowerCase(), + detail: inf.via.length > 0 ? `via ${inf.via.join(' → ')}` : `${inf.inference_type} deduction`, + })); + const result: ReasoningResult = { + system: selectedNode.id, + officialConnections: nodeEdges.length, + discoveredConnections: enrichmentEdges.length, + enrichmentNodes: [], + enrichmentEdges, + patterns: [ + `Live NARS deduction: ${live.inferred_edges} inferences across graph`, + `Node "${selectedNode.label}" participates in ${enrichmentEdges.length} inferred chains`, + ], + confidence: Math.round( + (enrichmentEdges.reduce((s, e) => s + e.truthValue.c, 0) / enrichmentEdges.length) * 100, + ), + }; + setReasoning(result); + setRunning(false); + onEnrich(result); + return; + } + + // Fallback: stub enrichment (pre-computed or default) + const result = ENRICHMENT_INDEX[selectedNode.id] || getDefaultReasoning(selectedNode.id, selectedNode.label); + setReasoning(result); + setRunning(false); + onEnrich(result); + }; + + const handleChinaLinks = () => { + setShowChina(true); + }; + + return ( +
+
+
+

NARS Inference

+ {selectedNode.label} +
+ {reasoning && ( + + {reasoning.discoveredConnections} discovered + + )} +
+
+ {/* Official data */} +
+
official data
+
+ {nodeEdges.slice(0, 5).map((e, i) => ( +
+ + {e.source === selectedNode.id ? selectedNode.label : e.source} + →[{e.label}]→ + {e.target === selectedNode.id ? selectedNode.label : e.target} + +
+ ))} + {nodeEdges.length === 0 && ( +
No direct edges in official data
+ )} +
+
+ {Object.entries(selectedNode.properties).map(([k, v]) => ( + v && String(v) !== 'NaN' && String(v) !== '' ? ( +
+
{k}
+
{String(v)}
+
+ ) : null + ))} +
+
+ + {/* Reason button */} + {!reasoning && ( + + )} + + {running && ( +
+
+ NARS inference in progress... + Deduction · Induction · Abduction +
+ )} + + {/* Discovered connections */} + {reasoning && !running && ( + <> +
+
+ AI discovered connections — {reasoning.discoveredConnections} inferences +
+
+ {reasoning.enrichmentEdges.map((e: EnrichmentEdge, i: number) => ( +
+
+ {e.source} →[{e.label}]→ {e.target} +
+
{e.detail}
+
+ + {e.inference} +
+
+ ))} +
+
+ + {/* Patterns */} +
+
structural patterns
+
+ {reasoning.patterns.map((p, i) => ( +
{p}
+ ))} +
+
+ + {/* Confidence bar */} +
+
confidence
+
+
+
+ {reasoning.confidence.toFixed(1)}% +
+ + {/* Action buttons */} +
+ + + +
+ + {/* China links panel */} + {showChina && ( +
+
cross-domain inference — China containment
+
+ Pattern: Every system in the dataset serves resource denial against China. +
+
+
US → Lattice → autonomous kill chain
+
US → Replicator → drone swarms
+
Israel → Lavender → target ranking
+
NATO → DIANA → defense innovation
+
+
+
live search
+
\uD83D\uDD0D "SenseTime military contracts"
+
\uD83D\uDD0D "Hikvision Xinjiang surveillance"
+
\uD83D\uDD0D "PLA autonomous weapons 2025"
+
+ + + High complexity, cross-domain inference + +
+
+
+ )} + + )} +
+
+ ); +} diff --git a/cockpit/src/components/NotebookTimeline.tsx b/cockpit/src/components/NotebookTimeline.tsx new file mode 100644 index 000000000..155eba80a --- /dev/null +++ b/cockpit/src/components/NotebookTimeline.tsx @@ -0,0 +1,34 @@ +interface NotebookTimelineProps { + startYear: number; + endYear: number; + currentYear: number; + nodeCount: number; + onYearChange: (year: number) => void; +} + +export function NotebookTimeline({ startYear, endYear, currentYear, nodeCount, onYearChange }: NotebookTimelineProps) { + const years = Array.from({ length: endYear - startYear + 1 }, (_, i) => startYear + i); + const progress = ((currentYear - startYear) / (endYear - startYear)) * 100; + + return ( +
+
+
+ {years.filter((_, i) => i % 3 === 0).map((y) => ( + + ))} +
+
+ {startYear} — {endYear} + {nodeCount} nodes in graph +
+
+ ); +} diff --git a/cockpit/src/components/PalantirShell.tsx b/cockpit/src/components/PalantirShell.tsx new file mode 100644 index 000000000..c7bfe906a --- /dev/null +++ b/cockpit/src/components/PalantirShell.tsx @@ -0,0 +1,107 @@ +import { useEffect } from 'react'; +import { DataSourceCard } from './DataSourceCard'; +import { connectSSE } from '../transport'; +import { useStore } from '../store'; +import { AIWAR_QUERIES } from '../data/aiwar-seed'; + +interface PalantirShellProps { + onLaunchDemo: () => void; + onLaunchAiwar: () => void; + onLaunchNotebook: () => void; + error?: string | null; +} + +export function PalantirShell({ onLaunchDemo, onLaunchAiwar, onLaunchNotebook, error }: PalantirShellProps) { + const connected = useStore((s) => s.connected); + + useEffect(() => { + connectSSE(); + }, []); + + return ( +
+ {/* Header */} +
+
+ q2 graph engine +

Q2 Cockpit

+
+
+ + {connected ? 'Connected: lance-graph v0.4.2' : 'Disconnected'} + +
+
+ + {/* Data source cards */} +
+ + + + {}} + actionLabel="Upload" + /> +
+ + {/* Error message */} + {error && ( +
+ Error: {error} + + Make sure the aiwar data files are in cockpit/public/ + +
+ )} + + {/* Recent queries */} +
+
+
+

Analytical Queries

+ pre-loaded from aiwar query collection +
+
+
+ {AIWAR_QUERIES.slice(0, 4).map((q, i) => ( +
+
{q.title}
+ {q.code.slice(0, 80)}... +
{q.description}
+
+ ))} +
+
+
+ ); +} diff --git a/cockpit/src/components/QueryBar.tsx b/cockpit/src/components/QueryBar.tsx new file mode 100644 index 000000000..c66385377 --- /dev/null +++ b/cockpit/src/components/QueryBar.tsx @@ -0,0 +1,91 @@ +import { useState, useRef, useCallback } from 'react'; +import { useStore } from '../store'; +import { executeQuery } from '../transport'; + +const LANG_PATTERNS: Array<{ pattern: RegExp; lang: string }> = [ + { pattern: /^\s*g\./i, lang: 'gremlin' }, + { pattern: /^\s*MATCH\s*\(/i, lang: 'cypher' }, + { pattern: /^\s*(SELECT|CONSTRUCT|ASK|DESCRIBE)\s/i, lang: 'sparql' }, + { pattern: /^\s*(library|require|ggplot|data\.frame|<-|%>%)/i, lang: 'r' }, +]; + +function detectLang(code: string): string { + for (const { pattern, lang } of LANG_PATTERNS) { + if (pattern.test(code)) return lang; + } + return 'gremlin'; +} + +export function QueryBar() { + const [code, setCode] = useState(''); + const [lang, setLang] = useState('gremlin'); + const executing = useStore((s) => s.executing); + const inputRef = useRef(null); + + const handleInput = useCallback((value: string) => { + setCode(value); + setLang(detectLang(value)); + }, []); + + const [error, setError] = useState(null); + + const handleRun = useCallback(async () => { + if (!code.trim() || executing) return; + setError(null); + try { + await executeQuery(code, lang); + } catch (e) { + setError(e instanceof Error ? e.message : 'Query failed'); + } + }, [code, lang, executing]); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if (e.shiftKey && e.key === 'Enter') { + e.preventDefault(); + handleRun(); + } + }, + [handleRun], + ); + + return ( +
+
>_
+
+ + handleInput(e.target.value)} + onKeyDown={handleKeyDown} + autoComplete="off" + spellCheck={false} + /> +
+ + + {error && ( +
+ {error} + +
+ )} +
+ ); +} diff --git a/cockpit/src/components/ReasoningNotebook.tsx b/cockpit/src/components/ReasoningNotebook.tsx new file mode 100644 index 000000000..a95ae074b --- /dev/null +++ b/cockpit/src/components/ReasoningNotebook.tsx @@ -0,0 +1,84 @@ +import { ObserveCell } from './cells/ObserveCell'; +import { InferCell } from './cells/InferCell'; +import { SearchCell } from './cells/SearchCell'; +import { ProjectCell } from './cells/ProjectCell'; +import { ReviseCell } from './cells/ReviseCell'; +import { NotebookTimeline } from './NotebookTimeline'; +import { ScenarioCompare } from './ScenarioCompare'; +import { useNotebook } from '../hooks/useNotebook'; + +interface ReasoningNotebookProps { + onBack: () => void; +} + +export function ReasoningNotebook({ onBack }: ReasoningNotebookProps) { + const nb = useNotebook(); + + return ( +
+ {/* Top bar */} +
+
+ +

Q2 › Reasoning Notebook

+ Graph: 51 → {nb.graphNodeCount} nodes + Timeline: 2003 — 2026-W14 +
+
+ + {/* Timeline */} + {}} + /> + + {/* Cell toolbar */} +
+ Add cell: + + + + + +
+ + {/* Notebook cells */} +
+ + + + + + + + + +
+ + {/* Scenario comparison (shows after PROJECT runs) */} + {nb.projectResult && ( + + )} +
+ ); +} diff --git a/cockpit/src/components/ReasoningTrace.tsx b/cockpit/src/components/ReasoningTrace.tsx new file mode 100644 index 000000000..d2785432d --- /dev/null +++ b/cockpit/src/components/ReasoningTrace.tsx @@ -0,0 +1,40 @@ +import { TruthBadge } from './TruthBadge'; +import type { EnrichmentEdge } from '../data/aiwar-seed'; + +interface ReasoningTraceProps { + edges: EnrichmentEdge[]; + title?: string; +} + +export function ReasoningTrace({ edges, title }: ReasoningTraceProps) { + const byType = { + deduction: edges.filter((e) => e.inference === 'deduction'), + induction: edges.filter((e) => e.inference === 'induction'), + abduction: edges.filter((e) => e.inference === 'abduction'), + }; + + return ( +
+ {title &&
{title}
} + {Object.entries(byType).map(([type, items]) => + items.length > 0 ? ( +
+
+ {type === 'deduction' ? '\u26A1' : type === 'induction' ? '\uD83D\uDD0D' : '\u2753'}{' '} + {type} ({items.length}) +
+ {items.map((e, i) => ( +
+
+ {e.source} → [{e.label}] → {e.target} +
+
{e.detail}
+ +
+ ))} +
+ ) : null, + )} +
+ ); +} diff --git a/cockpit/src/components/ResultTable.tsx b/cockpit/src/components/ResultTable.tsx new file mode 100644 index 000000000..aa14dfbec --- /dev/null +++ b/cockpit/src/components/ResultTable.tsx @@ -0,0 +1,163 @@ +import { useState, useMemo } from 'react'; +import { useStore } from '../store'; + +type SortDir = 1 | -1; + +const STATUS_COLORS: Record = { + healthy: '#35d07f', warning: '#ffb547', critical: '#ff637d', +}; + +export function ResultTable() { + const nodes = useStore((s) => s.nodes); + const edges = useStore((s) => s.edges); + const filter = useStore((s) => s.filter); + const selectedNodeId = useStore((s) => s.selectedNodeId); + const selectNode = useStore((s) => s.selectNode); + const searchTerm = useStore((s) => s.searchTerm); + const setSearchTerm = useStore((s) => s.setSearchTerm); + const [sortKey, setSortKey] = useState('label'); + const [sortDir, setSortDir] = useState(1); + + // Apply filter + const filteredNodes = useMemo(() => { + let result = nodes; + if (filter !== 'all') { + if (filter === 'warning') { + result = result.filter((n) => n.properties.status !== 'healthy'); + } else { + result = result.filter((n) => n.type === filter); + } + } + if (searchTerm) { + const q = searchTerm.toLowerCase(); + result = result.filter((n) => + [n.id, n.label, n.type, ...Object.values(n.properties).map(String)] + .join(' ') + .toLowerCase() + .includes(q), + ); + } + return result; + }, [nodes, filter, searchTerm]); + + // Degree + connection count map + const degreeMap = useMemo(() => { + const m: Record = {}; + edges.forEach((e) => { + m[e.source] = (m[e.source] || 0) + 1; + m[e.target] = (m[e.target] || 0) + 1; + }); + return m; + }, [edges]); + + const sorted = useMemo(() => { + return [...filteredNodes].sort((a, b) => { + let va: string | number; + let vb: string | number; + + if (sortKey === 'label') { va = a.label; vb = b.label; } + else if (sortKey === 'type') { va = a.type; vb = b.type; } + else if (sortKey === 'conns') { va = degreeMap[a.id] || 0; vb = degreeMap[b.id] || 0; } + else { va = a.properties[sortKey] ?? ''; vb = b.properties[sortKey] ?? ''; } + + if (typeof va === 'number' && typeof vb === 'number') return (va - vb) * sortDir; + return String(va).localeCompare(String(vb)) * sortDir; + }); + }, [filteredNodes, sortKey, sortDir, degreeMap]); + + const handleSort = (key: string) => { + if (sortKey === key) { + setSortDir((d) => (d === 1 ? -1 : 1) as SortDir); + } else { + setSortKey(key); + setSortDir(1); + } + }; + + const columns = [ + { key: 'label', label: 'Label' }, + { key: 'type', label: 'Type' }, + { key: 'region', label: 'Region' }, + { key: 'status', label: 'Status' }, + { key: 'cpu', label: 'CPU' }, + { key: 'memory_gb', label: 'Mem (GB)' }, + { key: 'conns', label: 'Conns' }, + ]; + + return ( +
+
+
+

Results

+ dense · sortable · same entities as the graph +
+
row click = graph highlight
+
+
+ setSearchTerm(e.target.value)} + /> +
+ {filteredNodes.length} rows + + + + + export + + selection synced +
+
+
+ + + + {columns.map((col) => ( + + ))} + + + + {sorted.map((node) => { + const statusStr = String(node.properties.status || ''); + const statusColor = STATUS_COLORS[statusStr] || '#93a9bf'; + const cpu = typeof node.properties.cpu === 'number' ? node.properties.cpu : null; + const mem = typeof node.properties.memory_gb === 'number' ? node.properties.memory_gb : null; + return ( + selectNode(node.id)} + > + + + + + + + + + ); + })} + +
handleSort(col.key)}> + {col.label} + {sortKey === col.key && ( + + {sortDir === 1 ? '\u2191' : '\u2193'} + + )} +
{node.label}{node.type}{String(node.properties.region || '')} + + {statusStr.toUpperCase()} + + 0.7 ? 'td-hot' : ''}> + {cpu !== null ? cpu.toFixed(2) : ''} + {mem !== null ? mem.toFixed(1) : ''}{degreeMap[node.id] || 0}
+
+
+ ); +} diff --git a/cockpit/src/components/ScenarioCompare.tsx b/cockpit/src/components/ScenarioCompare.tsx new file mode 100644 index 000000000..270cc6a00 --- /dev/null +++ b/cockpit/src/components/ScenarioCompare.tsx @@ -0,0 +1,46 @@ +import { TruthBadge } from './TruthBadge'; + +interface Scenario { + label: string; + truth: { f: number; c: number }; + events: string[]; + signals: string[]; +} + +interface ScenarioCompareProps { + scenarios: Scenario[]; +} + +const COLORS = ['#35d07f', '#ffb547', '#93a9bf', '#00d4ff', '#e040fb']; + +export function ScenarioCompare({ scenarios }: ScenarioCompareProps) { + if (scenarios.length === 0) { + return ( +
+ Run a PROJECT cell to generate scenarios for comparison. +
+ ); + } + + return ( +
+
scenario comparison
+
+ {scenarios.map((s, i) => ( +
+
+ {String.fromCharCode(65 + i)}: {s.label} + 0.5 ? 'FLOW' : 'HOLD'} compact /> +
+
    + {s.events.map((e, j) =>
  • {e}
  • )} +
+
+ {s.signals.join(', ')} +
+
+ ))} +
+
+ ); +} diff --git a/cockpit/src/components/SceneBreadcrumb.tsx b/cockpit/src/components/SceneBreadcrumb.tsx new file mode 100644 index 000000000..ebed66861 --- /dev/null +++ b/cockpit/src/components/SceneBreadcrumb.tsx @@ -0,0 +1,54 @@ +import type { WireSceneAct } from '../hooks/useShaderStream'; +import { fmt, safeNum, safeStr } from '../diagnostics/safe'; + +interface SceneBreadcrumbProps { + scene: WireSceneAct | null; + cycle: number; +} + +export function SceneBreadcrumb({ scene, cycle }: SceneBreadcrumbProps) { + const safeCycle = safeNum(cycle, 0, 'scene.cycle'); + const act = scene ? safeNum(scene.act, 0, 'scene.act') : 0; + const total = scene ? safeNum(scene.total, 0, 'scene.total') : 0; + const confidence = scene ? safeNum(scene.confidence, 0, 'scene.confidence') : 0; + const name = scene + ? safeStr(scene.name, 'unknown', 'scene.name') + .replace('aiwar_enrichment_', '') + .replace('aiwar_', '') + : 'idle'; + const preview = scene ? safeStr(scene.cypher_preview, '', 'scene.cypher_preview') : ''; + + return ( +
+
+ act + + {scene ? `${act} / ${total}` : '— / —'} + + + + {name} + + {scene && ( + <> + + = 0.8 ? 'var(--green)' : confidence >= 0.65 ? 'var(--yellow)' : 'var(--muted)', + }}> + c={fmt(confidence, 2, 'scene.confidence')} + + + )} + + + cycle {safeCycle} + +
+ {preview && ( +
+ {preview} +
+ )} +
+ ); +} diff --git a/cockpit/src/components/StyleSelector.tsx b/cockpit/src/components/StyleSelector.tsx new file mode 100644 index 000000000..ec49f3840 --- /dev/null +++ b/cockpit/src/components/StyleSelector.tsx @@ -0,0 +1,229 @@ +/** + * StyleSelector — 36-brain cognitive style picker for the Reasoning cockpit. + * + * Phase 3 Agent #A2. Canonical names + cluster ordering pulled from + * `lance_graph_contract::thinking::ThinkingStyle`. Six clusters of six + * styles each, indexed by their tau (τ) macro address: + * + * Exploratory (τ 0x20) → Curious, Exploratory, Questioning, Investigative, + * Speculative, Philosophical + * Analytical (τ 0x40) → Logical, Analytical, Critical, Systematic, + * Methodical, Precise + * Direct (τ 0x60) → Direct, Concise, Efficient, Pragmatic, + * Blunt, Frank + * Empathic (τ 0x80) → Empathetic, Compassionate, Supportive, + * Nurturing, Gentle, Warm + * Creative (τ 0xA0) → Creative, Imaginative, Innovative, Artistic, + * Poetic, Playful + * Meta (τ 0xC0) → Reflective, Contemplative, Metacognitive, + * Wise, Transcendent, Sovereign + * + * Click → optimistic local highlight + POST /v1/shader/style. The backend + * (Phase 3 A3) confirms via the SSE dispatch event; ReasoningPage renders + * `lastDispatch.style` below the grid so the user sees the round-trip. + * + * "Auto" clears the selection — the backend falls back to its automatic + * style picker. + */ + +export interface StyleCluster { + name: string; + tau: number; + styles: string[]; +} + +/** + * Canonical 6 × 6 cluster layout. Order chosen for visual ascent of tau: + * Exploratory (smallest tau) at top → Meta (largest tau) at bottom. + */ +export const STYLE_CLUSTERS: StyleCluster[] = [ + { + name: 'Exploratory', + tau: 0x20, + styles: [ + 'Curious', + 'Exploratory', + 'Questioning', + 'Investigative', + 'Speculative', + 'Philosophical', + ], + }, + { + name: 'Analytical', + tau: 0x40, + styles: [ + 'Logical', + 'Analytical', + 'Critical', + 'Systematic', + 'Methodical', + 'Precise', + ], + }, + { + name: 'Direct', + tau: 0x60, + styles: ['Direct', 'Concise', 'Efficient', 'Pragmatic', 'Blunt', 'Frank'], + }, + { + name: 'Empathic', + tau: 0x80, + styles: [ + 'Empathetic', + 'Compassionate', + 'Supportive', + 'Nurturing', + 'Gentle', + 'Warm', + ], + }, + { + name: 'Creative', + tau: 0xa0, + styles: [ + 'Creative', + 'Imaginative', + 'Innovative', + 'Artistic', + 'Poetic', + 'Playful', + ], + }, + { + name: 'Meta', + tau: 0xc0, + styles: [ + 'Reflective', + 'Contemplative', + 'Metacognitive', + 'Wise', + 'Transcendent', + 'Sovereign', + ], + }, +]; + +/** + * Cycle-fingerprint hue (kept consistent with EnergyField's tau→hue scheme). + * Maps a tau byte to a CSS hsl() hue: 0x20 → 220° blue, 0xC0 → 360° red. + */ +function tauToHue(tau: number): number { + // Tau range used: 0x20..=0xC5 → ~32..197 (165 span). + // Map linearly into 200°..360° (cyan→magenta→red). + const t = Math.max(0, Math.min(1, (tau - 0x20) / (0xc5 - 0x20))); + return 200 + t * 160; +} + +export interface StyleSelectorProps { + /** Currently active style name (canonical, e.g. "Curious"). null → Auto. */ + active: string | null; + /** Fires when the user picks a style. Caller is responsible for the POST. */ + onSelect: (style: string | null) => void; + /** Optional: most recent dispatch style echoed back from the SSE stream. */ + lastDispatchStyle?: string | null; + /** Optional: surface a transient inline error (e.g. last POST returned !ok). */ + errorText?: string | null; +} + +export function StyleSelector({ + active, + onSelect, + lastDispatchStyle, + errorText, +}: StyleSelectorProps) { + // Defensive: if the cluster table somehow shipped empty, render a + // calm placeholder instead of an empty grid. + if (!STYLE_CLUSTERS.length) { + return ( +
+ loading thinking styles… +
+ ); + } + + return ( +
+
+ θ thinking style + + + {lastDispatchStyle ? ( + <> + dispatch:  + + {lastDispatchStyle} + + + ) : ( + + awaiting dispatch + + )} + + {errorText && ( + + {errorText} + + )} +
+ +
+ {STYLE_CLUSTERS.map((cluster) => { + const hue = tauToHue(cluster.tau); + return ( +
+
+ {cluster.name} + + τ{cluster.tau.toString(16).padStart(2, '0')} + +
+ {cluster.styles.map((style) => { + const isActive = active === style; + return ( + + ); + })} +
+ ); + })} +
+
+ ); +} diff --git a/cockpit/src/components/SuperpositionView.tsx b/cockpit/src/components/SuperpositionView.tsx new file mode 100644 index 000000000..1f001d86d --- /dev/null +++ b/cockpit/src/components/SuperpositionView.tsx @@ -0,0 +1,124 @@ +import { useMemo } from 'react'; +import type { GraphNode } from '../store'; +import { computeSuperposition, THINKING_STYLES, CLUSTER_COLORS, type SuperpositionResult } from '../data/thinking-styles'; + +interface SuperpositionViewProps { + nodes: GraphNode[]; +} + +export function SuperpositionView({ nodes }: SuperpositionViewProps) { + const results = useMemo(() => { + const map = computeSuperposition(nodes); + const arr = Array.from(map.values()); + return { + consensus: arr.filter((r) => r.category === 'consensus') + .sort((a, b) => b.consensusScore - a.consensusScore), + faultLines: arr.filter((r) => r.category === 'fault_line') + .sort((a, b) => Math.abs(b.fireCount - 18) - Math.abs(a.fireCount - 18)), + blindSpots: arr.filter((r) => r.category === 'blind_spot') + .sort((a, b) => a.fireCount - b.fireCount), + all: map, + }; + }, [nodes]); + + const nodeMap = useMemo(() => { + const m = new Map(); + nodes.forEach((n) => m.set(n.id, n)); + return m; + }, [nodes]); + + const getLabel = (id: string) => nodeMap.get(id)?.label || id; + + const renderBar = (result: SuperpositionResult) => { + const pct = (result.fireCount / 36) * 100; + return ( +
+
+
+ ); + }; + + const renderFiredBy = (result: SuperpositionResult) => { + const byClusters: Record = {}; + result.firedBy.forEach((sid) => { + const style = THINKING_STYLES.find((s) => s.id === sid); + if (style) byClusters[style.cluster] = (byClusters[style.cluster] || 0) + 1; + }); + return ( +
+ {Object.entries(byClusters).sort((a, b) => b[1] - a[1]).map(([cluster, count]) => ( + + {cluster} ({count}) + + ))} +
+ ); + }; + + return ( +
+
+

Superposition — 36 Brains on One Graph

+ {nodes.length} nodes analyzed +
+ + {/* Consensus */} +
+
+ Consensus ({results.consensus.length}) — all 36 agree +
+ {results.consensus.slice(0, 8).map((r) => ( +
+ {getLabel(r.nodeId)} + {r.fireCount}/36 + {renderBar(r)} +
+ ))} +
+ + {/* Fault lines */} +
+
+ Fault Lines ({results.faultLines.length}) — styles diverge +
+ {results.faultLines.slice(0, 8).map((r) => ( +
+
+ {getLabel(r.nodeId)} + {r.fireCount}/36 +
+ {renderBar(r)} + {renderFiredBy(r)} +
+ ))} +
+ + {/* Blind spots */} +
+
+ Blind Spots ({results.blindSpots.length}) — almost no style sees +
+ {results.blindSpots.slice(0, 6).map((r) => ( +
+ {getLabel(r.nodeId)} + {r.fireCount}/36 + {renderBar(r)} + {r.firedBy.length > 0 && ( + + Only: {r.firedBy.map((sid) => THINKING_STYLES.find((s) => s.id === sid)?.name).join(', ')} + + )} +
+ ))} +
+
+ ); +} diff --git a/cockpit/src/components/ThoughtLog.tsx b/cockpit/src/components/ThoughtLog.tsx new file mode 100644 index 000000000..8dd3aac97 --- /dev/null +++ b/cockpit/src/components/ThoughtLog.tsx @@ -0,0 +1,90 @@ +import { useRef, useEffect } from 'react'; +import type { WireShaderCrystal } from '../hooks/useShaderStream'; +import { fmt, safeNum } from '../diagnostics/safe'; + +interface ThoughtLogProps { + crystals: WireShaderCrystal[]; + maxItems?: number; +} + +/** Fold a numeric fingerprint hash into a short hex signature. */ +function signature(n: number): string { + if (!Number.isFinite(n)) return '????????'; + return (n >>> 0).toString(16).padStart(8, '0'); +} + +/** Color a crystal row by meta confidence. */ +function confColor(c: number): string { + if (!Number.isFinite(c)) return 'var(--muted)'; + if (c >= 0.8) return '#35d07f'; + if (c >= 0.6) return '#00d4ff'; + if (c >= 0.4) return '#ffb547'; + return '#e040fb'; +} + +export function ThoughtLog({ crystals, maxItems = 50 }: ThoughtLogProps) { + const listRef = useRef(null); + + useEffect(() => { + if (listRef.current) { + listRef.current.scrollTop = listRef.current.scrollHeight; + } + }, [crystals]); + + const safeCrystals = Array.isArray(crystals) ? crystals : []; + const visible = safeCrystals.slice(-maxItems); + + return ( +
+
+
+ Γ crystallized cycles + + {safeCrystals.length} committed + +
+
+
+ {visible.length === 0 ? ( +
+ awaiting convergence… (Shift+D for diagnostics) +
+ ) : ( + visible.map((crystal, i) => { + if (!crystal || typeof crystal !== 'object') return null; + const bus = crystal.bus ?? null; + const meta = crystal.meta ?? null; + const conf = meta ? safeNum(meta.confidence, 0, 'crystal.meta.confidence') : 0; + const fpHash = bus ? safeNum(bus.cycle_fingerprint_hash, 0, 'crystal.bus.cycle_fingerprint_hash') : 0; + const sig = signature(fpHash); + const top = bus && Array.isArray(bus.resonance?.top_k) ? bus.resonance.top_k : []; + const topRow = top[0]?.row ?? null; + const persisted = crystal.persisted_row; + const admit = meta?.should_admit_ignorance === true; + return ( +
+ + c={fmt(conf, 2, 'crystal.meta.confidence')} + + + [{topRow !== null && Number.isFinite(topRow) ? topRow : '????'}] + + + sig {sig} + {persisted !== null && persisted !== undefined && ( + · row {persisted} + )} + {admit && · ⚠ ignorance} + +
+ ); + }) + )} +
+
+ ); +} diff --git a/cockpit/src/components/TruthBadge.tsx b/cockpit/src/components/TruthBadge.tsx new file mode 100644 index 000000000..3fe89b24c --- /dev/null +++ b/cockpit/src/components/TruthBadge.tsx @@ -0,0 +1,43 @@ +// Reusable NARS truth value display: (f, c, gate) + +interface TruthBadgeProps { + f: number; + c: number; + gate: 'FLOW' | 'HOLD' | 'BLOCK'; + compact?: boolean; +} + +const GATE_COLORS: Record = { + FLOW: '#35d07f', + HOLD: '#ffb547', + BLOCK: '#ff637d', +}; + +const GATE_ICONS: Record = { + FLOW: '\u2713', + HOLD: '\u25CF', + BLOCK: '\u2717', +}; + +export function TruthBadge({ f, c, gate, compact }: TruthBadgeProps) { + const color = GATE_COLORS[gate] || '#93a9bf'; + + if (compact) { + return ( + + {gate} {f.toFixed(2)} + + ); + } + + return ( + + + f={f.toFixed(2)}, c={c.toFixed(2)} + + + {GATE_ICONS[gate]} {gate} + + + ); +} diff --git a/cockpit/src/components/cells/InferCell.tsx b/cockpit/src/components/cells/InferCell.tsx new file mode 100644 index 000000000..fa5f81049 --- /dev/null +++ b/cockpit/src/components/cells/InferCell.tsx @@ -0,0 +1,97 @@ +import { useState } from 'react'; +import { TruthBadge } from '../TruthBadge'; + +interface Inference { + premise: string; + conclusion: string; + truth: { f: number; c: number }; + gate: 'FLOW' | 'HOLD' | 'BLOCK'; +} + +interface InferCellProps { + onExecute: (mode: string, depth: number) => void; + result: { flow: Inference[]; hold: Inference[]; block: Inference[] } | null; + onAddFlow: () => void; +} + +export function InferCell({ onExecute, result, onAddFlow }: InferCellProps) { + const [mode, setMode] = useState('Deduction'); + const [depth, setDepth] = useState(3); + const [loading, setLoading] = useState(false); + + const handleRun = () => { + setLoading(true); + onExecute(mode, depth); + setTimeout(() => setLoading(false), 1200); + }; + + return ( +
+
+ INFER + NARS inference on subgraph +
+
+
+ + + + + +
+ {result && ( +
+ {result.flow.length + result.hold.length + result.block.length} new inferences: + + {result.flow.length > 0 && ( +
+
FLOW ({result.flow.length})
+ {result.flow.slice(0, 4).map((inf, i) => ( +
+ {inf.conclusion} + +
+ ))} +
+ )} + + {result.hold.length > 0 && ( +
+
HOLD ({result.hold.length})
+ {result.hold.slice(0, 3).map((inf, i) => ( +
+ {inf.conclusion} + +
+ ))} +
+ )} + + {result.block.length > 0 && ( +
+
BLOCK ({result.block.length}) — too uncertain to display
+
+ )} + +
+ + +
+
+ )} +
+
+ ); +} diff --git a/cockpit/src/components/cells/ObserveCell.tsx b/cockpit/src/components/cells/ObserveCell.tsx new file mode 100644 index 000000000..c0dca79ce --- /dev/null +++ b/cockpit/src/components/cells/ObserveCell.tsx @@ -0,0 +1,59 @@ +import { useState } from 'react'; + +interface ObserveCellProps { + onExecute: (timeWindow: string) => void; + result: { events: string[]; nodeCount: number } | null; +} + +const TIME_WINDOWS = [ + 'March 2026', + 'February 2026', + 'January 2026', + 'Q4 2025', + 'Q3 2025', + 'Full Timeline', +]; + +export function ObserveCell({ onExecute, result }: ObserveCellProps) { + const [timeWindow, setTimeWindow] = useState('March 2026'); + const [loading, setLoading] = useState(false); + + const handleLoad = () => { + setLoading(true); + onExecute(timeWindow); + setTimeout(() => setLoading(false), 800); + }; + + return ( +
+
+ OBSERVE + Load time window +
+
+
+ + + +
+ {result && ( +
+ Loaded {result.events.length} events ({result.nodeCount} nodes): +
    + {result.events.slice(0, 8).map((e, i) => ( +
  • {e}
  • + ))} + {result.events.length > 8 && ( +
  • +{result.events.length - 8} more...
  • + )} +
+
+ )} +
+
+ ); +} diff --git a/cockpit/src/components/cells/ProjectCell.tsx b/cockpit/src/components/cells/ProjectCell.tsx new file mode 100644 index 000000000..0adf5692a --- /dev/null +++ b/cockpit/src/components/cells/ProjectCell.tsx @@ -0,0 +1,78 @@ +import { useState } from 'react'; +import { TruthBadge } from '../TruthBadge'; + +interface Scenario { + label: string; + truth: { f: number; c: number }; + events: string[]; + signals: string[]; +} + +interface ProjectCellProps { + onExecute: (horizon: string, count: number) => void; + result: { scenarios: Scenario[] } | null; +} + +export function ProjectCell({ onExecute, result }: ProjectCellProps) { + const [horizon, setHorizon] = useState('2 weeks'); + const [count, setCount] = useState(3); + const [loading, setLoading] = useState(false); + + const handleProject = () => { + setLoading(true); + onExecute(horizon, count); + setTimeout(() => setLoading(false), 1500); + }; + + const SCENARIO_COLORS = ['#35d07f', '#ffb547', '#93a9bf']; + + return ( +
+
+ PROJECT + Temporal projection +
+
+
+ + + + + +
+ {result && ( +
+ {result.scenarios.map((s, i) => ( +
+
+ Scenario {String.fromCharCode(65 + i)}: {s.label} + 0.5 ? 'FLOW' : 'HOLD'} compact /> +
+
    + {s.events.map((e, j) =>
  • {e}
  • )} +
+
+ Signals: {s.signals.join(', ')} +
+
+ ))} +
+ These are NARS projections, not predictions. Truth values show confidence in structural patterns. +
+
+ )} +
+
+ ); +} diff --git a/cockpit/src/components/cells/ReviseCell.tsx b/cockpit/src/components/cells/ReviseCell.tsx new file mode 100644 index 000000000..6b02fcc24 --- /dev/null +++ b/cockpit/src/components/cells/ReviseCell.tsx @@ -0,0 +1,80 @@ +import { useState } from 'react'; +import { TruthBadge } from '../TruthBadge'; + +interface ReviseResult { + before: { f: number; c: number }; + after: { f: number; c: number }; + cascadeCount: number; +} + +interface ReviseCellProps { + onExecute: (edgeDesc: string, newF: number, newC: number, justification: string) => void; + result: ReviseResult | null; +} + +export function ReviseCell({ onExecute, result }: ReviseCellProps) { + const [edgeDesc, setEdgeDesc] = useState('CNPC →[invested_in]→ Venezuela'); + const [newF, setNewF] = useState(0.30); + const [newC, setNewC] = useState(0.70); + const [justification, setJustification] = useState( + 'CNPC Venezuela investment was $4B in 2007 but operations suspended in 2019 due to sanctions.', + ); + const [loading, setLoading] = useState(false); + + const handleApply = () => { + setLoading(true); + onExecute(edgeDesc, newF, newC, justification); + setTimeout(() => setLoading(false), 600); + }; + + return ( +
+
+ REVISE + Human correction +
+
+
+
+ + setEdgeDesc(e.target.value)} /> +
+
+ + setNewF(Number(e.target.value))} /> + + setNewC(Number(e.target.value))} /> +
+
+