nexus/.planning/phases/23-brainstormer-flow/23-VERIFICATION.md

20 KiB
Raw Blame History

phase verified status score re_verification human_verification
23-brainstormer-flow 2026-04-01T22:15:00Z human_needed 13/15 must-haves verified false
test expected why_human
Open a new conversation and verify the Brainstormer (general agent) greets the user with a structured questioning flow The Brainstormer agent introduces itself and begins asking clarifying questions (What are you building? Why? Constraints?). The agent must respond using a real LLM adapter, not the streamEcho stub. The streamEcho stub (pre-existing from Phase 22) only echoes back user input word-by-word — it does not greet the user or produce structured questions. The Brainstormer persona requires a real LLM integration. AGENT-02 (structured questioning) and Success Criterion 1 (greets user, begins questioning) cannot be verified without a live LLM connection.
test expected why_human
After a simulated Brainstormer conversation, POST a spec_card message to a conversation via the API, then verify ChatSpecCard renders in the chat A message with messageType=spec_card renders as a card with What, Why, Constraints, Success sections plus Send to PM, Edit, and Save as Draft buttons. The ChatSpecCard component exists and is wired correctly in ChatMessage dispatch. However, there is no server-side mechanism in Phase 23 that creates spec_card messages — the Brainstormer LLM must produce them when it concludes its questioning flow. Rendering can only be tested by manually POSTing a spec_card message via the API or having a real LLM produce it.
test expected why_human
Verify the general agent SOUL.md persona reflects Brainstormer / structured-questioning behavior for AGENT-01 and AGENT-02 The general role agent's system prompt includes Brainstormer-style instructions: greet users, ask clarifying questions, produce a spec in the spec_card format. server/src/onboarding-assets/general/SOUL.md currently contains a generic Generalist persona with no mention of Brainstormer behavior, clarifying questions, or spec card generation. AGENT-01 states the default agent should behave as a Brainstormer. This persona gap cannot be verified programmatically — it requires a human to confirm whether the persona configuration is intentionally deferred or a gap.

Phase 23: Brainstormer Flow — Verification Report

Phase Goal: Users can open Nexus, start a conversation with the Brainstormer, receive structured clarifying questions, approve a spec, and watch it become real Nexus tasks — without ever touching the dashboard Verified: 2026-04-01T22:15:00Z Status: human_needed Re-verification: No — initial verification


Goal Achievement

Observable Truths (from Success Criteria)

# Truth Status Evidence
1 Brainstormer is default agent for new conversations; greets user and begins structured questioning ? UNCERTAIN useBrainstormerDefault auto-selects general agent — wired. But streamEcho stub (pre-existing from Phase 22) echoes text, does not produce greetings or questions. No Brainstormer persona in general/SOUL.md.
2 Brainstormer produces formatted spec card (What/Why/Constraints/Success + action buttons) ? UNCERTAIN ChatSpecCard component is fully implemented with all UI. messageType=spec_card dispatch is wired in ChatMessage. No server-side mechanism in Phase 23 creates spec_card messages — requires real LLM output or manual API call.
3 "Send to PM" button triggers handoff indicator in chat showing "Brainstormer → PM" ✓ VERIFIED handleHandoff in ChatPanel calls chatApi.handoffSpec → POST /conversations/:id/handoff → inserts messageType=handoff system message → ChatHandoffIndicator renders it. Full chain wired end-to-end.
4 PM agent creates Nexus issues from spec; user sees task IDs in chat ✓ VERIFIED Handoff route calls issueSvc.create(), inserts messageType=task_created message with {taskId, taskTitle, taskUrl} JSON. ChatTaskCreatedBadge renders task ID with View task link.
5 Engineer/Generalist completion status update appears in chat ✓ VERIFIED POST /conversations/:id/status-update inserts messageType=status_update system message. ChatStatusUpdateBadge renders CheckCircle2 + agent + task reference. chatApi.postStatusUpdate() exists for callers.

