You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Close the remaining gaps between the shipped flat work card and the locked merge design, so a live card actually reads like the approved mockup.
Why
flatChatList is on locally and the card renders — but in real use it collapses to mark · project · time / title · WORKING / $1.8884. The middle of the card (the part that says what the agent is doing) is empty, and two locked visual rules never landed. This is not staleness: verified against main at 9b852be with a build from the same tree.
Reference: ~/Projects/Boards/pickforge/sidebar-work-card-merge.html (approved 2026-07-24, same board as #306).
Gaps
1. Task brief never renders in production (primary)
The renderer exists — ProjectsPane.tsx:1540<Show when={brief()}> fed by cardBrief (src/stores/flatWorkCard.ts:116-119, reads chat.taskBriefText) — but taskBriefText has no writer outside fixtures. src/stores/workspace.ts:361 always creates chats with taskBriefText: null; the only non-null values are VRT mocks (src/lib/tauriMock.ts:424-425). The comment at flatWorkCard.ts:113-115 already admits it ("always null today").
Decided (2026-07-25): active plan step, falling back to a model-written one-liner.
Primary — active plan step. Needs no new plumbing: PlanItemStatus already carries inProgress (src/lib/agentChat.ts:29), and latestPlanForChat (src/stores/agentChat.ts:238) is the same accessor cardPlanProgress (flatWorkCard.ts:155-163) already reads for plan M/N. The brief is the inProgress item's text. This also keeps the brief honest against the footer — the card says step 2 of 5 and what step 2 is, from one source.
Fallback — model-written one-liner, only when there is no plan (no plan timeline item) or no inProgress item. Shares plumbing with Dynamic semantic chat titles that follow the active task #210 (dynamic semantic chat titles); build it there or extract a shared producer, do not write a second one.
Neither available → no brief line at all. No placeholder, per the locked footer principle.
Sub-decisions for PR 2:
Truncation: the line is already single-line-ellipsis in CSS (workbench.css:3427-3437); decide whether to also cap in the store to keep persisted values small.
Which wins if a plan exists and a model one-liner is cached — plan step, per the ordering above; make it explicit in the resolver so it does not drift.
All-complete plan (M === N, no inProgress item): falls through to the one-liner, then to nothing. Confirm that reads right on a just-finished card before it collapses.
2. NEEDS YOU label has no bracket glyphs
Locked rule (#306): "bracketed text only on the NEEDS YOU label". Code only recolors it — .pf-work-card-status--needsyou { color: var(--pf-warning) } (workbench.css:3423-3425), JSX at ProjectsPane.tsx:1536-1538. The four card corners are implemented (WorkCardCorners, ProjectsPane.tsx:1400-1407), the label brackets are not. The VRT at tests/vrt/flat-chat-list.spec.ts:178-182 asserts the class name, so it passes while the glyphs are absent — the test needs tightening as part of the fix. The composer chips already use the bracket idiom, so there is a house treatment to match.
3. Cost is 4-decimal in the card footer
formatCost (src/components/chat/ContextMeter.tsx:16-18) returns $1.8884; the board shows $0.41. Fine for the composer readout, too noisy at card scale. Wants a card-scale format (2 decimals, or sub-cent → <$0.01) without changing the composer.
4. Branch chip is not visually distinct
.pf-work-card-branch (workbench.css:3452-3459) sets truncation only and inherits --pf-text-low; the board renders the branch in an accent tone so it reads as an identifier next to plan M/N. Token-level change, no new chrome — see the readouts-need-an-edge principle.
Non-gaps (verified, do not "fix")
Branch + plan M/N slots exist and work (WorkCardFooter, ProjectsPane.tsx:1414-1458); they are absent on the screenshotted chat because it has no worktree branch and no plan. Conditional-on-real-data is the locked footer rule.
The ▮▮▮ 1/3 glyph is swarm lane ticks, not a context bar; correctly absent on non-swarm chats.
2px context edge, state tint, needs-you-above-working sort, QUIET · N — all implemented and matching.
Two-line quiet rows are a recorded owner deviation (ProjectsPane.tsx:1309-1316), not a regression.
Flag
Rides the existing flatChatList flag (default off, src/stores/flags.ts:57). No new flag. The enable-in-release / remove-flag lifecycle stays tracked on #306 — this issue must land before that flag is enabled, since it is what the enabled state will look like.
PR plan
PR 1 — visual gaps: NEEDS YOU label brackets, card-scale cost format, branch chip tone
Depends on: none
Touches: ProjectsPane.tsx, workbench.css, a card-scale cost helper, tests/vrt/flat-chat-list.spec.ts
Validation: bun run test:unit; VRT flat-chat-list (tighten the bracket assertion to the glyphs, not the class)
Link: pending
PR 2 — brief from the active plan step
Depends on: none (source decided; uses existing plan plumbing)
Touches: flatWorkCard.ts (cardBrief resolves from latestPlanForChat instead of taskBriefText), ProjectsPane.tsx wiring, tauriMock.ts fixtures
Validation: unit tests — inProgress step wins; no plan → no brief; all-complete plan → no brief; VRT calm/normal/heavy with a real brief
Goal
Close the remaining gaps between the shipped flat work card and the locked merge design, so a live card actually reads like the approved mockup.
Why
flatChatListis on locally and the card renders — but in real use it collapses tomark · project · time/title · WORKING/$1.8884. The middle of the card (the part that says what the agent is doing) is empty, and two locked visual rules never landed. This is not staleness: verified againstmainat 9b852be with a build from the same tree.Reference:
~/Projects/Boards/pickforge/sidebar-work-card-merge.html(approved 2026-07-24, same board as #306).Gaps
1. Task brief never renders in production (primary)
The renderer exists —
ProjectsPane.tsx:1540<Show when={brief()}>fed bycardBrief(src/stores/flatWorkCard.ts:116-119, readschat.taskBriefText) — buttaskBriefTexthas no writer outside fixtures.src/stores/workspace.ts:361always creates chats withtaskBriefText: null; the only non-null values are VRT mocks (src/lib/tauriMock.ts:424-425). The comment atflatWorkCard.ts:113-115already admits it ("always null today").Decided (2026-07-25): active plan step, falling back to a model-written one-liner.
PlanItemStatusalready carriesinProgress(src/lib/agentChat.ts:29), andlatestPlanForChat(src/stores/agentChat.ts:238) is the same accessorcardPlanProgress(flatWorkCard.ts:155-163) already reads forplan M/N. The brief is theinProgressitem's text. This also keeps the brief honest against the footer — the card says step 2 of 5 and what step 2 is, from one source.plantimeline item) or noinProgressitem. Shares plumbing with Dynamic semantic chat titles that follow the active task #210 (dynamic semantic chat titles); build it there or extract a shared producer, do not write a second one.Sub-decisions for PR 2:
workbench.css:3427-3437); decide whether to also cap in the store to keep persisted values small.inProgressitem): falls through to the one-liner, then to nothing. Confirm that reads right on a just-finished card before it collapses.2. NEEDS YOU label has no bracket glyphs
Locked rule (#306): "bracketed text only on the NEEDS YOU label". Code only recolors it —
.pf-work-card-status--needsyou { color: var(--pf-warning) }(workbench.css:3423-3425), JSX atProjectsPane.tsx:1536-1538. The four card corners are implemented (WorkCardCorners,ProjectsPane.tsx:1400-1407), the label brackets are not. The VRT attests/vrt/flat-chat-list.spec.ts:178-182asserts the class name, so it passes while the glyphs are absent — the test needs tightening as part of the fix. The composer chips already use the bracket idiom, so there is a house treatment to match.3. Cost is 4-decimal in the card footer
formatCost(src/components/chat/ContextMeter.tsx:16-18) returns$1.8884; the board shows$0.41. Fine for the composer readout, too noisy at card scale. Wants a card-scale format (2 decimals, or sub-cent →<$0.01) without changing the composer.4. Branch chip is not visually distinct
.pf-work-card-branch(workbench.css:3452-3459) sets truncation only and inherits--pf-text-low; the board renders the branch in an accent tone so it reads as an identifier next toplan M/N. Token-level change, no new chrome — see the readouts-need-an-edge principle.Non-gaps (verified, do not "fix")
plan M/Nslots exist and work (WorkCardFooter,ProjectsPane.tsx:1414-1458); they are absent on the screenshotted chat because it has no worktree branch and no plan. Conditional-on-real-data is the locked footer rule.▮▮▮ 1/3glyph is swarm lane ticks, not a context bar; correctly absent on non-swarm chats.QUIET · N— all implemented and matching.ProjectsPane.tsx:1309-1316), not a regression.Flag
Rides the existing
flatChatListflag (default off,src/stores/flags.ts:57). No new flag. The enable-in-release / remove-flag lifecycle stays tracked on #306 — this issue must land before that flag is enabled, since it is what the enabled state will look like.PR plan
ProjectsPane.tsx,workbench.css, a card-scale cost helper,tests/vrt/flat-chat-list.spec.tsbun run test:unit; VRT flat-chat-list (tighten the bracket assertion to the glyphs, not the class)flatWorkCard.ts(cardBriefresolves fromlatestPlanForChatinstead oftaskBriefText),ProjectsPane.tsxwiring,tauriMock.tsfixturesinProgressstep wins; no plan → no brief; all-complete plan → no brief; VRT calm/normal/heavy with a real briefcardBriefresolver orderTraceability
plan M/Nplan M/Nnever disagree — both read one sourceOpen decisions
None blocking. All three PRs can start; PR 3 should be sequenced with #210 so the one-liner producer is written once.
Refs #306, #210