feat(cogbattlespace): add Cognitive Battlespace UI components and page#22202
feat(cogbattlespace): add Cognitive Battlespace UI components and page#22202BrianCLong wants to merge 1 commit intomainfrom
Conversation
Adds the requested Tri-Graph Model UI components to `packages/summit-ui/src/components/cogbattlespace/` including `LayerToggle`, `ExplainDrawer`, `MetricsPanel`, and `RejectionReportPanel`. Also adds the main Cognitive Battlespace page stub to `packages/summit-ui/src/pages/cogbattlespace/index.tsx`. Updates `packages/summit-cogbattlespace/src/storage.ts` to include required methods `getCurrentEntity` and `putLaneSnapshot`. Updates `packages/summit-cogbattlespace/tsconfig.json` to exclude test files from compilation. Co-authored-by: BrianCLong <6404035+BrianCLong@users.noreply.github.com>
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
There was a problem hiding this comment.
Code Review
This pull request implements the Cognitive Battlespace feature, adding storage methods for lane snapshots and a suite of UI components for visualizing narratives, divergence signals, and layer toggles. The feedback primarily addresses TypeScript best practices, specifically recommending the replacement of 'any' types with generics or defined interfaces to enhance type safety. Additionally, several suggestions were made to improve React component structure by extracting prop types and using more stable keys for list rendering to prevent potential UI bugs.
| getCurrentEntity(entityType: string, fingerprint: string): Promise<any>; | ||
| putLaneSnapshot(entityType: string, fingerprint: string, data: any): Promise<void>; |
There was a problem hiding this comment.
The use of any for getCurrentEntity's return type and putLaneSnapshot's data parameter 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:
export interface CogBattleStorage {
// ... other methods
getCurrentEntity<T>(entityType: string, fingerprint: string): Promise<T | null>;
putLaneSnapshot<T>(entityType: string, fingerprint: string, data: T): Promise<void>;
}This would require updating InMemoryCogBattleStorage as well, but would significantly improve type safety.
| // 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[]>([]); |
There was a problem hiding this comment.
Using any[] for state and not providing return types for fetch functions undermines TypeScript's type safety. It's best to define strong types for your data structures (Narrative, Divergence) and use them consistently in your state and API functions. This will prevent runtime errors and improve code maintainability. These types could be shared with the MetricsPanel component, for example by moving them to a shared types file.
// It's best to define these types in a shared file and import them.
type Narrative = {
id: string;
label: string;
summary: string;
metrics: { velocity: number };
};
type Divergence = {
narrativeId: string;
claimId: string;
divergenceScore: number;
};
// Replace these with your real API client
async function fetchTopNarratives(): Promise<Narrative[]> {
return [];
}
async function fetchDivergence(): Promise<Divergence[]> {
return [];
}
export default function CognitiveBattlespacePage() {
const [layers, setLayers] = useState<Record<Layer, boolean>>({
reality: true,
narrative: true,
belief: true,
});
const [narratives, setNarratives] = useState<Narrative[]>([]);
const [divergence, setDivergence] = useState<Divergence[]>([]);
| export function ExplainDrawer(props: { | ||
| open: boolean; | ||
| onClose: () => void; | ||
| title: string; | ||
| body: string; | ||
| disclaimers: string[]; | ||
| }) { |
There was a problem hiding this comment.
For better readability and reusability, it's a good practice to define component props in a separate interface or type alias.
| export function ExplainDrawer(props: { | |
| open: boolean; | |
| onClose: () => void; | |
| title: string; | |
| body: string; | |
| disclaimers: string[]; | |
| }) { | |
| type ExplainDrawerProps = { | |
| open: boolean; | |
| onClose: () => void; | |
| title: string; | |
| body: string; | |
| disclaimers: string[]; | |
| }; | |
| export function ExplainDrawer(props: ExplainDrawerProps) { |
| <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> |
There was a problem hiding this comment.
Using an array index as a key is an anti-pattern in React when the list of items can be reordered, added to, or removed from. This can lead to incorrect component state and rendering issues. If the disclaimer strings are not guaranteed to be unique, a more robust key can be generated by combining the string and its index.
| <li key={i}>{d}</li> | |
| <li key={`${d}-${i}`}>{d}</li> |
| @@ -0,0 +1,30 @@ | |||
| import React from "react"; | |||
|
|
|||
| export type Layer = "reality" | "narrative" | "belief"; | |||
There was a problem hiding this comment.
To ensure the Layer type and the array of layers used for rendering are always in sync, it's better to define the array as a const and derive the type from it. This avoids potential mismatches if the Layer type is updated in the future but the hardcoded array in the component is not.
| export type Layer = "reality" | "narrative" | "belief"; | |
| export const LAYERS = ["reality", "narrative", "belief"] as const; | |
| export type Layer = typeof LAYERS[number]; |
|
|
||
| return ( | ||
| <div className="flex gap-2 items-center"> | ||
| {(["reality", "narrative", "belief"] as Layer[]).map((k) => ( |
| 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; | ||
| }) { |
There was a problem hiding this comment.
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 narratives and divergence would also benefit from being extracted into their own named types.
type Narrative = {
id: string;
label: string;
summary: string;
metrics: { velocity: number };
};
type Divergence = {
narrativeId: string;
claimId: string;
divergenceScore: number;
};
interface MetricsPanelProps {
narratives: Narrative[];
divergence: Divergence[];
onExplain: (narrativeId: string) => void;
}
export function MetricsPanel(props: MetricsPanelProps) {
| <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"> |
There was a problem hiding this comment.
Using an array index as part of the key is an anti-pattern if the list can be reordered. Since each divergence item has a narrativeId and a claimId, a composite key from these two properties would be more stable and is preferred over using the index.
| <div key={`${d.narrativeId}-${idx}`} className="p-3 rounded-xl border"> | |
| <div key={`${d.narrativeId}-${d.claimId}`} className="p-3 rounded-xl border"> |
| items: RejectionItem[]; | ||
| }; | ||
|
|
||
| export function RejectionReportPanel({ report }: { report: RejectionReport }) { |
| {it.errors?.length ? ( | ||
| <ul className="mt-2 list-disc pl-5 text-xs"> | ||
| {it.errors.map((e, idx) => ( | ||
| <li key={idx}> |
There was a problem hiding this comment.
Using an array index as a key is an anti-pattern in React when the list of items can change. This can lead to incorrect component state and rendering issues. A more stable key can be created by combining the index with other properties of the error object, like code and instancePath.
| <li key={idx}> | |
| <li key={`${idx}-${e.code}-${e.instancePath ?? ''}`}> |
WalkthroughThis PR extends the CogBattleStorage interface with snapshot retrieval and storage methods, introduces a new Cognitive Battlespace page with supporting React components for layer toggling, metrics display, divergence tracking, and error reporting, and updates TypeScript configuration to exclude node_modules and test files. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9377367122
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| type RejectionItem = { | ||
| opId: string; | ||
| status: "ACCEPTED" | "REJECTED"; |
There was a problem hiding this comment.
Align rejection statuses with writeset outcomes
The panel hardcodes item status to "ACCEPTED" | "REJECTED", but the only writeset producer in this repo (applyCogWriteSet in packages/summit-cogbattlespace/src/writeset/firewall.ts) emits statuses like APPLIED, MERGED, PROMOTED, NOOP_ENTITY, etc. When this component is fed real API data, successful operations will not map correctly and will be rendered with the non-accepted styling branch, misreporting valid writes as failures.
Useful? React with 👍 / 👎.
| type RejectionReport = { | ||
| ok: boolean; | ||
| writesetId: string; | ||
| summary: { receivedOps: number; acceptedOps: number; rejectedOps: number }; |
There was a problem hiding this comment.
Align summary counters with writeset report fields
The summary shape expects acceptedOps, but the backend writeset report model provides granular counters (appliedOps, mergedOps, promotedOps, etc.) and no acceptedOps field. If this component is connected to the existing API contract, the accepted count will render as undefined, which breaks the report header and obscures operator outcomes.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (4)
packages/summit-ui/src/pages/cogbattlespace/index.tsx (2)
41-41: Remove unnecessaryasynckeyword.The
explainfunction is markedasyncbut contains noawaitexpressions. The comment suggests it will be wired to an endpoint later, so this can stay if that's imminent; otherwise remove to avoid confusion.- const explain = async (narrativeId: string) => { + const explain = (narrativeId: string) => {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/summit-ui/src/pages/cogbattlespace/index.tsx` at line 41, The explain function is declared async but contains no await; remove the unnecessary async keyword from the explain declaration (function explain(narrativeId: string) { ... }) to avoid misleading callers, or if you intend to call async operations soon, add the awaited logic inside explain (e.g., await fetch/axios) instead; locate the explain function in this module to update its signature accordingly.
29-34: Add error handling and loading state for data fetching.The current implementation silently fails if fetches error, and provides no loading feedback. Consider adding:
- A loading state to show a spinner/skeleton
- Error handling with user feedback
- Cleanup to prevent state updates on unmounted components
♻️ Proposed improvements
+ const [loading, setLoading] = useState(true); + const [error, setError] = useState<string | null>(null); React.useEffect(() => { + let cancelled = false; (async () => { - setNarratives(await fetchTopNarratives()); - setDivergence(await fetchDivergence()); + try { + const [narr, div] = await Promise.all([fetchTopNarratives(), fetchDivergence()]); + if (!cancelled) { + setNarratives(narr); + setDivergence(div); + } + } catch (e) { + if (!cancelled) setError("Failed to load battlespace data"); + } finally { + if (!cancelled) setLoading(false); + } })(); + return () => { cancelled = true; }; }, []);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/summit-ui/src/pages/cogbattlespace/index.tsx` around lines 29 - 34, Wrap the data fetching inside useEffect with a loading and error state: add local state variables like isLoading and fetchError and set isLoading=true before the async calls; use try/catch around the await fetchTopNarratives() and fetchDivergence() calls to set fetchError on failure and show user feedback, and finally set isLoading=false in a finally block. Prevent state updates after unmount by using an isMounted flag (or AbortController) inside the useEffect and check it before calling setNarratives and setDivergence. Update the component render to show a spinner/skeleton when isLoading is true and an error message when fetchError is set.packages/summit-ui/src/components/cogbattlespace/ExplainDrawer.tsx (1)
13-34: Consider adding accessibility features for the modal drawer.The drawer overlay is missing standard accessibility features for modal dialogs:
- No
role="dialog"oraria-modal="true"attributes- No focus trap (users can tab outside the drawer)
- No keyboard listener for Escape to close
- The backdrop click doesn't close the drawer
These can be addressed iteratively, but consider adding at minimum:
♿ Proposed accessibility improvements
- <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="fixed inset-0 bg-black/40 flex justify-end" + onClick={props.onClose} + onKeyDown={(e) => e.key === "Escape" && props.onClose()} + > + <div + role="dialog" + aria-modal="true" + aria-labelledby="drawer-title" + className="w-full max-w-xl h-full bg-white p-6 overflow-auto" + onClick={(e) => e.stopPropagation()} + > <div className="flex items-center justify-between"> - <h2 className="text-xl font-semibold">{props.title}</h2> + <h2 id="drawer-title" className="text-xl font-semibold">{props.title}</h2>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/summit-ui/src/components/cogbattlespace/ExplainDrawer.tsx` around lines 13 - 34, The ExplainDrawer component's modal markup lacks accessibility: add role="dialog" and aria-modal="true" to the container element (the overlay or inner panel), ensure backdrop clicks call props.onClose (attach onClick to the overlay but stopPropagation on the panel), add a keyboard listener in the ExplainDrawer component to call props.onClose on Escape, and implement a focus trap / initial focus behavior so focus moves into the drawer on open and cannot tab out (or use a small focus-trap utility or hook inside ExplainDrawer); ensure the panel stops click propagation so internal clicks don't close the drawer and return focus to the prior element on close.packages/summit-ui/src/components/cogbattlespace/RejectionReportPanel.tsx (1)
3-24: Consider exporting types for reuse.The
RejectionError,RejectionItem, andRejectionReporttypes are useful for API response typing and other components. Exporting them would improve reusability.♻️ Proposed change
-type RejectionError = { +export type RejectionError = { code: string; message: string; instancePath?: string; schemaPath?: string; }; -type RejectionItem = { +export type RejectionItem = { opId: string; status: "ACCEPTED" | "REJECTED"; entityType?: string; domain?: string; action?: string; errors?: RejectionError[]; }; -type RejectionReport = { +export type RejectionReport = { ok: boolean; writesetId: string; summary: { receivedOps: number; acceptedOps: number; rejectedOps: number }; items: RejectionItem[]; };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/summit-ui/src/components/cogbattlespace/RejectionReportPanel.tsx` around lines 3 - 24, Export the three types so they can be reused: add the export keyword to RejectionError, RejectionItem, and RejectionReport declarations (e.g., export type RejectionError = {...}) and update any consumers/import sites to import these named types; also export them from the module's public API (barrel/index) if one exists so other components can import them easily.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/summit-cogbattlespace/src/storage.ts`:
- Around line 30-31: Update the storage interface so it uses the concrete
EntitySnapshot type instead of any: change getCurrentEntity to return
Promise<EntitySnapshot | null> and change putLaneSnapshot to accept data:
EntitySnapshot; then update call sites (notably reconcileEntityTrustAware and
the place casting with "as any" in firewall.ts) to stop using casts and work
with the stronger types, adjusting imports to reference the EntitySnapshot type
where needed.
In `@packages/summit-ui/src/components/cogbattlespace/MetricsPanel.tsx`:
- Line 17: Guard against undefined/null before calling .toFixed() on numeric
fields: update the render in MetricsPanel.tsx where n.metrics.velocity and
d.divergenceScore are used (search for the symbols n.metrics.velocity and
d.divergenceScore) to first check for a valid number (e.g., Number.isFinite(...)
or nullish-coalesce to a default like 0) and only call .toFixed(2) when the
value is numeric; otherwise render a safe fallback (such as "-" or "0.00") so no
runtime error occurs.
In `@packages/summit-ui/src/pages/cogbattlespace/index.tsx`:
- Around line 21-22: Replace the loose any[] state with concrete types: define
interfaces (e.g., Narrative and Divergence) that match the API/props shape or
import/reuse the existing types used by MetricsPanel, then update the useState
generics for narratives and divergence to use those types
(useState<Narrative[]>() / useState<Divergence[]>()), adjust
setNarratives/setDivergence usages to satisfy the new types, and add any
necessary imports for the types at the top of the file (or export the types from
MetricsPanel and consume them here).
---
Nitpick comments:
In `@packages/summit-ui/src/components/cogbattlespace/ExplainDrawer.tsx`:
- Around line 13-34: The ExplainDrawer component's modal markup lacks
accessibility: add role="dialog" and aria-modal="true" to the container element
(the overlay or inner panel), ensure backdrop clicks call props.onClose (attach
onClick to the overlay but stopPropagation on the panel), add a keyboard
listener in the ExplainDrawer component to call props.onClose on Escape, and
implement a focus trap / initial focus behavior so focus moves into the drawer
on open and cannot tab out (or use a small focus-trap utility or hook inside
ExplainDrawer); ensure the panel stops click propagation so internal clicks
don't close the drawer and return focus to the prior element on close.
In `@packages/summit-ui/src/components/cogbattlespace/RejectionReportPanel.tsx`:
- Around line 3-24: Export the three types so they can be reused: add the export
keyword to RejectionError, RejectionItem, and RejectionReport declarations
(e.g., export type RejectionError = {...}) and update any consumers/import sites
to import these named types; also export them from the module's public API
(barrel/index) if one exists so other components can import them easily.
In `@packages/summit-ui/src/pages/cogbattlespace/index.tsx`:
- Line 41: The explain function is declared async but contains no await; remove
the unnecessary async keyword from the explain declaration (function
explain(narrativeId: string) { ... }) to avoid misleading callers, or if you
intend to call async operations soon, add the awaited logic inside explain
(e.g., await fetch/axios) instead; locate the explain function in this module to
update its signature accordingly.
- Around line 29-34: Wrap the data fetching inside useEffect with a loading and
error state: add local state variables like isLoading and fetchError and set
isLoading=true before the async calls; use try/catch around the await
fetchTopNarratives() and fetchDivergence() calls to set fetchError on failure
and show user feedback, and finally set isLoading=false in a finally block.
Prevent state updates after unmount by using an isMounted flag (or
AbortController) inside the useEffect and check it before calling setNarratives
and setDivergence. Update the component render to show a spinner/skeleton when
isLoading is true and an error message when fetchError is set.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 00c156c6-e280-42cb-a7de-7eafbaead762
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (7)
packages/summit-cogbattlespace/src/storage.tspackages/summit-cogbattlespace/tsconfig.jsonpackages/summit-ui/src/components/cogbattlespace/ExplainDrawer.tsxpackages/summit-ui/src/components/cogbattlespace/LayerToggle.tsxpackages/summit-ui/src/components/cogbattlespace/MetricsPanel.tsxpackages/summit-ui/src/components/cogbattlespace/RejectionReportPanel.tsxpackages/summit-ui/src/pages/cogbattlespace/index.tsx
| getCurrentEntity(entityType: string, fingerprint: string): Promise<any>; | ||
| putLaneSnapshot(entityType: string, fingerprint: string, data: any): Promise<void>; |
There was a problem hiding this comment.
🧩 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 any with concrete EntitySnapshot type for storage API contract.
The interface returns and accepts any, which bypasses strict type checking. getCurrentEntity() should return Promise<EntitySnapshot | null> (matching what reconcileEntityTrustAware() expects), and putLaneSnapshot() should accept EntitySnapshot. The current workaround as any cast on line 201 of firewall.ts is a symptom of this weak typing.
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
Verify each finding against the current code and only fix it if needed.
In `@packages/summit-cogbattlespace/src/storage.ts` around lines 30 - 31, Update
the storage interface so it uses the concrete EntitySnapshot type instead of
any: change getCurrentEntity to return Promise<EntitySnapshot | null> and change
putLaneSnapshot to accept data: EntitySnapshot; then update call sites (notably
reconcileEntityTrustAware and the place casting with "as any" in firewall.ts) to
stop using casts and work with the stronger types, adjusting imports to
reference the EntitySnapshot type where needed.
| <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.
Guard against undefined values before calling .toFixed().
If n.metrics.velocity is undefined or null, calling .toFixed(2) will throw a runtime error. Same applies to d.divergenceScore on line 39.
🛡️ 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
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <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> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/summit-ui/src/components/cogbattlespace/MetricsPanel.tsx` at line
17, Guard against undefined/null before calling .toFixed() on numeric fields:
update the render in MetricsPanel.tsx where n.metrics.velocity and
d.divergenceScore are used (search for the symbols n.metrics.velocity and
d.divergenceScore) to first check for a valid number (e.g., Number.isFinite(...)
or nullish-coalesce to a default like 0) and only call .toFixed(2) when the
value is numeric; otherwise render a safe fallback (such as "-" or "0.00") so no
runtime error occurs.
| const [narratives, setNarratives] = useState<any[]>([]); | ||
| const [divergence, setDivergence] = useState<any[]>([]); |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Avoid any[] - define proper types for state.
Using any[] defeats TypeScript's purpose. Define types matching your API response or reuse the types from MetricsPanel props.
♻️ 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
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const [narratives, setNarratives] = useState<any[]>([]); | |
| const [divergence, setDivergence] = useState<any[]>([]); | |
| 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<Narrative[]>([]); | |
| const [divergence, setDivergence] = useState<DivergenceSignal[]>([]); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/summit-ui/src/pages/cogbattlespace/index.tsx` around lines 21 - 22,
Replace the loose any[] state with concrete types: define interfaces (e.g.,
Narrative and Divergence) that match the API/props shape or import/reuse the
existing types used by MetricsPanel, then update the useState generics for
narratives and divergence to use those types (useState<Narrative[]>() /
useState<Divergence[]>()), adjust setNarratives/setDivergence usages to satisfy
the new types, and add any necessary imports for the types at the top of the
file (or export the types from MetricsPanel and consume them here).
❌ Lint Gate ResultsESLint
Code Quality
❌ Lint gate failedPlease fix the linter errors and warnings before merging. About Lint GateThis gate enforces zero linter warnings/errors and production code quality:
|
❌ TypeScript Gate ResultsType Safety
Sample ErrorsAbout TypeScript GateThis gate enforces type safety:
To fix TypeScript errors:
|
|
Closing in favor of #22241, which carries the Cognitive Battlespace UI slice on top of the converged CI/governance baseline. |
Implements the React UI skeleton for the Cognitive Battlespace subsystem, including layer toggles, explanation drawers, metrics panels, and a unified rejection report panel. Fixes TypeScript build issues in
summit-cogbattlespaceby excluding test files and adds missing methods toInMemoryCogBattleStoragefor the firewall reconciler.PR created automatically by Jules for task 14338170707411774589 started by @BrianCLong
Summary by CodeRabbit