Automated score: 3/5 truths verified, 2/5 need human confirmation


Required Artifacts

Artifact Expected Status Details
packages/db/src/schema/chat_messages.ts messageType column definition ✓ VERIFIED messageType: text("message_type") on line 13, nullable
packages/db/src/migrations/0049_add_message_type.sql SQL migration for message_type ✓ VERIFIED ALTER TABLE "chat_messages" ADD COLUMN "message_type" text;
packages/shared/src/types/chat.ts ChatMessage.messageType field ✓ VERIFIED messageType: string | null; in ChatMessage interface
packages/shared/src/validators/chat.ts handoffSchema and messageType in createMessageSchema ✓ VERIFIED Both handoffSchema (with spec/targetRole) and messageType: z.string().optional() in createMessageSchema
packages/shared/src/index.ts handoffSchema and Handoff re-exported ✓ VERIFIED Lines 564 and 568 export handoffSchema and type Handoff
server/src/services/chat.ts addSystemMessage helper and messageType in addMessage ✓ VERIFIED addSystemMessage at line 196, addMessage accepts messageType?: string at line 140
server/src/routes/chat.ts handoff and status-update routes ✓ VERIFIED POST /conversations/:id/handoff at line 151, POST /conversations/:id/status-update at line 194
ui/src/components/ChatSpecCard.tsx Spec card with 4 fields and action buttons ✓ VERIFIED 233 lines; renders What/Why/Constraints/Success; edit mode; Send to PM / Edit / Save as Draft buttons
ui/src/components/ChatHandoffIndicator.tsx Separator-style handoff indicator ✓ VERIFIED Flanking <hr aria-hidden="true">, aria-label="Agent handoff from Brainstormer to PM"
ui/src/components/ChatTaskCreatedBadge.tsx Task created badge ✓ VERIFIED Loading state ("Creating task...") and resolved state with taskId, taskTitle, View task link
ui/src/components/ChatStatusUpdateBadge.tsx Status update badge ✓ VERIFIED CheckCircle2 icon, agentName, taskId, View task link, role="status"
ui/src/hooks/useBrainstormerDefault.ts General agent auto-selector ✓ VERIFIED Queries ["agents", selectedCompanyId], filters role === "general", sorts by createdAt, returns first
ui/src/components/ChatMessage.tsx messageType dispatch to specialized components ✓ VERIFIED Dispatch block at line 51 routes to ChatSpecCard / ChatHandoffIndicator / ChatTaskCreatedBadge / ChatStatusUpdateBadge
ui/src/components/ChatMessageList.tsx messageType prop propagation ✓ VERIFIED messageType={msg.messageType}, conversationId={conversationId}, onHandoff={onHandoff} passed to <ChatMessage>
ui/src/components/ChatPanel.tsx useBrainstormerDefault wiring ✓ VERIFIED Imported, called, auto-select useEffect wired, handleHandoff callback wired, onHandoff={handleHandoff} on ChatMessageList
ui/src/api/chat.ts handoffSpec and postStatusUpdate API methods ✓ VERIFIED handoffSpec() at line 152, postStatusUpdate() at line 163
Wave 0 test stubs (5 files) it.todo() stubs for all Phase 23 components/hooks ✓ VERIFIED All 5 files exist: ChatSpecCard.test.tsx (9 todos), ChatHandoffIndicator.test.tsx, ChatTaskCreatedBadge.test.tsx, ChatStatusUpdateBadge.test.tsx, useBrainstormerDefault.test.ts (4 todos)

