feat: add Exhibit Stage fixture gallery - #121
Conversation
🤖 CodeAnt AI — Review Status
|
Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
|
Warning Review limit reached
Next review available in: 38 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (17)
✨ Finishing Touches🧪 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 |
| * set by relevance for rotation; retired artifacts fall to the archive shelf. | ||
| */ | ||
| export const fixtureGallery: ExhibitArtifact[] = [ | ||
| activityNarrative, |
There was a problem hiding this comment.
ThermalMap is implemented but no thermal_map artifact is declared or added to this gallery. As a result, ?mode=exhibits can never render that view, even though the v1 acceptance criteria require all seven authored exhibits plus live_graph to render from typed contracts. Please add a thermal-map fixture here (and include it in the gallery) so this fixture-only stage exercises the full vocabulary.
| const active = useMemo( | ||
| () => artifacts.filter((a) => a.status !== 'retired').sort((a, b) => b.relevance - a.relevance), | ||
| [artifacts] | ||
| ); | ||
| const retired = useMemo(() => artifacts.filter((a) => a.status === 'retired'), [artifacts]); |
There was a problem hiding this comment.
Suggestion: The selected exhibit is stored only as a positional index, so when artifacts refreshes or relevance values reorder active, the same index can point to a different artifact and silently change the visible exhibit. Track the selected artifact ID and derive its current index after rebuilding the sorted list, falling back only when that ID no longer exists. [stale reference]
Severity Level: Major ⚠️
- ⚠️ Refreshed curator exhibits can change selection unexpectedly.
- ⚠️ Commentary and renderer may no longer match user choice.
- ⚠️ Active exhibit state is unstable during relevance updates.Steps of Reproduction ✅
1. The `?mode=exhibits` entry in `web/app-entry.tsx:10-12` mounts `ExhibitGalleryApp`,
which passes `fixtureGallery` to `ExhibitStage` at
`web/components/exhibits/ExhibitGalleryApp.tsx:26-38`.
2. `ExhibitStage` builds `active` by filtering and relevance-sorting the supplied
artifacts at `web/components/exhibits/ExhibitStage.tsx:104-108`, while storing only the
selected position in `index` at lines 110-115.
3. Render the stage with multiple artifacts, select a non-first item through `goTo()` at
`web/components/exhibits/ExhibitStage.tsx:139-142`, then refresh the supplied artifact
array with changed relevance values so its sorted order changes.
4. React preserves `index`, but `active[safeIndex]` at
`web/components/exhibits/ExhibitStage.tsx:115-116` now refers to a different artifact; the
displayed title, commentary, renderer, and active rail item silently switch without the
user selecting another exhibit. The current fixture caller is static, but the component's
`artifacts` prop is explicitly designed for refreshed artifact data.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** web/components/exhibits/ExhibitStage.tsx
**Line:** 104:108
**Comment:**
*Stale Reference: The selected exhibit is stored only as a positional index, so when `artifacts` refreshes or relevance values reorder `active`, the same index can point to a different artifact and silently change the visible exhibit. Track the selected artifact ID and derive its current index after rebuilding the sorted list, falling back only when that ID no longer exists.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| export const fixtureGallery: ExhibitArtifact[] = [ | ||
| activityNarrative, | ||
| relationshipDag, | ||
| walkthrough, | ||
| concernSnapshot, | ||
| seismograph, | ||
| momentum, | ||
| liveGraph, | ||
| retiredEarlyGuess, | ||
| ]; |
There was a problem hiding this comment.
Suggestion: The fixture gallery omits the thermal_map artifact even though this PR adds the Thermal Map renderer, includes it in the supported exhibit vocabulary, and describes the gallery as the full exhibit floor. As a result, the new exhibit can never be reached through the advertised fixture gallery; add a thermal-map fixture artifact to the array. [incomplete implementation]
Severity Level: Major ⚠️
- ❌ Fixture gallery cannot demonstrate Thermal Map.
- ⚠️ `?mode=exhibits` omits a supported exhibit type.
- ⚠️ ThermalMap renderer is unreachable through fixture navigation.Steps of Reproduction ✅
1. Open the documented fixture route `?mode=exhibits`; `web/app-entry.tsx:7-12` mounts
`ExhibitGalleryApp`, and `web/components/exhibits/ExhibitGalleryApp.tsx:38` passes
`fixtureGallery` into `ExhibitStage`.
2. `fixtureGallery` contains activity narrative, relationship DAG, walkthrough, concern
snapshot, seismograph, momentum, live graph, and one retired artifact at
`web/components/exhibits/fixture-gallery.ts:316-325`; it contains no artifact with
`exhibitType: 'thermal_map'`.
3. `ExhibitStage` filters the active gallery and renders only those artifacts at
`web/components/exhibits/ExhibitStage.tsx:104-108` and `154-175`, so the fixture route has
no rail item or rotation entry for thermal maps.
4. Although `thermal_map` is part of `ExhibitPayloadMap` and `AUTHORED_EXHIBIT_TYPES` at
`web/components/exhibits/types.ts:165-184` and `253-262`, and `ActiveExhibit` dispatches
it to `ThermalMap` at `web/components/exhibits/ExhibitStage.tsx:79`, that renderer is
unreachable through the advertised fixture gallery until a thermal-map artifact is added.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** web/components/exhibits/fixture-gallery.ts
**Line:** 316:325
**Comment:**
*Incomplete Implementation: The fixture gallery omits the `thermal_map` artifact even though this PR adds the Thermal Map renderer, includes it in the supported exhibit vocabulary, and describes the gallery as the full exhibit floor. As a result, the new exhibit can never be reached through the advertised fixture gallery; add a thermal-map fixture artifact to the array.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| <div className="relative h-[720px] overflow-hidden rounded-[30px] border border-white/10 bg-[#050914] shadow-[0_0_0_1px_rgba(255,255,255,0.02),0_30px_80px_rgba(0,0,0,0.65)]"> | ||
| <div className="absolute inset-0 bg-[radial-gradient(circle_at_top_left,rgba(56,189,248,0.14),transparent_32%),radial-gradient(circle_at_75%_10%,rgba(192,132,252,0.14),transparent_28%),radial-gradient(circle_at_50%_100%,rgba(52,211,153,0.10),transparent_24%)]" /> | ||
| <div className="absolute inset-0 opacity-[0.08] [background-image:linear-gradient(rgba(255,255,255,0.9)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.9)_1px,transparent_1px)] [background-size:60px_60px]" /> | ||
| <div className="absolute inset-0 bg-[linear-gradient(to_bottom,rgba(255,255,255,0.02),transparent_12%,transparent_88%,rgba(255,255,255,0.02))]" /> | ||
| {children} | ||
| </div> |
There was a problem hiding this comment.
Suggestion: The fixed 720px frame clips exhibit content at shorter viewport heights because overflow is hidden. The momentum view contains stacked panels whose content can exceed this height, and the fixed-width cards also overflow on narrow screens, so users can lose controls and narrative content instead of being able to scroll or see a responsive layout. Use a responsive/min-height frame and allow the exhibit content to scroll or reflow at small viewport sizes. [css layout issue]
Severity Level: Major ⚠️
- ⚠️ Short-window prototype users can lose lower content.
- ⚠️ Narrow-window users can lose controls or card text.
- ⚠️ The restored prototype is not responsive despite viewport use.Steps of Reproduction ✅
1. Render `RepoExhibitVisualizationPrototype` from
`docs/ideas/repoviz/exhibit-prototype.jsx:739` in a viewport shorter than 720 CSS pixels
or narrower than the fixed card layout requires.
2. Select `MomentumView` through `ViewStage` at
`docs/ideas/repoviz/exhibit-prototype.jsx:731-736`; its panels are positioned inside the
`Frame` beginning at line `631`.
3. The `Frame` at `docs/ideas/repoviz/exhibit-prototype.jsx:102` always has `h-[720px]`
and `overflow-hidden`, so content extending beyond that rectangle cannot increase the
frame height or be scrolled.
4. On narrow widths, Momentum's fixed internal dimensions, including the `240px` gauge at
`docs/ideas/repoviz/exhibit-prototype.jsx:648` and fixed-width cards in the other views,
can extend beyond the available frame width; the overflow rule clips the excess controls
or narrative instead of allowing reflow or scrolling.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** docs/ideas/repoviz/exhibit-prototype.jsx
**Line:** 102:107
**Comment:**
*Css Layout Issue: The fixed 720px frame clips exhibit content at shorter viewport heights because overflow is hidden. The momentum view contains stacked panels whose content can exceed this height, and the fixed-width cards also overflow on narrow screens, so users can lose controls and narrative content instead of being able to scroll or see a responsive layout. Use a responsive/min-height frame and allow the exhibit content to scroll or reflow at small viewport sizes.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| onMouseEnter={() => setPaused(true)} | ||
| onMouseLeave={() => setPaused(false)} |
There was a problem hiding this comment.
Suggestion: The hover handlers overwrite the user's manual pause state: moving the pointer into the exhibit list or stage forces paused to true, and leaving forces it to false. As a result, a user who manually pauses cycling can have it resume simply by hovering and leaving these regions, and clicking the pause button while the pointer is over the list can immediately toggle the hover-forced state back to active. Keep manual pause and hover pause as separate state values, or only apply hover pausing when the user has not manually paused. [incorrect condition logic]
Severity Level: Major ⚠️
- ⚠️ Prototype cycling can resume against user intent.
- ⚠️ Manual pause behavior is inconsistent across hover regions.
- ⚠️ Current `?mode=exhibits` uses a separate `ExhibitStage` implementation.Steps of Reproduction ✅
1. The current browser entry at `web/app-entry.tsx:10-12` mounts `ExhibitGalleryApp` for
`?mode=exhibits`; it does not import or render `RepoExhibitVisualizationPrototype` from
`docs/ideas/repoviz/exhibit-prototype.jsx:739`, so this behavior is limited to the
restored prototype when that file is rendered.
2. Render `RepoExhibitVisualizationPrototype` and click the `Pause cycling` button
implemented at `docs/ideas/repoviz/exhibit-prototype.jsx:794-799`; this sets the shared
`paused` state to `true` and stops the interval at lines `746-755`.
3. Move the pointer over any exhibit-list button at
`docs/ideas/repoviz/exhibit-prototype.jsx:813-817`; its `onMouseEnter` handler sets the
same state to `true`, masking the manual state but not distinguishing its source.
4. Move the pointer away from the button; `onMouseLeave` at
`docs/ideas/repoviz/exhibit-prototype.jsx:816` sets `paused` to `false`, restarting the
interval even though the user previously selected manual pause. The stage container has
the same overriding handlers at lines `852-855`.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** docs/ideas/repoviz/exhibit-prototype.jsx
**Line:** 815:816
**Comment:**
*Incorrect Condition Logic: The hover handlers overwrite the user's manual pause state: moving the pointer into the exhibit list or stage forces `paused` to true, and leaving forces it to false. As a result, a user who manually pauses cycling can have it resume simply by hovering and leaving these regions, and clicking the pause button while the pointer is over the list can immediately toggle the hover-forced state back to active. Keep manual pause and hover pause as separate state values, or only apply hover pausing when the user has not manually paused.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| export default function ActivityNarrative({ payload }: ActivityNarrativeProps) { | ||
| const reduce = useReducedMotion(); | ||
| const { beats, threads } = payload; | ||
| const [active, setActive] = useState(beats.length - 1); |
There was a problem hiding this comment.
Suggestion: The selected index is initialized from the initial beat count but is never reconciled when beats changes. An empty payload initializes active to -1, and a refresh that removes beats can leave active above the new slider maximum, producing an invalid controlled range input and no valid selected beat. Clamp or reset active whenever the beat list changes. [stale reference]
Severity Level: Major ⚠️
- ❌ Refreshed activity exhibits can show invalid timeline selection.
- ⚠️ Empty payloads render an out-of-range controlled slider.
- ⚠️ Automatic beat cycling can reference stale selection state.Steps of Reproduction ✅
1. Open the fixture gallery through `ExhibitGalleryApp` at
`web/components/exhibits/ExhibitGalleryApp.tsx:26-38`; `ExhibitStage` selects the activity
artifact through `web/components/exhibits/ExhibitStage.tsx:73-74`.
2. The fixture currently supplies seven beats at
`web/components/exhibits/fixture-gallery.ts:38-88`, so `ActivityNarrative` initializes
`active` to `6` at `web/components/exhibits/ActivityNarrative.tsx:20`.
3. Refresh the same mounted activity artifact with an empty `payload.beats` array, or with
fewer beats than the previous payload. The state initializer does not rerun, leaving
`active` at `6` (or `-1` for an initially empty payload).
4. The controlled range input at `web/components/exhibits/ActivityNarrative.tsx:104-110`
then receives `value={active}` while its maximum is `Math.max(0, beats.length - 1)`,
producing an out-of-range controlled slider and no valid selected beat. Add an effect that
clamps or resets `active` when `beats.length` changes.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** web/components/exhibits/ActivityNarrative.tsx
**Line:** 20:20
**Comment:**
*Stale Reference: The selected index is initialized from the initial beat count but is never reconciled when `beats` changes. An empty payload initializes `active` to `-1`, and a refresh that removes beats can leave `active` above the new slider maximum, producing an invalid controlled range input and no valid selected beat. Clamp or reset `active` whenever the beat list changes.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const reduce = useReducedMotion(); | ||
| const { concerns, flows } = payload; | ||
| const byId = useMemo(() => Object.fromEntries(concerns.map((c) => [c.id, c])), [concerns]); | ||
| const [selected, setSelected] = useState(concerns[0]?.id ?? ''); |
There was a problem hiding this comment.
Suggestion: The selected concern ID is initialized only once and is not synchronized with refreshed concerns. If the selected concern is removed or replaced while the artifact remains mounted, current falls back to the first concern while no concern receives the selected styling, so the focus card and highlighted box describe different concerns. Reconcile selected against the current concern IDs when the payload changes. [stale reference]
Severity Level: Major ⚠️
- ❌ Refreshed concern maps can lose visual selection.
- ⚠️ Focus card and highlighted box can disagree.
- ⚠️ Curator updates can present stale concern context.Steps of Reproduction ✅
1. Open the fixture gallery through `ExhibitGalleryApp` at
`web/components/exhibits/ExhibitGalleryApp.tsx:26-38`; `ExhibitStage` renders concern
snapshots through `web/components/exhibits/ExhibitStage.tsx:76`.
2. The initial concern IDs are defined at
`web/components/exhibits/fixture-gallery.ts:185-191`, and the component initializes
`selected` to the first concern ID at `web/components/exhibits/ConcernSnapshot.tsx:28`.
3. While the component remains mounted, refresh the same concern artifact with a payload
that removes that selected ID or replaces it with different IDs. The `useState`
initializer does not rerun, so `selected` still contains the removed ID.
4. At `web/components/exhibits/ConcernSnapshot.tsx:29-30`, `current` falls back to
`concerns[0]`, while the button class at
`web/components/exhibits/ConcernSnapshot.tsx:49-53` compares against the stale ID and
highlights nothing. The focus card therefore describes the first concern while no concern
is selected; reconcile `selected` whenever the concern IDs change.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** web/components/exhibits/ConcernSnapshot.tsx
**Line:** 28:28
**Comment:**
*Stale Reference: The selected concern ID is initialized only once and is not synchronized with refreshed `concerns`. If the selected concern is removed or replaced while the artifact remains mounted, `current` falls back to the first concern while no concern receives the selected styling, so the focus card and highlighted box describe different concerns. Reconcile `selected` against the current concern IDs when the payload changes.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fixThere was a problem hiding this comment.
Pull request overview
Adds an Exhibit Stage “fixture gallery” surface to the web app, exposing a curated set of exhibit-style visualizations behind an additive ?mode=exhibits entry point while keeping the default surface as AgentVisualizer.
Changes:
- Introduces typed exhibit artifact contracts plus a hand-authored fixture gallery to drive the stage.
- Adds the ExhibitStage UI (rail + rotating main frame) and ports/implements multiple exhibit renderers + shared primitives/CSS.
- Adds a
?mode=exhibitsswitch inweb/app-entry.tsxand restores a prototype reference doc.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| web/components/exhibits/Walkthrough.tsx | Walkthrough exhibit renderer (central narrative + satellites/files). |
| web/components/exhibits/types.ts | Exhibit artifact envelope + discriminated payload types and helpers. |
| web/components/exhibits/ThermalMap.tsx | Thermal map exhibit renderer with squarified treemap layout. |
| web/components/exhibits/Seismograph.tsx | Seismograph exhibit renderer (time-axis trace + annotations). |
| web/components/exhibits/RelationshipDag.tsx | Relationship DAG exhibit renderer (nodes/edges + focus card). |
| web/components/exhibits/primitives.tsx | Shared exhibit primitives (Frame/Chip/Node) + SVG helpers. |
| web/components/exhibits/Momentum.tsx | Momentum exhibit renderer (gauge + stats + next items). |
| web/components/exhibits/index.ts | Barrel exports for the exhibits surface. |
| web/components/exhibits/fixture-gallery.ts | Hand-authored fixture ExhibitArtifact[] gallery content. |
| web/components/exhibits/ExhibitStage.tsx | The stage container (rail, rotation, active exhibit swapping). |
| web/components/exhibits/exhibits.css | CSS for the exhibit stage + all exhibit visuals. |
| web/components/exhibits/ExhibitGalleryApp.tsx | Standalone fixture-only app wrapper for the stage. |
| web/components/exhibits/ConcernSnapshot.tsx | Concern snapshot exhibit renderer (heat + flows + focus card). |
| web/components/exhibits/ActivityNarrative.tsx | Activity narrative exhibit renderer (timeline foldout + scrub). |
| web/app-entry.tsx | Adds ?mode=exhibits route switch; default remains AgentVisualizer. |
| docs/ideas/repoviz/exhibit-prototype.jsx | Restored visual prototype reference document. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export default function ActivityNarrative({ payload }: ActivityNarrativeProps) { | ||
| const reduce = useReducedMotion(); | ||
| const { beats, threads } = payload; | ||
| const [active, setActive] = useState(beats.length - 1); |
| * Fixture gallery — a hand-authored exhibition of the REAL Codex homelab | ||
| * coordinator session (see | ||
| * `tests/fixtures/transcripts/codex/rollout-2026-07-23-homelab-coordinator.ground-truth.md`). | ||
| * |
| } from "lucide-react"; | ||
|
|
||
| type ViewId = "dag" | "timeline" | "walkthrough" | "architecture" | "momentum"; | ||
|
|
||
| type ViewDef = { |
| */ | ||
| export { default as ExhibitStage } from './ExhibitStage'; | ||
| export type { ExhibitStageProps } from './ExhibitStage' | ||
| export { default as fixtureGallery } from './fixture-gallery' |
There was a problem hiding this comment.
Suggestion: The public barrel export includes fixtureGallery, which contains details from a real homelab coordinator session, including the exposed FORGEJO_INTERNAL_TOKEN incident and rollout history. Because the gallery is reachable through the production client bundle, any visitor who opens the exhibits mode can inspect these operational details. Replace this with sanitized synthetic fixture data or keep real session fixtures out of the client bundle. [security]
Severity Level: Major ⚠️
- ⚠️ Exhibit mode discloses real homelab operational history.
- ⚠️ Client bundles expose token names and remediation details.
- ⚠️ Database, deployment, and credential-state metadata becomes public.Steps of Reproduction ✅
1. Build the web client using the repository's `npm run build:web` script from
`package.json:11`; Vite statically follows the barrel export at
`web/components/exhibits/index.ts:11` and includes `fixture-gallery.ts` in the client
bundle.
2. Open the documented gallery entry point with `?mode=exhibits`;
`web/app-entry.tsx:10-12` and `web/electron-entry.tsx:11-15` select `ExhibitGalleryApp`
for that query.
3. `ExhibitGalleryApp` imports and passes `fixtureGallery` to `ExhibitStage` at
`web/components/exhibits/ExhibitGalleryApp.tsx:6-8,26-38`, making the fixture data
available to every gallery visitor.
4. Inspect the rendered exhibit or downloaded JavaScript bundle and observe real-session
operational details from
`web/components/exhibits/fixture-gallery.ts:2-13,69-70,112,259-261`, including the named
`FORGEJO_INTERNAL_TOKEN` incident, database scope, deployment status, GHCR failure, and
deferred rotation. The token value itself is not present, but these details should still
be replaced with synthetic data or excluded from the client bundle.(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** web/components/exhibits/index.ts
**Line:** 11:11
**Comment:**
*Security: The public barrel export includes `fixtureGallery`, which contains details from a real homelab coordinator session, including the exposed `FORGEJO_INTERNAL_TOKEN` incident and rollout history. Because the gallery is reachable through the production client bundle, any visitor who opens the exhibits mode can inspect these operational details. Replace this with sanitized synthetic fixture data or keep real session fixtures out of the client bundle.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix- Add vitest + root test infrastructure (vitest.config.ts, vitest.config.build.ts). npm test runs the fast IPC contract suite; npm run test:build runs the slow build-smoke suite separately. - tests/ipc-contract.test.ts: pin IPC channel names, assert uniqueness, assert avc: namespace (not shadow:/vscode:), assert runtime-frozen. The freeze test caught a real gap: IPC was declared `as const` (compile-time only) but not Object.freeze'd at runtime — a rename would silently succeed in JS. - electron/ipc-channels.ts: wrap IPC in Object.freeze() so the contract test passes and the wire protocol is runtime-immutable. - tests/build-smoke.test.ts: run `npm run build` and assert dist-web/index.html + dist-electron/main.js exist with non-trivial size. Catches the stacked-PR dependency leak below. - web/electron-entry.tsx: remove the ExhibitGalleryApp import and ?mode=exhibits switch. The substrate PR (PR #119) shipped an import of ./components/exhibits which only resolves in PR #121 — the substrate PR did not build independently. The exhibits entry switch belongs in PR #121, not the substrate PR. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
586f9b3 to
f81144c
Compare
Code Review SummaryStatus: No New Issues Found | Recommendation: Review existing comments before merge All issues identified in this PR have already been flagged in existing review comments. The pre-existing comments cover valid concerns that should be addressed:
Please address the existing comments before merging. Note on doctrine: Per Files Reviewed (16 files)
Previous Review Summary (commit 7e3ab0a)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit 7e3ab0a)Status: No New Issues Found | Recommendation: Review existing comments before merge All issues identified in this PR have already been flagged in existing review comments. The pre-existing comments cover valid concerns that should be addressed:
Please address the existing comments before merging. Note on doctrine: Per Files Reviewed (16 files)
Reviewed by ling-3.0-flash-free · Input: 86.4K · Output: 4.3K · Cached: 112.8K |
* feat: codex replay corpus + ingestion/replay design Add a real, sanitized Codex CLI rollout (3,677 lines, 4.5h homelab database-recovery coordinator session) as the deterministic replay corpus, with human-verified ground truth as assertable expectations, and the design for the Codex harness driver + deterministic replay runner (docs/plans/plan-codex-replay.md). Fixture provenance and sanitization (17 secrets -> REDACTED_*) are documented in the ground-truth file; both files are frozen. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U9EpjZNoWaXLzfG93tdvTU * docs: capture v1 curator rebuild requirements before pin Record the nuke-and-copy-agent-flow plan (req-v1-curator, visual substrate inventory) and point roadmap M2/M3 at them so the v0 snapshot preserves the restart rationale. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> * feat: replace v0 codebase with copied agent-flow substrate Nuke the classifier-era src/tests/docs and copy agent-flow web/ + extension ingestion (minus VS Code glue) as the v1 renderer substrate. Apache-2.0 LICENSE + NOTICE; fresh governing docs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> * feat: scaffold Electron shell with IPC bridge for agent-flow renderer Add flat root package.json, main/preload, and an Electron Vite SPA entry that reuses vscode-bridge over contextBridge IPC. Document copy-verify findings (prefer app-style SPA over webview IIFE; SSE host is reference-only). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> * chore: make pre-push tests pass on substrate PR Substrate slice has no host/ingestion package yet; stub test scripts so stacked PR pushes work with the existing pre-push hook. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> * test: harden substrate PR with build-smoke + IPC contract tests - Add vitest + root test infrastructure (vitest.config.ts, vitest.config.build.ts). npm test runs the fast IPC contract suite; npm run test:build runs the slow build-smoke suite separately. - tests/ipc-contract.test.ts: pin IPC channel names, assert uniqueness, assert avc: namespace (not shadow:/vscode:), assert runtime-frozen. The freeze test caught a real gap: IPC was declared `as const` (compile-time only) but not Object.freeze'd at runtime — a rename would silently succeed in JS. - electron/ipc-channels.ts: wrap IPC in Object.freeze() so the contract test passes and the wire protocol is runtime-immutable. - tests/build-smoke.test.ts: run `npm run build` and assert dist-web/index.html + dist-electron/main.js exist with non-trivial size. Catches the stacked-PR dependency leak below. - web/electron-entry.tsx: remove the ExhibitGalleryApp import and ?mode=exhibits switch. The substrate PR (PR #119) shipped an import of ./components/exhibits which only resolves in PR #121 — the substrate PR did not build independently. The exhibits entry switch belongs in PR #121, not the substrate PR. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com>
f81144c to
a7ba849
Compare
Recover typed exhibit components, fixture gallery, and stage CSS under web/components/exhibits; restore exhibit-prototype.jsx from the v0 pin. Additive ?mode=exhibits entry leaves AgentVisualizer as the default surface. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
Add tests/exhibit-contract.test.ts: a pure (non-DOM) contract test for the exhibit vocabulary and fixture gallery. Asserts the typed contracts from docs/plans/req-v1-curator.md §6 hold: - AUTHORED_EXHIBIT_TYPES is exactly the v1 seven (no live_graph) - Every fixture artifact is a valid ExhibitArtifact (id, title, narrative, relevance in [0,1], decayClass, status, createdAtEvent) - narrative is MANDATORY and non-trivial (>20 chars — not a placeholder) - exhibitType is in the v1 vocabulary (7 authored + live_graph) - ids are unique; relevance values are spread; >=5 distinct types covered - Type guards (isExhibitOfType, isRetired) narrow correctly This is the test the prior suite was missing: the exhibit type contracts and fixture gallery were unverified. A DOM mount test belongs in a later PR once the live-exhibits hook (PR #123) and a jsdom + testing-library setup land. The root vitest config arrives via rebase from the substrate PR (#119); the test runs via `npx vitest run tests/exhibit-contract.test.ts` in the meantime. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
7e3ab0a to
1104423
Compare
User description
Summary
feat/exhibit-componentsintoweb/components/exhibits/?mode=exhibitsentry for fixture gallery; default remains AgentVisualizerdocs/ideas/repoviz/exhibit-prototype.jsxfrom the v0 pin as look/feel referenceHonest status
live_graphis a placeholder; not the default product surfaceTest plan
npm run buildhttp://127.0.0.1:5173/?mode=exhibits(or Electron with that query) — fixture exhibits renderCodeAnt-AI Description
Add an interactive Exhibit Stage for exploring curated agent-session stories
What Changed
?mode=exhibitsgallery while keeping the live visualizer as the default viewImpact
✅ Interactive agent-session gallery✅ Clearer progress, risks, and unfinished work✅ Live visualizer remains unchanged by default💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.