-
Notifications
You must be signed in to change notification settings - Fork 1
feat(cogbattlespace): add Cognitive Battlespace UI components and page #22202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,9 +27,12 @@ export interface CogBattleStorage { | |
| listTopNarratives(limit: number): Promise<Narrative[]>; | ||
| listBeliefs(limit: number): Promise<Belief[]>; | ||
| listDivergence(narrativeId?: string): Promise<DivergenceMetric[]>; | ||
| getCurrentEntity(entityType: string, fingerprint: string): Promise<any>; | ||
| putLaneSnapshot(entityType: string, fingerprint: string, data: any): Promise<void>; | ||
|
Comment on lines
+30
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Verify call sites and check whether callers currently depend on untyped `any` behavior.
rg -nP --type=ts -C2 '\b(getCurrentEntity|putLaneSnapshot)\s*\('Repository: BrianCLong/summit Length of output: 2420 🏁 Script executed: #!/bin/bash
# Find the reconcileEntityTrustAware function and see what type it expects for 'current'
rg -nP --type=ts 'reconcileEntityTrustAware' -A5 -B2Repository: BrianCLong/summit Length of output: 2463 🏁 Script executed: #!/bin/bash
# Check if there are any other imports or implementations of CogBattleStorage interface
rg -nP --type=ts 'implements CogBattleStorage|CogBattleStorage' -B1 -A3Repository: BrianCLong/summit Length of output: 7681 🏁 Script executed: #!/bin/bash
# Look at the context around the firewall.ts call sites to understand type expectations
sed -n '190,240p' packages/summit-cogbattlespace/src/writeset/firewall.tsRepository: BrianCLong/summit Length of output: 2514 🏁 Script executed: #!/bin/bash
# Find EntitySnapshot type definition
rg -nP --type=ts 'type EntitySnapshot|interface EntitySnapshot' -B2 -A5Repository: BrianCLong/summit Length of output: 759 🏁 Script executed: #!/bin/bash
# Check what is imported in reconciler.ts to understand type context
head -30 packages/summit-cogbattlespace/src/writeset/reconcile/reconciler.tsRepository: BrianCLong/summit Length of output: 1272 Replace The interface returns and accepts Recommended fix+ import type { EntitySnapshot } from "./writeset/reconcile/types";
export interface CogBattleStorage {
- getCurrentEntity(entityType: string, fingerprint: string): Promise<any>;
- putLaneSnapshot(entityType: string, fingerprint: string, data: any): Promise<void>;
+ getCurrentEntity(entityType: string, fingerprint: string): Promise<EntitySnapshot | null>;
+ putLaneSnapshot(entityType: string, fingerprint: string, data: EntitySnapshot): Promise<void>;
}
export class InMemoryCogBattleStorage implements CogBattleStorage {
- private laneSnapshots = new Map<string, Map<string, any>>();
+ private laneSnapshots = new Map<string, Map<string, EntitySnapshot>>();
- async getCurrentEntity(entityType: string, fingerprint: string): Promise<any> {
+ async getCurrentEntity(entityType: string, fingerprint: string): Promise<EntitySnapshot | null> {
const typeMap = this.laneSnapshots.get(entityType);
if (!typeMap) return null;
return typeMap.get(fingerprint) ?? null;
}
- async putLaneSnapshot(entityType: string, fingerprint: string, data: any): Promise<void> {
+ async putLaneSnapshot(entityType: string, fingerprint: string, data: EntitySnapshot): Promise<void> {
let typeMap = this.laneSnapshots.get(entityType);
if (!typeMap) {
- typeMap = new Map();
+ typeMap = new Map<string, EntitySnapshot>();
this.laneSnapshots.set(entityType, typeMap);
}
typeMap.set(fingerprint, data);
}
}🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| export class InMemoryCogBattleStorage implements CogBattleStorage { | ||
| private laneSnapshots = new Map<string, Map<string, any>>(); | ||
| private readonly artifacts = new Map<string, Artifact>(); | ||
| private readonly narratives = new Map<string, Narrative>(); | ||
| private readonly beliefs = new Map<string, Belief>(); | ||
|
|
@@ -88,4 +91,19 @@ export class InMemoryCogBattleStorage implements CogBattleStorage { | |
| } | ||
| return this.divergence.filter((item) => item.narrativeId === narrativeId); | ||
| } | ||
|
|
||
| async getCurrentEntity(entityType: string, fingerprint: string): Promise<any> { | ||
| const typeMap = this.laneSnapshots.get(entityType); | ||
| if (!typeMap) return null; | ||
| return typeMap.get(fingerprint) ?? null; | ||
| } | ||
|
|
||
| async putLaneSnapshot(entityType: string, fingerprint: string, data: any): Promise<void> { | ||
| let typeMap = this.laneSnapshots.get(entityType); | ||
| if (!typeMap) { | ||
| typeMap = new Map(); | ||
| this.laneSnapshots.set(entityType, typeMap); | ||
| } | ||
| typeMap.set(fingerprint, data); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,35 @@ | ||||||||||||||||||||||||||||||||||
| import React from "react"; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| export function ExplainDrawer(props: { | ||||||||||||||||||||||||||||||||||
| open: boolean; | ||||||||||||||||||||||||||||||||||
| onClose: () => void; | ||||||||||||||||||||||||||||||||||
| title: string; | ||||||||||||||||||||||||||||||||||
| body: string; | ||||||||||||||||||||||||||||||||||
| disclaimers: string[]; | ||||||||||||||||||||||||||||||||||
| }) { | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+3
to
+9
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For better readability and reusability, it's a good practice to define component props in a separate interface or type alias.
Suggested change
|
||||||||||||||||||||||||||||||||||
| if (!props.open) return null; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||
| <div className="fixed inset-0 bg-black/40 flex justify-end"> | ||||||||||||||||||||||||||||||||||
| <div className="w-full max-w-xl h-full bg-white p-6 overflow-auto"> | ||||||||||||||||||||||||||||||||||
| <div className="flex items-center justify-between"> | ||||||||||||||||||||||||||||||||||
| <h2 className="text-xl font-semibold">{props.title}</h2> | ||||||||||||||||||||||||||||||||||
| <button className="px-3 py-1 rounded-2xl border" onClick={props.onClose}> | ||||||||||||||||||||||||||||||||||
| Close | ||||||||||||||||||||||||||||||||||
| </button> | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| <pre className="mt-4 whitespace-pre-wrap text-sm">{props.body}</pre> | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| <div className="mt-6"> | ||||||||||||||||||||||||||||||||||
| <h3 className="text-sm font-semibold">Defensive disclaimers</h3> | ||||||||||||||||||||||||||||||||||
| <ul className="mt-2 list-disc pl-5 text-sm"> | ||||||||||||||||||||||||||||||||||
| {props.disclaimers.map((d, i) => ( | ||||||||||||||||||||||||||||||||||
| <li key={i}>{d}</li> | ||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using an array index as a
Suggested change
|
||||||||||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||||||||||
| </ul> | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,30 @@ | ||||||||||||||||||||||
| import React from "react"; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| export type Layer = "reality" | "narrative" | "belief"; | ||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To ensure the
Suggested change
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| export function LayerToggle(props: { | ||||||||||||||||||||||
| enabled: Record<Layer, boolean>; | ||||||||||||||||||||||
| onChange: (next: Record<Layer, boolean>) => void; | ||||||||||||||||||||||
| }) { | ||||||||||||||||||||||
|
Comment on lines
+5
to
+8
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For better readability and reusability, it's a good practice to define component props in a separate interface or type alias.
Suggested change
|
||||||||||||||||||||||
| const { enabled, onChange } = props; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const toggle = (k: Layer) => { | ||||||||||||||||||||||
| onChange({ ...enabled, [k]: !enabled[k] }); | ||||||||||||||||||||||
| }; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return ( | ||||||||||||||||||||||
| <div className="flex gap-2 items-center"> | ||||||||||||||||||||||
| {(["reality", "narrative", "belief"] as Layer[]).map((k) => ( | ||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||||||
| <button | ||||||||||||||||||||||
| key={k} | ||||||||||||||||||||||
| className={`px-3 py-1 rounded-2xl border text-sm ${ | ||||||||||||||||||||||
| enabled[k] ? "bg-black text-white" : "bg-white" | ||||||||||||||||||||||
| }`} | ||||||||||||||||||||||
| onClick={() => toggle(k)} | ||||||||||||||||||||||
| > | ||||||||||||||||||||||
| {k} | ||||||||||||||||||||||
| </button> | ||||||||||||||||||||||
| ))} | ||||||||||||||||||||||
| </div> | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,46 @@ | ||||||
| import React from "react"; | ||||||
|
|
||||||
| export function MetricsPanel(props: { | ||||||
| narratives: Array<{ id: string; label: string; summary: string; metrics: { velocity: number } }>; | ||||||
| divergence: Array<{ narrativeId: string; claimId: string; divergenceScore: number }>; | ||||||
| onExplain: (narrativeId: string) => void; | ||||||
| }) { | ||||||
|
Comment on lines
+3
to
+7
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For better readability and reusability, it's a good practice to define component props in a separate interface or type alias. The complex inline types for |
||||||
| return ( | ||||||
| <div className="grid gap-4"> | ||||||
| <div className="rounded-2xl border p-4"> | ||||||
| <h3 className="text-sm font-semibold">Top narratives (velocity)</h3> | ||||||
| <div className="mt-3 grid gap-2"> | ||||||
| {props.narratives.map((n) => ( | ||||||
| <div key={n.id} className="p-3 rounded-xl border"> | ||||||
| <div className="flex items-center justify-between"> | ||||||
| <div className="font-medium">{n.label}</div> | ||||||
| <div className="text-xs opacity-70">v={n.metrics.velocity.toFixed(2)}</div> | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Guard against undefined values before calling If 🛡️ Proposed defensive fix- <div className="text-xs opacity-70">v={n.metrics.velocity.toFixed(2)}</div>
+ <div className="text-xs opacity-70">v={(n.metrics.velocity ?? 0).toFixed(2)}</div>And for line 39: - <div className="text-xs opacity-70">score={d.divergenceScore.toFixed(2)}</div>
+ <div className="text-xs opacity-70">score={(d.divergenceScore ?? 0).toFixed(2)}</div>📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| </div> | ||||||
| <div className="text-sm opacity-80 mt-1">{n.summary}</div> | ||||||
| <button | ||||||
| className="mt-2 px-3 py-1 rounded-2xl border text-sm" | ||||||
| onClick={() => props.onExplain(n.id)} | ||||||
| > | ||||||
| Explain | ||||||
| </button> | ||||||
| </div> | ||||||
| ))} | ||||||
| </div> | ||||||
| </div> | ||||||
|
|
||||||
| <div className="rounded-2xl border p-4"> | ||||||
| <h3 className="text-sm font-semibold">Divergence signals</h3> | ||||||
| <div className="mt-3 grid gap-2"> | ||||||
| {props.divergence.map((d, idx) => ( | ||||||
| <div key={`${d.narrativeId}-${idx}`} className="p-3 rounded-xl border"> | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using an array index as part of the
Suggested change
|
||||||
| <div className="text-sm"> | ||||||
| narrative={d.narrativeId} → claim={d.claimId} | ||||||
| </div> | ||||||
| <div className="text-xs opacity-70">score={d.divergenceScore.toFixed(2)}</div> | ||||||
| </div> | ||||||
| ))} | ||||||
| </div> | ||||||
| </div> | ||||||
| </div> | ||||||
| ); | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,75 @@ | ||||||
| import React from "react"; | ||||||
|
|
||||||
| type RejectionError = { | ||||||
| code: string; | ||||||
| message: string; | ||||||
| instancePath?: string; | ||||||
| schemaPath?: string; | ||||||
| }; | ||||||
|
|
||||||
| type RejectionItem = { | ||||||
| opId: string; | ||||||
| status: "ACCEPTED" | "REJECTED"; | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The panel hardcodes item status to Useful? React with 👍 / 👎. |
||||||
| entityType?: string; | ||||||
| domain?: string; | ||||||
| action?: string; | ||||||
| errors?: RejectionError[]; | ||||||
| }; | ||||||
|
|
||||||
| type RejectionReport = { | ||||||
| ok: boolean; | ||||||
| writesetId: string; | ||||||
| summary: { receivedOps: number; acceptedOps: number; rejectedOps: number }; | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The summary shape expects Useful? React with 👍 / 👎. |
||||||
| items: RejectionItem[]; | ||||||
| }; | ||||||
|
|
||||||
| export function RejectionReportPanel({ report }: { report: RejectionReport }) { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||
| return ( | ||||||
| <div className="rounded-2xl border p-4"> | ||||||
| <div className="flex items-center justify-between"> | ||||||
| <div className="text-sm font-semibold">Write Report</div> | ||||||
| <div className={`text-xs px-2 py-1 rounded-xl border ${report.ok ? "bg-white" : "bg-black text-white"}`}> | ||||||
| {report.ok ? "OK" : "REJECTED"} | ||||||
| </div> | ||||||
| </div> | ||||||
|
|
||||||
| <div className="mt-2 text-xs opacity-70"> | ||||||
| writeset={report.writesetId} · received={report.summary.receivedOps} · accepted={report.summary.acceptedOps} · | ||||||
| rejected={report.summary.rejectedOps} | ||||||
| </div> | ||||||
|
|
||||||
| <div className="mt-4 grid gap-2"> | ||||||
| {report.items.map((it) => ( | ||||||
| <div key={it.opId} className="p-3 rounded-xl border"> | ||||||
| <div className="flex items-center justify-between"> | ||||||
| <div className="text-sm font-medium"> | ||||||
| {it.opId}{" "} | ||||||
| <span className="text-xs opacity-70"> | ||||||
| {it.domain ? `· ${it.domain}` : ""} {it.entityType ? `· ${it.entityType}` : ""}{" "} | ||||||
| {it.action ? `· ${it.action}` : ""} | ||||||
| </span> | ||||||
| </div> | ||||||
| <div className={`text-xs px-2 py-1 rounded-xl border ${it.status === "ACCEPTED" ? "" : "bg-black text-white"}`}> | ||||||
| {it.status} | ||||||
| </div> | ||||||
| </div> | ||||||
|
|
||||||
| {it.errors?.length ? ( | ||||||
| <ul className="mt-2 list-disc pl-5 text-xs"> | ||||||
| {it.errors.map((e, idx) => ( | ||||||
| <li key={idx}> | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using an array index as a
Suggested change
|
||||||
| <span className="font-semibold">{e.code}</span>: {e.message} | ||||||
| {e.instancePath ? <span className="opacity-70"> · path={e.instancePath}</span> : null} | ||||||
| {e.schemaPath ? <span className="opacity-70"> · schema={e.schemaPath}</span> : null} | ||||||
| </li> | ||||||
| ))} | ||||||
| </ul> | ||||||
| ) : ( | ||||||
| <div className="mt-2 text-xs opacity-70">No errors.</div> | ||||||
| )} | ||||||
| </div> | ||||||
| ))} | ||||||
| </div> | ||||||
| </div> | ||||||
| ); | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,93 @@ | ||||||||||||||||||||||||||||||||||||||
| import React, { useMemo, useState } from "react"; | ||||||||||||||||||||||||||||||||||||||
| import { LayerToggle, Layer } from "../../components/cogbattlespace/LayerToggle"; | ||||||||||||||||||||||||||||||||||||||
| import { MetricsPanel } from "../../components/cogbattlespace/MetricsPanel"; | ||||||||||||||||||||||||||||||||||||||
| import { ExplainDrawer } from "../../components/cogbattlespace/ExplainDrawer"; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| // Replace these with your real API client | ||||||||||||||||||||||||||||||||||||||
| async function fetchTopNarratives() { | ||||||||||||||||||||||||||||||||||||||
| return []; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| async function fetchDivergence() { | ||||||||||||||||||||||||||||||||||||||
| return []; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| export default function CognitiveBattlespacePage() { | ||||||||||||||||||||||||||||||||||||||
| const [layers, setLayers] = useState<Record<Layer, boolean>>({ | ||||||||||||||||||||||||||||||||||||||
| reality: true, | ||||||||||||||||||||||||||||||||||||||
| narrative: true, | ||||||||||||||||||||||||||||||||||||||
| belief: true | ||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const [narratives, setNarratives] = useState<any[]>([]); | ||||||||||||||||||||||||||||||||||||||
| const [divergence, setDivergence] = useState<any[]>([]); | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+6
to
+22
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using
Comment on lines
+21
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Avoid Using ♻️ Proposed type definitions+type Narrative = {
+ id: string;
+ label: string;
+ summary: string;
+ metrics: { velocity: number };
+};
+
+type DivergenceSignal = {
+ narrativeId: string;
+ claimId: string;
+ divergenceScore: number;
+};
+
export default function CognitiveBattlespacePage() {
// ...
- const [narratives, setNarratives] = useState<any[]>([]);
- const [divergence, setDivergence] = useState<any[]>([]);
+ const [narratives, setNarratives] = useState<Narrative[]>([]);
+ const [divergence, setDivergence] = useState<DivergenceSignal[]>([]);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const [drawerOpen, setDrawerOpen] = useState(false); | ||||||||||||||||||||||||||||||||||||||
| const [drawerTitle, setDrawerTitle] = useState("Explain"); | ||||||||||||||||||||||||||||||||||||||
| const [drawerBody, setDrawerBody] = useState(""); | ||||||||||||||||||||||||||||||||||||||
| const [drawerDisclaimers, setDrawerDisclaimers] = useState<string[]>([]); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| React.useEffect(() => { | ||||||||||||||||||||||||||||||||||||||
| (async () => { | ||||||||||||||||||||||||||||||||||||||
| setNarratives(await fetchTopNarratives()); | ||||||||||||||||||||||||||||||||||||||
| setDivergence(await fetchDivergence()); | ||||||||||||||||||||||||||||||||||||||
| })(); | ||||||||||||||||||||||||||||||||||||||
| }, []); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const enabledLayers = useMemo( | ||||||||||||||||||||||||||||||||||||||
| () => Object.entries(layers).filter(([, v]) => v).map(([k]) => k), | ||||||||||||||||||||||||||||||||||||||
| [layers] | ||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const explain = async (narrativeId: string) => { | ||||||||||||||||||||||||||||||||||||||
| // Stubbed explain content; wire to summit-cogbattlespace explainDivergence endpoint later | ||||||||||||||||||||||||||||||||||||||
| setDrawerTitle(`Explain: ${narrativeId}`); | ||||||||||||||||||||||||||||||||||||||
| setDrawerBody( | ||||||||||||||||||||||||||||||||||||||
| [ | ||||||||||||||||||||||||||||||||||||||
| "This view is analytic/defensive.", | ||||||||||||||||||||||||||||||||||||||
| "It explains why a narrative was flagged and what evidence-backed claims it may conflict with.", | ||||||||||||||||||||||||||||||||||||||
| "", | ||||||||||||||||||||||||||||||||||||||
| "No counter-messaging guidance is generated." | ||||||||||||||||||||||||||||||||||||||
| ].join("\n") | ||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||
| setDrawerDisclaimers([ | ||||||||||||||||||||||||||||||||||||||
| "Analytic/defensive only: no persuasion or targeting guidance.", | ||||||||||||||||||||||||||||||||||||||
| "Heuristic scores; review artifacts + evidence.", | ||||||||||||||||||||||||||||||||||||||
| "Association is not causation." | ||||||||||||||||||||||||||||||||||||||
| ]); | ||||||||||||||||||||||||||||||||||||||
| setDrawerOpen(true); | ||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||
| <div className="p-6 grid gap-6"> | ||||||||||||||||||||||||||||||||||||||
| <div className="flex items-center justify-between"> | ||||||||||||||||||||||||||||||||||||||
| <div> | ||||||||||||||||||||||||||||||||||||||
| <h1 className="text-2xl font-semibold">Cognitive Battlespace</h1> | ||||||||||||||||||||||||||||||||||||||
| <div className="text-sm opacity-70 mt-1"> | ||||||||||||||||||||||||||||||||||||||
| Layers enabled: {enabledLayers.join(", ")} | ||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||
| <LayerToggle enabled={layers} onChange={setLayers} /> | ||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| {/* Placeholder for map/graph canvas */} | ||||||||||||||||||||||||||||||||||||||
| <div className="rounded-2xl border p-6 min-h-[260px]"> | ||||||||||||||||||||||||||||||||||||||
| <div className="text-sm opacity-70"> | ||||||||||||||||||||||||||||||||||||||
| Canvas placeholder (graph/map). Wire to IntelGraph/H3/Map layers later. | ||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||
| <div className="mt-3 text-sm"> | ||||||||||||||||||||||||||||||||||||||
| Reality / Narrative / Belief layers are toggled above; this canvas will render the chosen overlays. | ||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| <MetricsPanel narratives={narratives} divergence={divergence} onExplain={explain} /> | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| <ExplainDrawer | ||||||||||||||||||||||||||||||||||||||
| open={drawerOpen} | ||||||||||||||||||||||||||||||||||||||
| onClose={() => setDrawerOpen(false)} | ||||||||||||||||||||||||||||||||||||||
| title={drawerTitle} | ||||||||||||||||||||||||||||||||||||||
| body={drawerBody} | ||||||||||||||||||||||||||||||||||||||
| disclaimers={drawerDisclaimers} | ||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of
anyforgetCurrentEntity's return type andputLaneSnapshot'sdataparameter circumvents TypeScript's type safety. This can lead to runtime errors and makes the code harder to maintain and understand. Consider using a generic type parameter for the entity data, for example<T>, to provide type safety for consumers of this storage interface.For example:
This would require updating
InMemoryCogBattleStorageas well, but would significantly improve type safety.