From To Via Status Details
packages/db/src/schema/chat_messages.ts packages/shared/src/types/chat.ts messageType field match ✓ WIRED Both define messageType as nullable; schema uses text("message_type"), type uses string | null
server/src/routes/chat.ts server/src/services/chat.ts svc.addSystemMessage call ✓ WIRED Grep confirms svc.addSystemMessage called 3 times in chat.ts routes
server/src/routes/chat.ts server/src/services/issues.ts issueSvc.create for task creation ✓ WIRED issueService imported from ../services/issues.js, issueSvc.create() called in handoff route
ui/src/components/ChatMessageList.tsx ui/src/components/ChatMessage.tsx messageType={msg.messageType} prop ✓ WIRED Line 148: messageType={msg.messageType} and onHandoff={onHandoff} passed
ui/src/components/ChatMessage.tsx ui/src/components/ChatSpecCard.tsx dispatch when messageType === "spec_card" ✓ WIRED Line 52: if (messageType === "spec_card") return <ChatSpecCard .../>
ui/src/components/ChatPanel.tsx ui/src/hooks/useBrainstormerDefault.ts hook call for default agent selection ✓ WIRED Imported at line 17, called at line 32, used in useEffect at line 36
ui/src/components/ChatSpecCard.tsx ui/src/api/chat.ts handoffSpec call on Send to PM ? PARTIAL ChatSpecCard calls onHandoff?.(spec) prop callback — it does NOT call chatApi.handoffSpec directly. ChatPanel.handleHandoff calls chatApi.handoffSpec. The chain: ChatSpecCard → onHandoff prop → ChatPanel.handleHandoff → chatApi.handoffSpec. This is correct and intentional — ChatSpecCard correctly delegates to parent.
ui/src/hooks/useBrainstormerDefault.ts ui/src/api/agents.ts useQuery with agents queryKey ✓ WIRED queryKey: ["agents", selectedCompanyId], queryFn: () => agentsApi.list(selectedCompanyId!)

Note on ChatSpecCard → chatApi link: The PLAN specified ChatSpecCard → chatApi.handoffSpec directly, but the actual implementation correctly uses prop callback delegation (onHandoff prop → ChatPanel.handleHandoffchatApi.handoffSpec). This is an intentional architecture improvement (component stays data-free) and does not represent a gap — the chain is fully wired.


Data-Flow Trace (Level 4)

Artifact Data Variable Source Produces Real Data Status
useBrainstormerDefault.ts agents (Agent[]) agentsApi.list() → GET /companies/:id/agents Yes — real DB query in agents route ✓ FLOWING
ChatSpecCard.tsx spec (SpecContent) JSON.parse(content) from ChatMessage content prop Content comes from chat_messages DB row via useChatMessages ✓ FLOWING
ChatTaskCreatedBadge.tsx taskId, taskTitle, taskUrl JSON.parse(content) from message; content set by handoff route from issueSvc.create() return Real DB insert via issueService ✓ FLOWING
ChatStatusUpdateBadge.tsx agentName, taskId JSON.parse(content) from message; content set by caller via POST /status-update Caller-provided data; no hardcoded stubs ✓ FLOWING
ChatPanel.tsx handleHandoff activeConversationId useChatPanel() context, set when user opens a conversation Real context value ✓ FLOWING
ChatMessageList.tsx messages messages (ChatMessageType[]) useChatMessages(conversationId) → GET /conversations/:id/messages Real DB query via chatService.listMessages() ✓ FLOWING

Behavioral Spot-Checks

