Stream Deck SD+: two-zone builder workflow (selectors + action palette, dial-driven feedback queue) - #1439
Conversation
…dial feedback verbs, mode label
…odel + activity-hook prerequisite
… Terminal; drop fleet jump/count
…+ number + Terminal band)
# Conflicts: # apps/streamdeck/src/__tests__/face.test.ts # apps/streamdeck/src/actions.ts # apps/streamdeck/src/face.ts
…ces via labelFaceSvg
…like Dev Server
…ge (badge + label freshness) + rebuttal
|
Integration review (streamdeck architect) — APPROVE. High-risk tier (deck + vscode relay/feedback router + overview wire + types; 1770 additions): reviewed continuously through the lane's four plan iterations (all owner-decided: req-6 single approve, Row 1 windowing, E2=b canvas back-sync, Row 2 key-4 swap), hardware dev-approval passed, 3-way consult run. Independently source-verified per standing practice: (1) both binding constraints hold — |
PIR Review: Stream Deck SD+ two-zone builder workflow (selectors + action palette, dial-driven feedback queue)
Fixes #1410
Summary
Turns the SD+ into a two-zone remote bound by one shared selection: Row 1 is a 4-wide window of fleet-selector keys (scrolled by the Select dial, so a fleet larger than four is reachable), and Row 2 is a fixed, uniformly per-builder action palette — Approve · Dev · Send Fb (N) · Open Terminal — always acting on the selected builder. The diff dials move from immediate
forward-*to a mode-neutralfeedback-*verb that VSCode routes forward-now or into the per-builder review queue per thecodev.diffCodelensModesetting, with a newsend-queueflush and a per-builder queued-count badge; the overview wire gains aqueuedFeedbackmap + afeedbackModescalar, and focusing a builder's spec/plan/review canvas now back-syncs the deck selection the same way focusing its diff already did.Files Changed
packages/types/src/api.ts(+20 / -0) —OverviewData.queuedFeedbackmap +feedbackModepackages/codev/src/agent-farm/servers/overview.ts(+70 / -4) — populate both (read queue files +.vscode/settings.json)packages/codev/src/agent-farm/servers/tower-routes.ts(+1 / -1) — no-workspace fallback defaultspackages/codev/src/agent-farm/__tests__/overview.test.ts(+62 / -0) —countQueuedFeedback/readFeedbackModeapps/vscode/src/command-relay.ts(+8 / -0) — allowlistfeedback-*+send-queueapps/vscode/src/review-queue/feedback.ts(+127 / -0, new) — mode-router (forward now vs enqueue viaReviewQueueStore)apps/vscode/src/extension.ts(+15 / -1) — register the 3 feedback commands;submitReviewaccepts a builder idapps/vscode/src/markdown-preview/preview-provider.ts(+33 / -0) — canvas focus back-syncapps/vscode/src/markdown-preview/canvas-owner.ts(+27 / -0, new) — pure canvas→builder resolverapps/vscode/src/__tests__/feedback.test.ts(+118, new),command-relay.test.ts(+16),canvas-back-sync.test.ts(+35, new)apps/streamdeck/src/store.ts(+40 / -4) —feedbackMode/queuedFeedback/windowedBuilderreadersapps/streamdeck/src/face.ts(+45 / -12) — selected accent,approveFaceSvg/sendFbFaceSvg,comment/terminalglyphsapps/streamdeck/src/actions.ts(+110 / -30) — Row 1 windowing, dialfeedback-*, touchstrip mode label, Row 2 paletteapps/streamdeck/src/plugin.ts(+4) — registerSendQueueAction,OpenTerminalActionapps/streamdeck/com.cluesmith.codev.sdPlugin/manifest.json(+22 / -10) —send-queue+open-terminalactionsapps/streamdeck/src/__tests__/actions.test.ts(+140),face.test.ts(+30) — deck coverageapps/streamdeck/README.md(+80 / -35) — two-zone layout, feedback verbs, coherence model, activity-hook prerequisite(Diff-stat anchored at the merge-base; excludes the
origin/mainmerge that brought in bugfix-1437's Dev Server face + silent-successack, which this branch builds on.)Commits
729f359a6Open Terminal: plain label face (no builder id), VerbKey like Dev Server417f6bb8fRow 2 key 4: replace Next/Attention with per-builder Open Terminal; drop fleet jump/countbc2dffde9Tests: feedback router, relay verbs, canvas owner, overview wire0a1d403d2Docs: two-zone layout, mode-neutral feedback, coherence model + activity-hook prerequisite53c144473Deck: Row 1 window, Row 2 palette, dial feedback verbs, mode labele27db8252VSCode: mode-neutral feedback verbs, send-queue flush, canvas back-synca1f8910f3Overview wire: per-builder queuedFeedback map + feedbackMode2901a0828E2=(b): symmetric canvas focus back-syncmainmerge; full list viagit log main..HEAD)Test Results
pnpm build(full workspace): ✓ passpnpm --filter @cluesmith/codev-streamdeck test: ✓ 125 passpnpm --filter codev-vscode test:unit: ✓ 822 passpnpm --filter @cluesmith/codev test(codev): ✓ 4856 pass / 48 skippedstreamdeck validate: ✓Files · send/Files · queuelabel, Row 2 Approve/Dev/Open-Terminal on the selected builder, and the diff/canvas focus back-sync were exercised on real hardware.Architecture Updates
COLD (
codev/resources/arch.md, Integration Points): added a concise note recording the Stream-Deck↔VSCode shared-selection coherence invariant — the deck's selected builder and VSCode's focused artifact are kept equal by thebuilder-activeactivity hook (which this PR extends to fire for a focused canvas, not only a diff), and deck-driven review feedback mutates the queue only throughReviewQueueStore; the overview carries a per-builderqueuedFeedbackmap + afeedbackModescalar.HOT: no
arch-critical.mdchange — this is a deck+vscode feature within existing module boundaries and the existing "outside-in controller" fact already frames it; it doesn't rise to an always-injected system-shape fact.Lessons Learned Updates
COLD (
codev/resources/lessons-learned.md, Testing): sharpened the existing #1414 dual-artifact lesson with why the deck bundle can be silently absent on a fresh worktree — the rootpnpm buildintentionally builds only the published@cluesmith/codevpackage + its deps, notapps/streamdeck/apps/vscode(CI builds those in separate jobs), so a relinked plugin with nobin/plugin.jsrenders nothing untilpnpm --filter @cluesmith/codev-streamdeck buildis run.HOT: no
lessons-critical.mdchange — the gotcha is a sharpening of an existing cold lesson, not a new always-on rule.Things to Look At During PR Review
selectedBuilder(); the review dials act on the focused artifact;feedback-*writes attach to the focused diff's owner (correct — a comment must attach to the file in view) while Send Fb flushesselectedBuilder(). These agree because focusing a diff/canvas firesbuilder-active→syncToBuilder. The one transient divergence (rotate the Select dial without opening) self-heals on the next Row 1 press / focus. See the plan's "Layer integration" section.feedbackModesourcing. Tower reads<root>/.vscode/settings.json(JSONC-tolerant, defaults toforward). This is single-folder-workspace only; a multi-root.code-workspaceor user-level override isn't at that path and reads as the default — an accepted limitation (the deck falls back tosend, never a wrong-way write, since the mode only labels the dial).send-queue→codev.submitReviewid forwarding. The status-bar button still calls it arg-less (resolves target itself); the deck passes[selectedId]. Confirm thetypeof builderId === 'string'guard.Codev.streamDeckProfilehas always shippedActions: null(as Stream Deck: merge Fleet Slot into Builder Action (phase-aware press) #1404's Row 1 did); the two-zone layout is documented in the README and placed at the hardware session. No known-goodsdProfileActions schema exists in history to safely pre-populate.builder-activeactivity hook in~/.codev/config.json(documented in the README). Without it, only deck-driven selection moves the cursor.How to Test Locally
For reviewers pulling the branch (note: the deck plugin + VSCode extension are separate builds from the root
pnpm build):pnpm --filter @cluesmith/codev-streamdeck build(plugin bundle),pnpm --filter codev-vscode vsix(extension),pnpm -w run local-install(CLI/Tower, for the badge/label wire).pir-1410→ Review Diff.afx dev pir-1410.commentmode and injects inforwardmode, with the touchstrip naming the mode; Send Fb flushes; Row 2 Approve/Dev/Open-Terminal act on the selected builder; focusing a diff or a spec/plan canvas in VSCode moves the deck selection to it.Flaky Tests
None.