Workspace
Current responsibility: own the browser's shared model, run, layer, and neuron selection, mode registry, layout context, theme, and onboarding tour. The first slice is implemented in selection.ts, modes.ts, layout.tsx, theme.tsx, and the tour files. WS-03, pinning and layout restoration, is not started. It also owns the online-visitor bar under Run history (WS-04), its only server slice: schemas.py → service.py → routes.py and api.ts → hooks.ts → Presence.tsx (hover shows a per-country world map, WorldMap.tsx). It does not own run data, solver state, or ACT commands. See the parent scope, the repository rules, and the development task guide.
Change Guide
| Goal | Edit here | Conditional / reused path |
|---|---|---|
| Change selection/reset behavior | selection.ts and selection.test.ts | Update app.tsx or consumers only when action/prop contracts change. No server change. |
| Add or remap a center mode | modes.ts, its owning view, modes.test.ts | Existing app composition uses the registry. A new engine method also needs verification/bridge support; a display-only mode does not. |
| Change tour wording or order | tourSteps.ts | Copy-only changes need no prose-pinning tests. Change tour.tsx for interaction; app.tsx only for region targets or composition. |
| Change tour placement | placeCard in tourSteps.ts and its placement tests | Keep viewport-boundary cases in tourSteps.test.ts; render desktop/mobile. |
| Change the online-visitor bar or its country map | Presence.tsx, WorldMap.tsx, hooks.ts (interval), service.py (window, country grouping) | Wire changes go through schemas.py and npm run gen:types; keep test_workspace.py green. |
| Change context bar or theme | layout.tsx, theme.tsx, relevant styles.css | Other feature modules only if their public selection/navigation contract changes. |
Pinning and restoration are WS-03 future work, not an existing docking API.
Flow Diagram
The online-visitor bar is a heartbeat loop, independent of selection:
The context bar and theme are independent presentation helpers in layout.tsx and theme.tsx. The tour has its own path:
| Block | Implementation and contract |
|---|---|
| User input | app.tsx callbacks. Produces selection actions or mode changes. |
| Selection | selectionReducer in selection.ts. Returns a new context and revision; model changes clear run, layer, and neuron. |
| Modes | modes, modeForMethod, and modeForId in modes.ts. Maps fuzz, interval, and bab to visible center views. |
| Layout and theme | ContextBar in layout.tsx and theme state in theme.tsx. Renders shared context; it does not fetch. |
| Tour | Tour in tour.tsx plus TOUR_STEPS in tourSteps.ts. Reads data-tour regions and ends on Finish, Skip, or Escape. A waitFor: "model" step (Build and load) lets only its region take clicks, keeps Next disabled until app.tsx reports a loaded model, then advances by itself so later steps spotlight the live center panels. |
| Presence | PresenceService.beat in service.py: in-memory map of browser id to last heartbeat, pruned to a 90 s window, with the browser's country from Cloudflare's CF-IPCountry header (XX, Tor T1, or a direct local request count as unknown); no IPs, no persistence. The response carries only per-country totals. One id per browser (localStorage), so tabs are deduplicated. Correct only while the service runs as one process. |
| Neighbor handoff | Module views receive selection and callbacks from app.tsx; their data path continues through the parent flow diagram. |
Validation
Run the browser test suite:
npm test
.venv/bin/python -m pytest visual_bench/workspaceRelevant observable behavior is that selection changes update the context bar and dependent views, mode methods select the corresponding center view, and the tour starts once, can be replayed from Guide, and exits with Finish, Skip, or Escape. These are validation instructions, not a new test result.
Reference and Backlog
Current files and routes
Current Files and Routes
Route: POST /api/presence (body PresenceHeartbeat, response PresenceOut), mounted by server.py. app.tsx is the composition root that consumes this module.
| File | Responsibility |
|---|---|
| selection.ts | Pure reducer for modelId, runId, layerId, neuron, and monotonic revision. Changing model or run clears incompatible context. |
| selection.test.ts | Selection transitions and stale-context behavior. |
| modes.ts | The Fuzzing, Verification, and BaB mode registry. Each entry maps a run method to a view. Add modes here, not in app.tsx. |
| modes.test.ts | Mode IDs and method mapping. |
| layout.tsx | Context bar showing the current model, run, layer, and index. |
| theme.tsx | Light and dark theme toggle with persistence. |
| tour.tsx | Skippable first-visit tour, keyboard navigation, target measurement, the interactive Build-and-load gate, and portal rendering. |
| tourSteps.ts | Tour copy, order, target regions, and missing-region hints. |
| tourSteps.test.ts | Tour step and placement behavior. |
| schemas.py | PresenceHeartbeat and PresenceOut wire models. |
| service.py | PresenceService: in-memory online-visitor count. |
| routes.py | POST /api/presence. |
| test_workspace.py | Deduplication, expiry, and route validation. |
| api.ts, hooks.ts | Heartbeat call and the 20 s usePresence query. |
| Presence.tsx | Online-visitor bar under Run history; hover card with the country list. |
| WorldMap.tsx | Per-country choropleth (d3-geo + world-atlas 110m), loaded on first hover. |
| countryCodes.ts | Generated ISO alpha-2 to atlas numeric id table. |
Browser-wide HTTP, wire-number, query-key, and shared UI code lives in ../shared/. Views obtain server data through their module hooks.
Task acceptance, rationale, and planned capabilities
Tasks and Acceptance
All tasks remain tracked in the development plan. Dependencies are acceptance prerequisites, not import instructions.
| ID | Deliverable | Depends on | Completion evidence |
|---|---|---|---|
| WS-01 | Define selection state and reducer | BASE-02 | Given different layer/node IDs, actions preserve their object kinds and snapshot scope. |
| WS-02 | Link two panels through context | WS-01 | Select A then B; delaying A’s response cannot revert either active panel. |
| WS-03 | Add pinning and layout restoration | WS-02 | A pinned panel survives active-context changes; invalid restored references have an explicit fallback. |
| WS-04 | Show the online-visitor count under Run history | BASE-02 | Two browsers count as two, two tabs of one browser as one, and a silent browser drops out after 90 s; hovering shows the countries from CF-IPCountry (test_workspace.py, hover screenshot). |
Current status: WS-01 and WS-02 are implemented as the selection reducer and application wiring. WS-04 is implemented. WS-03 is planned.
Use pure state transitions and derived context rather than a feature-wide event bus. A layout library may be added later, but domain objects must not contain renderer instances or layout-library nodes. Pinning, restoration, and unavailable-object states belong to WS-03 and are not current capabilities.
Planned public operations are reduceWorkspace, getPanelContext, and navigateTo. Their names describe intended boundaries, not shipped APIs. The current equivalent is selectionReducer plus callbacks in app.tsx.
Owner: C. A reviews scientific identity and semantics. On task completion, record the implementation, fixture provenance, exact commands and results, ACT or provider dependencies, and unverified behavior here.