Behavior Check Result Status
Handoff route exists and is callable grep "router.post.*handoff" in chat.ts Found at line 151 ✓ PASS
status-update route exists grep "router.post.*status-update" in chat.ts Found at line 194 ✓ PASS
issueSvc.create called in handoff Static analysis of chat.ts issueSvc.create(companyId, {...}) at line 173 ✓ PASS
addSystemMessage inserts 3 typed messages in handoff flow Static analysis of chat.ts routes handoff (line 160), task_created (line 181); status-update in separate route (line 202) ✓ PASS
chatApi.handoffSpec posts to correct endpoint grep "handoffSpec" in chat.ts api.post("/conversations/${conversationId}/handoff", ...) at line 157 ✓ PASS
ChatMessage messageType dispatch complete grep "spec_card|handoff|task_created|status_update" in ChatMessage.tsx All 4 branches present at lines 52, 62, 65, 73 ✓ PASS
Streaming synthetic message has messageType: null ChatMessageList.tsx line 49 messageType: null present — no false dispatch ✓ PASS
All Phase 23 commits exist in git git show --stat on all 5 documented commit SHAs 6e436950, 0a1b3dc0, 588bbdd5, 1489e499, 651864ba, c7a48bc5, 3f575453 — all verified ✓ PASS
Brainstormer default agent auto-select useEffect grep "brainstormerDefaultId" in ChatPanel.tsx useEffect at line 35 sets activeAgentId when === null && !activeConversationId ✓ PASS
Structured questioning / spec_card creation by LLM Requires running LLM streamEcho stub only echoes text ? SKIP — needs human

Requirements Coverage

Requirement Source Plan Description Status Evidence
AGENT-01 23-00, 23-02, 23-03 Default agent is the Brainstormer (general role) ? PARTIAL Wiring: useBrainstormerDefault selects first role=general agent and ChatPanel auto-selects it for new conversations. Gap: general/SOUL.md contains Generalist persona, not Brainstormer persona — no structured questioning instructions. Behavioral verification requires human.
AGENT-02 23-00, 23-02, 23-03 Brainstormer follows structured questioning, produces spec template ? PARTIAL UI infra: ChatSpecCard renders spec card when messageType=spec_card. Wiring: dispatch in ChatMessage is in place. Gap: no mechanism in Phase 23 creates spec_card messages from the server; the LLM must produce them and the LLM integration (streamEcho stub) does not exist yet.
AGENT-03 23-01 PM agent receives specs from chat and creates Nexus tasks ✓ SATISFIED POST /conversations/:id/handoff calls issueSvc.create(), returns issue with id, identifier, title. ChatTaskCreatedBadge renders task reference in chat.
AGENT-05 23-01, 23-02, 23-03 Handoff indicators visible in chat ✓ SATISFIED ChatHandoffIndicator renders when messageType=handoff. Handoff route inserts messageType=handoff system message. Full chain verified.
AGENT-06 23-01, 23-03 Task creation from chat becomes Nexus issue ✓ SATISFIED Handoff route creates issue via issueService.create(). ChatTaskCreatedBadge displays resulting task ID. chatApi.postStatusUpdate() available for agents.
AGENT-07 23-01, 23-02, 23-03 Status updates from agents appear in chat ✓ SATISFIED POST /conversations/:id/status-update inserts messageType=status_update message. ChatStatusUpdateBadge renders CheckCircle2 + agent + task reference.
CHAT-09 23-01, 23-02, 23-03 System message indicator for handoff visible in chat ✓ SATISFIED messageType=handoff in DB identifies handoff messages. ChatHandoffIndicator renders separator-style indicator with content text between two hr elements.

Orphaned requirements check: All 7 requirements mapped to Phase 23 in REQUIREMENTS.md (AGENT-01, AGENT-02, AGENT-03, AGENT-05, AGENT-06, AGENT-07, CHAT-09) are covered in at least one plan's frontmatter. No orphaned requirements.


Anti-Patterns Found

File Line Pattern Severity Impact
server/src/services/chat.ts 220-227 streamEcho stub yields words with 50ms delay instead of real LLM ⚠️ Warning Pre-existing from Phase 22. The Brainstormer cannot produce greetings, questions, or spec_card messages — it echoes user input. Does NOT block handoff/task-creation flow (those are explicit API calls, not LLM-generated), but blocks Success Criteria 1 and 2.
server/src/onboarding-assets/general/SOUL.md 1-end Generalist persona with no Brainstormer behavior ⚠️ Warning The general role agent is selected as default Brainstormer, but its persona contains no structured questioning instructions. AGENT-01 specifies "Brainstormer (Generalist with a Superpowers-style system prompt)". The system prompt gap means AGENT-02 behavior cannot activate even when LLM is connected.
ui/src/components/ChatSpecCard.tsx 91-137 placeholder attributes on textareas Info These are legitimate textarea placeholders ("What should be built?", etc.) — not stub patterns. Not a blocker.

