story-kit: create 173_bug_pipeline_board_lozenges_dont_update_on_agent_state_changes

This commit is contained in:
Dave
2026-02-24 23:39:52 +00:00
parent ef903644a7
commit 5c25bfcabd

View File

@@ -7,22 +7,35 @@ title: Pipeline board lozenges don't update on agent state changes
## Description ## Description
The pipeline board (`LozengeFlyContext`) only refreshes on `WorkItemChanged` and `PipelineState` WebSocket events (file moves between stages). It does not react to `AgentStateChanged` events. This means lozenge colors (amber=unassigned, green=agent working) don't update in real-time when agents are assigned or complete. When an agent is assigned to a work item (coder, QA, mergemaster), the pipeline board lozenge should turn from amber (unassigned) to green (agent working). This works inconsistently — sometimes the lozenge goes green, sometimes it stays amber until a full page refresh. The server data is always correct (the agent IS assigned), so the issue is in the WebSocket push or frontend rendering.
The coder assignment appeared to work because the file moved from `1_upcoming` to `2_current` at the same time, triggering a `WorkItemChanged` refresh. But QA assignment doesn't move the file (it's already in `3_qa`), so the lozenge stays amber until a full page refresh. ## Investigation findings
## Root cause **Server side is correct**: `notify_agent_state_changed()` fires on every `start_agent` call. The WS handler sends both an `AgentStateChanged` message and a `PipelineState` refresh (ws.rs:192-206). The `PipelineState` includes agent assignments via `build_active_agent_map` (workflow.rs:53-83) which correctly filters for Pending/Running agents.
`LozengeFlyContext.tsx` does not consume `agentStateVersion` (or any equivalent signal from `AgentStateChanged` WebSocket events). Only `AgentPanel.tsx` reacts to that signal via `stateVersion`. **Likely race condition**: When a story advances stages (e.g. coder passes → moves to QA → QA agent assigned), two events fire close together:
1. File move (`WorkItemChanged`) → triggers `PipelineState` push (no agent yet)
2. Agent assignment (`AgentStateChanged`) → triggers `PipelineState` push (with agent)
If the first push overwrites or interferes with the second, the lozenge stays amber. This is inconsistent — sometimes the second push wins (green), sometimes the first push wins (amber).
**Frontend animation complexity**: `LozengeFlyContext.tsx` uses `useLayoutEffect` to diff previous vs current pipeline state and trigger fly-in/fly-out animations (lines 160-240). When a story changes stage AND agent simultaneously, the animation system processes both a fly-out (coder leaving) and fly-in (QA arriving), which may interfere.
**The pipeline board DOES receive `PipelineState` updates** — it's passed as a prop from `Chat.tsx:1071` (`<LozengeFlyProvider pipeline={pipeline}>`). So the data reaches the component. The issue is either:
- The second `PipelineState` (with agent) is being lost or arrives before the agent is in the HashMap
- React batches the two rapid state updates and the `useLayoutEffect` diff misses the agent change
- The fly-in/fly-out animation logic interferes when stage and agent change simultaneously
## Key files ## Key files
- `frontend/src/components/LozengeFlyContext.tsx` — needs to react to `AgentStateChanged` - `server/src/http/ws.rs:188-215` — WS handler that sends both `AgentStateChanged` and `PipelineState`
- `frontend/src/components/Chat.tsx:1074` — passes `stateVersion={agentStateVersion}` to `AgentPanel` but not to the pipeline board - `server/src/http/workflow.rs:42-84``load_pipeline_state` and `build_active_agent_map`
- `frontend/src/components/AgentPanel.tsx:312` — example of how `stateVersion` triggers a re-fetch - `server/src/agents.rs:447` — where `notify_agent_state_changed` fires in `start_agent`
- `frontend/src/components/LozengeFlyContext.tsx:160-240``useLayoutEffect` pipeline diff and animation logic
- `frontend/src/components/Chat.tsx:237-238``onPipelineState` handler that sets `pipeline` state
## Acceptance Criteria ## Acceptance Criteria
- [ ] Pipeline board re-fetches and updates lozenge colors when an `AgentStateChanged` event is received - [ ] Agent assignment reliably turns lozenges green for all agent types (coder, QA, mergemaster)
- [ ] QA agent assignment turns the lozenge green without a page refresh - [ ] No full page refresh required to see agent state changes on the pipeline board
- [ ] All tests pass - [ ] All tests pass