Repository navigation
Point the contributor at the next action in the post-init view - #256
Merged
juanmaguitar merged 1 commit intoAug 11, 2026
Conversation
juanmaguitar
force-pushed
the
juanmaguitar/next-action-post-init-panels
branch
from
August 11, 2026 08:03
5834b20 to
ec039ab
Compare
juanmaguitar
force-pushed
the
juanmaguitar/next-action-post-init-panels
branch
from
August 11, 2026 08:11
ec039ab to
d47927f
Compare
juanmaguitar
force-pushed
the
juanmaguitar/next-action-post-init-panels
branch
from
August 11, 2026 08:13
d47927f to
4ebe3f4
Compare
juanmaguitar
force-pushed
the
juanmaguitar/next-action-post-init-panels
branch
from
August 11, 2026 08:45
4ebe3f4 to
28293be
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
Extends PR #254’s next-action cue to post-initialization panels and adds screen-reader announcements.
Changes:
- Adds cue targets to six post-init actions.
- Adds a visually hidden live status region.
- Review found 2
[fix here]accessibility/testing issues.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/renderer/index.jsx |
Wires cue targets and live announcements. |
src/renderer/index.html |
Adds visually hidden utility styling. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+3539
to
+3540
| <div className="sr-only" role="status" aria-live="polite"> | ||
| {isActive && nextAction ? `Next step: ${nextAction.reason}` : ''} |
| holds text, so only the visible site speaks; it clears to nothing when | ||
| there is no next action. */} | ||
| <div className="sr-only" role="status" aria-live="polite"> | ||
| {isActive && nextAction ? `Next step: ${nextAction.reason}` : ''} |
juanmaguitar
force-pushed
the
juanmaguitar/next-action-post-init-panels
branch
from
August 11, 2026 09:10
28293be to
37ce9ac
Compare
PR #254 wired the setup checklist; the resolver already decided a next action for the post-init view too, but no block carried its id, so the cue did nothing once the wizard was skipped (#252). Add a `cueProps(id)` helper and spread it onto the post-init blocks — the update-incomplete and stale banners, the update tracker, the Start-dev and Review-changes buttons, and the Trac ticket panel — so the ring and scroll reach every panel the resolver can name. Add the accessibility equivalent flagged in #254's review: the "Start here" ring is a decorative CSS pseudo-element, so a visually-hidden polite live region now announces the next step as the cue moves, using the reason the resolver already returns. It is mounted unconditionally with only its text toggling — a live region that appears already holding text is not reliably read — and only the active row ever holds text, so only the visible site speaks. Closes #252. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
juanmaguitar
force-pushed
the
juanmaguitar/next-action-post-init-panels
branch
from
August 11, 2026 10:47
37ce9ac to
7942ef1
Compare
juanmaguitar
added a commit
that referenced
this pull request
Aug 11, 2026
## Why The initial setup checklist labelled the **current** step "In progress" the moment it became the next actionable step — before the contributor clicked anything and before any work was happening. On a fresh site, *Install npm dependencies* announced itself as "In progress" while nothing was installing (#257), which reads as "the app is already doing this" and invites a contributor to wait instead of clicking. The next-action ring (#252) made it worse by drawing the eye straight to the wrong word. ## What changes Root cause: the checklist's `current` status — "first ready, not-done step" — always mapped to the "In progress" label, conflating *next* with *running*. The running signal (`installing` / `building` / `starting`, and `isPending` for the clone) already existed for the buttons but the label ignored it. - New pure `setupStepLabel(status, isRunning)` in `src/renderer/setup-steps.cjs`: a current step reads **"Ready"** until its action is under way, and **"In progress"** only once it is. Other statuses keep their fixed words. - The render passes each step's own running flag (download↔`isPending`, install↔`installing`, build↔`building`, dev↔`starting`). - Removed the now-dead `label` keys from the `checklistVisuals` object so the status word has one source of truth (the object keeps only colours/indicator). ## How to test this **Platforms:** any (renderer-only). Stacked on #254 + #256 — test this branch's Buildkite artifact to exercise all three. **Starting state:** a freshly created site, on the **Initial setup checklist**, clone finished. 1. Look at the current step (*Install npm dependencies*) before clicking. → It reads **"Ready"**, not "In progress". 2. Click **Install npm dependencies**. → While it runs, the status reads **"In progress"**. 3. Let it finish. → Install reads **"Completed"**; **Run full build** becomes current and reads **"Ready"** (not "In progress"). Repeat for build → dev. 4. While the initial clone is still running (a brand-new site), the **Download** step reads **"In progress"** — because it genuinely is. **What must not have happened:** - No step reads "In progress" while its button is idle and clickable. - Completed / pending / locked steps are unchanged ("Completed" / "Pending" / "Locked"). - The next-action ring and scroll (from #254/#256) still behave exactly as before — only the status word changed. ## Risks and limitations - Renderer-only; no behavioural change beyond the status word. Not hand-verified by the author (no local app run — the repo's EBADENGINE install constraint); `eslint .` is clean and `npm test` passes (**794**, incl. 3 new for `setupStepLabel`). The Buildkite artifact is the hand-test path. ## Related Closes #257. Stacked on #256 (base branch `juanmaguitar/next-action-post-init-panels`), which is stacked on #254. Merge #254 → #256 → this. --- <details> <summary>Review outcome (required — see AGENTS.md)</summary> **No findings across the five dimensions** (0 [fix here] · 0 [follow-up]). Judgement pass ran in a fresh `Explore` subagent given only the diff and the review standard, per `/self-review`. Verified: only `complete`/`current`/`pending`/`locked` reach the switch, so `default` is exclusively `current`; each step's `running` flag matches the flag that drives its own button (and `isPending` for the clone, which is the only time download is `current`); no other reader of the removed `visuals.label` remains; the `running` spread never collides with `computeSetupStepState`'s keys; and the new tests fail on the old hard-coded "In progress" behaviour. Deterministic layer: `eslint .` clean; `npm test` **794 pass** (3 new). Both run in the worktree with node_modules symlinked. </details> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
juanmaguitar
added a commit
that referenced
this pull request
Aug 11, 2026
## Why The next-action cue (#252) points at the block a contributor should act on next. A block that is *doing* work — a trunk update, a patch apply or revert — is where attention belongs too: it should scroll into view and glow like any other cue target, so a contributor who looked away can see where the work is and that it isn't stuck. The trunk-update tracker was already highlighted; this completes the idea so **any block displaying work in progress** gets the same treatment. ## What changes - `next-action.cjs`: a new high-priority rule — when `isApplying` is true, point at the `applying-patch` block (the patch apply/revert step tracker). It sits above the stale-state warnings: a live operation outranks a warning. One flag covers both operations — a revert runs through the same apply machinery (`runApply({ reverse: true })`), so there is no separate "reverting" id. - Reordered the ladder so the two in-flight, tree-owning operations (`isApplying`, `isUpdating`) are checked before `updateIncomplete`, and dropped the now-redundant `!isUpdating` guard. Behaviour-preserving for the pre-existing cases. - `index.jsx`: passes `isApplying` to the resolver and spreads `cueProps('applying-patch')` onto the tracker (the block that only renders while the operation runs). After this, every in-progress block in the site view is a cue target: the trunk-update tracker (wired earlier in the stack) and the patch apply/revert tracker (here). Each glows and — with the assertive scroll from the base PR — is centered in view when it starts, and the cue clears when it ends. ## How to test this **Platforms:** any (renderer-only). Stacked on #254 + #256 + #258 — test this branch's Buildkite artifact to exercise the whole stack. **Starting state:** an initialized site, wizard skipped, with the *Apply a patch or PR* panel visible. 1. Apply a PR or a `.diff`/`.patch` file (paste a PR URL → **Apply PR** → **Apply and rebuild**). → While it runs, the **step tracker block glows** (soft amber) and the view scrolls to center it. 2. Let it finish. → The glow clears from the tracker (the block unmounts); the cue moves on to the next pending action. 3. With a patch applied, click **Revert this patch**. → The same tracker block glows while the revert runs. 4. Trigger **Update to latest trunk** (on a stale site). → Its progress tracker glows and scrolls into view the same way — confirming the treatment is general, not apply-only. **What must not have happened:** - The glow must not linger after an operation ends (the tracker unmounts when `isApplying` is false). - While applying/reverting, the cue must be on the tracker — not on start-dev / review-changes / link-ticket. - The screen-reader live region announces "Next step: A patch is being applied or reverted." ## Risks and limitations - `isApplying` and `isUpdating` own the working tree and never run at once (each disables the other's controls), so the ordering between them is not observable in practice; `isApplying` is placed first regardless. - Renderer-only. Not hand-verified by the author (no local app run — the EBADENGINE install constraint); `eslint .` clean, `npm test` **796** (2 new). Buildkite artifact is the hand-test path. ## Related Part of #252. Stacked on #258 (base branch `juanmaguitar/setup-step-ready-label`) → #256 → #254. Merge bottom-up. --- <details> <summary>Review outcome (required — see AGENTS.md)</summary> **No findings across the five dimensions** (0 [fix here] · 0 [follow-up]). Judgement pass ran in a fresh `Explore` subagent given only the diff and the review standard, per `/self-review`. Verified: `isApplying` is true for both apply and revert (`runApply` sets `applyState` unconditionally, revert calls `runApply({reverse:true})`); the ladder reorder is behaviour-preserving across all `updateIncomplete`/`isUpdating` combinations, and dropping the `!isUpdating` guard is safe now that `isUpdating` is checked first; the two tree-owning operations are mutually exclusive (both bail on the shared `running` flag), so `isApplying` winning is moot in practice and reasonable otherwise; and the `applying-patch` id and its DOM block appear/disappear together (`cueProps` in scope). **One change applied from the review** (a style note, not a finding): removed a second test that fed the resolver the same input as the first — the apply/revert distinction lives in `runApply`, not the resolver, so a resolver test can't prove it. Kept one test documenting the shared-flag behaviour. Deterministic layer: `eslint .` clean; `npm test` **796 pass** (2 new). _Note: reviewed as the apply/revert-specific change; the reframing to "any block showing work in progress" is a title/description change only — no code changed since review._ </details> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
juanmaguitar
added a commit
that referenced
this pull request
Aug 11, 2026
## Why
When a contributor pastes a PR or picks a `.diff`/`.patch` file, the app
shows a **staged preview** — "<label> changes N files" with **Apply and
rebuild** / **Cancel**. That block is a clear next action: they set it
up and the decision to apply is theirs. But it was not a cue target, so
nothing pointed at it. This highlights it like the other next-action
blocks.
## What changes
- `next-action.cjs`: a new rule — when `applyPreview` is staged, point
at the `apply-preview` block. Placed **after** the in-flight operations
(`isApplying`, `isUpdating`) and **before** the stale-state warnings and
routine steps: an explicit, waiting choice beats a standing suggestion,
but a live operation still wins. The ordering matters — the preview
block renders only under `applyPreview && !isApplying`, so once applying
starts the cue must move to the progress tracker; checking `isApplying`
first guarantees the id follows the visible block.
- `index.jsx`: passes `applyPreview` to the resolver and spreads
`cueProps('apply-preview')` onto the preview block.
## How to test this
**Platforms:** any (renderer-only). Stacked on #254 + #256 + #258 + #260
— test this branch's Buildkite artifact to exercise the whole stack.
**Starting state:** an initialized site, wizard skipped, *Apply a patch
or PR* panel visible.
1. Paste a PR URL (or number) and click **Apply PR** — or choose a
`.diff`/`.patch` file. → The **preview block** (with *Apply and rebuild*
/ *Cancel*) glows and the view scrolls to center it.
2. Click **Apply and rebuild**. → The preview unmounts and the glow
follows to the **progress tracker** (from #260).
3. Instead, click **Cancel**. → The preview clears and the cue moves on
to the next pending action.
**What must not have happened:**
- The glow must not stay on the preview once applying begins (the
preview block is gone by then).
- No glow on the preview when there is nothing staged.
- Screen reader announces "Next step: A patch is staged — apply and
rebuild, or cancel."
## Risks and limitations
- Renderer-only. Not hand-verified by the author (no local app run — the
EBADENGINE install constraint); `eslint .` clean, `npm test` **799** (3
new). Buildkite artifact is the hand-test path.
## Related
Part of #252. Stacked on #260 (base branch
`juanmaguitar/highlight-patch-progress`) → #258 → #256 → #254. Merge
bottom-up.
---
<details>
<summary>Review outcome (required — see AGENTS.md)</summary>
**No findings across the five dimensions** (0 [fix here] · 0
[follow-up]). Judgement pass ran in a fresh `Explore` subagent given
only the diff and the review standard, per `/self-review`.
Verified: the resolver checks `isApplying` before `apply-preview`, so
when applying starts the preview block unmounts and the cue follows to
the progress tracker in the same render (locked by a new test);
`Boolean(applyPreview)` is the right null-vs-object coercion, and the id
is returned only when the preview block is actually rendered (no
id-without-block window); `cueProps` in scope; full suite green. The
reviewer also confirmed a staged preview + in-flight trunk update can
coexist and `updating` correctly wins — placing `apply-preview` below
`isUpdating` is intentional, and the cue still lands on a rendered
block.
Deterministic layer: `eslint .` clean; `npm test` **799 pass** (3 new).
</details>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
PR #254 pointed the contributor at the next action in the setup checklist, but the resolver already decides a next action for the post-init view too — and nothing carried those ids onto the screen yet, so the cue silently did nothing once the wizard was skipped. This finishes #252: the same "start here" ring and scroll now reach every panel, and the cue gains a spoken equivalent for screen-reader users.
What changes
cueProps(id)helper spreadsdata-next-action+ the.next-action-cueclass onto: the update-incomplete banner (retry-install-build), the stale-trunk banner (update-trunk), the update-in-progress tracker (updating), the Start dev server and Review & submit changes buttons (each wrapped so the ring hugs the button), and the Trac ticket panel (link-ticket). No resolver change — it already returned these ids; this just gives them a home in the DOM.::before; this adds a visually-hiddenrole="status" aria-live="polite"region that announcesNext step: <reason>as the cue moves, using thereasonthe resolver already returns. Gated on the active row so only the visible site speaks, cleared to nothing when there's no next action..sr-onlyadded toindex.html.Not in this PR: no new resolver logic or ids — the ladder and its tests shipped in PR #254. The changes here are JSX markup plus one trivial props helper, so no new
*.cjsdecision module was introduced (consistent with the §1 invariant: the only decision,deriveNextAction, is already a tested module).How to test this
Platforms: any (renderer-only). Stacked on PR #254 — test this branch's Buildkite artifact and you exercise both PRs at once.
Starting state: an initialized site with the wizard skipped (the main dev view, not the checklist).
src/so the tree is dirty. → The cue moves to Review & submit changes.What must not have happened:
<span>wrappers areinline-flex; they must not collapse or misalign the buttons).link-ticketonly activates when unlinked, even though the shared wrapper carries thedata-next-action.Risks and limitations
inline-flexspan so the ring can hug them. This is the one layout-affecting change; visually confirm the row is unchanged when no cue is active.node_modulescouldn't be installed here (the repo's EBADENGINE constraint), so no localeslint/full suite/app run. The resolver test passes directly and the renderer transpiles clean; the Buildkite artifact is the path to drive the steps above.Related
Closes #252. Stacked on #254 (base branch
juanmaguitar/nothing-points-the-contributor-at-the-next-thing) — merge #254 first.Design decisions and alternatives considered
cuePropsspread over per-block className expressions. One helper keeps the tag and the class in lockstep and reads the same at every call site.reasongives the "what's next" signal without threading a visually-hidden node into six panels, and it naturally follows the cue as it moves.data-next-action="link-ticket"sits on the wrapper used for both linked and unlinked states; harmless because the.next-action-cueclass only activates when the resolver returnslink-ticket, which it only does when no ticket is linked.Review outcome (required — see AGENTS.md)
No findings across the five dimensions (0 [fix here] · 0 [follow-up]). The judgement pass ran in a fresh
Exploresubagent given only the diff and the review standard, per/self-review.Verified:
cuePropsand the live region add no new decision toindex.jsx(the only decision,deriveNextAction, is already a tested module — matches the §1 invariant); the six cue ids match the resolver's returned ids exactly; span-wrapping the two action-bar buttons leaves the rendered layout unchanged (eachinline-flexspan becomes the stretched flex child, the button fills it);data-next-action="link-ticket"on the shared ticket panel is inert when a ticket is linked (the class only activates when the resolver returnslink-ticket).One improvement applied from the review (a non-dimension robustness note, not a finding): the live region is now mounted unconditionally with only its text toggling, rather than the element being conditionally rendered — a
role="status"region that appears already holding text isn't reliably announced, whereas a text change to one already in the DOM is.Deterministic layer:
npm run lintand fullnpm testcould not run (nonode_modules— EBADENGINE); the resolver test passes directly (11/11) and the renderer transpiles clean via esbuild.