Stub classification note: The streamEcho method is a pre-existing stub from Phase 22, documented in 23-01-SUMMARY.md under "Known Stubs". It does not block handoff or task creation (those are explicit POST routes). It blocks the LLM conversational experience and is expected to be replaced in a future LLM integration phase.


Human Verification Required

1. Brainstormer Greeting and Structured Questioning (Success Criterion 1 + AGENT-01/02)

Test: Open Nexus, click "New Conversation." Verify the general role agent is auto-selected. Send a message. Verify the agent responds with a structured greeting and begins asking clarifying questions. Expected: Agent introduces itself as Brainstormer, asks "What are you looking to build?" and proceeds with structured questions. Why human: streamEcho stub only echoes input back. Even with a real LLM, general/SOUL.md contains no Brainstormer persona — no structured questioning instructions exist. This requires either (a) confirming the streamEcho replacement is scoped to a future phase and AGENT-02 is intentionally deferred, or (b) identifying this as a gap requiring SOUL.md updates.

2. Spec Card Visual Rendering and Interaction (Success Criterion 2 + AGENT-02)

Test: Manually POST a message to a conversation with { role: "system", messageType: "spec_card", content: "{\"what\":\"Build a login page\",\"why\":\"Users need auth\",\"constraints\":\"Must use OAuth\",\"success\":\"Users can log in\"}" }. Then open that conversation in the UI. Expected: A formatted card renders with four labeled sections (What, Why, Constraints, Success), plus Send to PM, Edit, and Save as Draft buttons. Edit button opens textarea mode. Escape key discards edits. Save as Draft shows [Draft] badge. Why human: Requires running the UI. Cannot verify visual layout or interactive behavior via static analysis. Also confirms the messageType dispatch chain works end-to-end.

3. Full Handoff Flow (Success Criteria 3 + 4 + AGENT-03/05/06)

Test: In the UI, click "Send to PM" on a spec card. Verify: (a) handoff separator appears with "Brainstormer → PM: spec handed off", (b) task created badge appears with a real task identifier (e.g. NXS-42), (c) clicking "View task" navigates to the issue. Expected: Three new messages appear in chat: handoff indicator, task created badge with identifier and title, and the View task link navigates correctly. Why human: Requires live server with database. The link in taskUrl uses /issues/${issue.id} (UUID) — must verify the router resolves this path correctly.


Gaps Summary

No structural gaps found in Phase 23 implementation. All planned artifacts exist, are substantive (not stubs), and are wired. All key links verified.

Two items flagged for human verification represent behavior that requires a real LLM (Success Criteria 1 and 2), which is outside Phase 23's stated implementation scope per RESEARCH.md: "Phase 23 does not require a real LLM to function — the spec card, handoff, and task creation flows are all triggered by explicit API calls from the UI, not by the LLM output type changing."

One additional item requires human judgment on scope: whether the Brainstormer system prompt (AGENT-01: "Generalist with a Superpowers-style system prompt") is intentionally deferred to a future LLM integration phase, or represents a gap that should be addressed in Phase 23. The general/SOUL.md Generalist persona has no Brainstormer-specific behavior.

Assessment: Phase 23 successfully delivered the complete infrastructure for the Brainstormer flow — DB schema, server routes, UI components, API wiring, and integration plumbing. The success criteria items involving live LLM behavior are gated on the LLM integration (replacing streamEcho), which is correctly identified as a dependency outside Phase 23's scope.


Verified: 2026-04-01T22:15:00Z Verifier: Claude (gsd-verifier)