Skip to content

Fix #1606: revive Stream Deck Review dials for BUGFIX/AIR phases + honest none-mode label - #1607

Merged
amrmelsayed merged 12 commits into
mainfrom
builder/bugfix-1606
Sep 4, 2026
Merged

Fix #1606: revive Stream Deck Review dials for BUGFIX/AIR phases + honest none-mode label#1607
amrmelsayed merged 12 commits into
mainfrom
builder/bugfix-1606

Conversation

@amrmelsayed

@amrmelsayedamrmelsayed commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

The Stream Deck Review dials (Files/Headings, Changes/Blocks) silently no-op for an AIR builder during the pr phase and for a BUGFIX builder in the pr phase (until the pr gate is requested), then come alive only when blocked at the gate — read in live use as "the diff dials sometimes work and sometimes not". This revives them for the pr phase and makes the inert (none) state tell the truth on the strip instead of borrowing the diff label.

Fixes#1606

Root Cause

phaseArtifactVerb (apps/streamdeck/src/actions.ts) resolves dial mode from a vocabulary hardcoded to SPIR/PIR (phases specify|plan|implement|review|verify, gates spec-approval|plan-approval|dev-approval|pr|verify-approval). It matches on the exact phase-id string, so a phase whose diff-producing work is named differently falls through:

  • BUGFIX (investigate/fix/pr) and AIR (implement/pr): the prphase id is unrecognized, so reviewMode resolves to none between entering the phase and the pr gate firing (blockedGate === 'pr' was already handled).

In none mode every ReviewNav gesture no-ops. Compounding it, ReviewNav.renderTo had only canvas/diff label branches, so none rendered the diff label (Files · send) while every gesture was inert — a gesture that lied about what it does.

Fix

  1. Review dials recognize the pr phase.reviewMode now maps the prphase to diff mode via a registered DIFF_REVIEW_PHASES set, applied after the existing verb-based canvas/diff resolution so gates still win. By the pr phase the work exists as a finished diff (owner ruling 2026-09-04).
  2. Work-in-progress phases stay inert, honestly. BUGFIX investigate/fix are deliberately not diffable (owner ruling 2026-09-04): their diff is partial or not yet written, so they are not a review target. They stay none — but ReviewNav.renderTo now renders No review target in none mode instead of borrowing the diff label. init/no-status builders are none too, with the same honest label.

Scope (owner ruling 2026-09-04)

Only the pr phase is revived; investigate/fix are work-in-progress and stay inert. The value of the fix there is the honest label — the dials no longer claim Files · send while doing nothing. The broader question of MAINTAIN/EXPERIMENT/SPIKE phases (which also produce diffs and still resolve to none) is tracked in follow-up #1609, not this PR.

Trade-off note (metadata vs. registered list)

The issue preferred deriving mode from protocol.json phase metadata over a hardcoded name list. That path is not currently expressible: protocol.json phases carry only id/name/type/steps/transition/gate — no field encodes review mode — and the SDK's PHASE_TO_STAGE drives the VSCode Builders tree with different semantics, so it can't be repurposed. Per the issue's documented fallback, I registered the pr phase in reviewMode with a GATE_LABELS-style registration note. phaseArtifactVerb is deliberately left untouched, so the Builder Action key (open-terminal) and the Zoom dial (view-diff) keep their behavior; a guard test documents that split.

Shipping

apps/streamdeck change → needs a plugin version bump + Elgato Marketplace resubmission (~4–10 working days). Per the architect the release is held: this merges to main with no version bump and ships later in a batched resubmission. Hardware verification runs on the architect's side via streamdeck link.

Test Plan

  • Regression tests — reviewMode: pr phase → diff; investigate/fix → none (WIP); init/no-status → none. A behavioral test (a BUGFIX pr-phase builder's dials emit diff verbs) and its inverse (an investigate builder's dials stay inert). A legibility test (none-mode strip says No review target, not Files · send). A phaseArtifactVerb guard for the deliberate split. Verified the behavioral/mode/label tests fail without the source fix and pass with it.
  • Build passes (npm run build, esbuild + tsc --noEmit clean)
  • All tests pass (vitest run — 248 passed)

…t none-mode label
The Stream Deck Review dials (Files/Headings, Changes/Blocks) silently no-op for
a BUGFIX builder's whole working life (investigate, fix) and for AIR during the
pr phase, because phaseArtifactVerb's hardcoded SPIR/PIR phase vocabulary left
those ids unrecognized -> reviewMode resolved to 'none' and every dial gesture
no-opped. Compounding it, the none-mode strip rendered the diff label
(Files · send) while inert -- a gesture that lied about what it did.
- reviewMode: recognize investigate/fix/pr as diff mode via a registered
DIFF_REVIEW_PHASES set with a GATE_LABELS-style registration note (protocol.json
phase metadata carries no review-mode field; the SDK's PHASE_TO_STAGE folds
investigate->plan, wrong here, and drives the VSCode tree). phaseArtifactVerb is
left untouched so the Builder Action key (open-terminal) and Zoom (view-diff)
keep their behavior; only the review dials gain the extra vocabulary.
- ReviewNav.renderTo: none mode now renders "No review target" instead of
borrowing the diff label.
- Tests: reviewMode coverage for the BUGFIX/AIR phase ids and init/no-status; a
phaseArtifactVerb guard documenting the deliberate split; a behavioral test
(investigate dials drive the diff) and a legibility test (honest none label).
…revived dial vocabulary
Addresses CMAP (claude) review comments on PR #1607:
- README.md: the Review-dial bullets described the diff vocabulary as
"implement / review, or blocked at dev-approval / pr" and never mentioned the
inert state. Updated to include the BUGFIX/AIR investigate/fix/pr phases and the
honest "No review target" strip, so the doc that ships to the Marketplace matches
the fixed behavior.
- DIFF_REVIEW_PHASES note: `investigate` is registered by name, not owned by BUGFIX
(RESEARCH uses it too, and its worktree changes review as a diff). Corrected the
comment's attribution.
No behavior change. MAINTAIN/EXPERIMENT/SPIKE phases still resolving to none is left
for an architect scope decision (out of #1606's investigate/fix/pr scope); the honest
label already stops them from lying.
… ruling)
Owner ruling 2026-09-04: only the `pr` phase should drive the review dials to diff
mode. BUGFIX `investigate`/`fix` are work-in-progress (partial or unwritten diff),
so they are not a review target and stay `none` — inert, but now with the honest
`No review target` label instead of the old `Files · send` lie.
- DIFF_REVIEW_PHASES = {pr}; investigate/fix removed and documented as deliberately
excluded so they are not re-added without an owner ruling.
- Tests: pr phase -> diff (behavioral + unit); investigate/fix -> none (behavioral +
unit); guard and none-label tests updated. 248 pass; tsc + build clean.
- README + PR body updated to pr-only scope.
@amrmelsayed
amrmelsayed merged commit c0e4d67 into mainSep 4, 2026
7 checks passed
@amrmelsayed
amrmelsayed deleted the builder/bugfix-1606 branch September 4, 2026 09:54
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

streamdeck: Review dials silently dead for BUGFIX (investigate/fix) and AIR (pr phase) — phase vocabulary hardcoded to SPIR/PIR

1 participant

@amrmelsayed