Skip to content

Commit f7b61cb

Browse files
committed
Keep scenario stepping and pause usable from the keyboard
1 parent 5392fc0 commit f7b61cb

10 files changed

Lines changed: 175 additions & 35 deletions

File tree

‎DESIGN.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ keyboard recovery control.
8686
Environment stays readable without a workspace snapshot; unknown repository
8787
counts stay absent until data arrives.
8888

89+
Manual scenario steps keep keyboard focus on the same enabled control; completion
90+
or a failed step returns entry to main. Pausing remains available during an
91+
in-flight step and stops future scheduling, while the current transaction can
92+
finish. A changing Play/Pause/New run action label uses an ordinary button,
93+
without a contradictory toggle pressed state. Respect another chosen control.
94+
8995
## Motion
9096

9197
No authored animation or transition in the workspace, including modal scale/fade, progress interpolation, hover motion and smooth route scrolling. Update status immediately without recreating the page. Native dialog handles focus and Escape; returning focus must not move the document. Game canvas motion belongs to gameplay and remains independent of workspace chrome.

‎docs/CONTEXT.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ and external AI CLIs require a direct user request. Never merge old work implici
8282
- Existing Commons run 49092854-f9bd-4b7a-8d12-4ac5ea0e5f70 retains the approved,
8383
unmerged safe-timer change from job 811bdb98-bcbb-4b65-80b9-f19693aef6b4.
8484
Preserve it. 29 earlier lab experiments were verified before this release work.
85-
- Public source: antropos17/commit-zero at e788d0e; all three CI jobs and fresh evidence preflight passed. Preserve separate histories.
85+
- Public source: antropos17/commit-zero at 5392fc0; all three CI jobs passed with local dfa9ecb's identical tree. Preserve separate histories.
8686
README GIF is a 15.8s condensed walkthrough of retained Sequence Kit work,
8787
not a continuous live recording. Static fallback included; desktop/mobile and all
8888
three CI jobs passed. Evidence: runtime/verification/github-readme-gif-2026-10-19.json.

‎docs/ECOSYSTEM-DECISIONS.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,19 @@ No substitute model is inferred from a familiar display name.
4747

4848
## Other adopted decisions and their evidence
4949

50+
The [W3C button pattern](https://www.w3.org/WAI/ARIA/apg/patterns/button/)
51+
(accessed 2026-10-19) distinguishes a stable-label toggle from an action button
52+
with changing labels, and describes focus staying on actions in the same
53+
context. Actual Chrome fixtures showed focus loss after Next step and an
54+
unavailable Pause during an in-flight transaction. Decision: retain native
55+
action buttons, restore manual-operation entry after the DOM commit, and keep
56+
Pause available until future scheduling stops. The existing small
57+
[React layout effect](https://react.dev/reference/react/useLayoutEffect)
58+
runs after committed updates; it performs no state update, network call or
59+
layout loop. Expected benefit: keyboard users can complete and pause the
60+
deterministic cycle. Browser fixtures check terminal/new-run history, failure
61+
without automatic write retry, and pause with/without another focus choice.
62+
5063
| Question | Decision and verification |
5164
| --- | --- |
5265
| Hosted request/response patterns | Four disconnected text contracts share host context and evidence validation. [Primary sources, offline fixtures and activation gaps](PROVIDER-DRAFTS.md). |

‎docs/FIRST-RUN.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ It uses isolated fixture actors and does not modify a saved user run.
2424
The [PR diff capture](media/scenario-pr-2026-10-19.png) is an actual Chrome
2525
capture after completing the deterministic ten-step example in disposable
2626
services. Conversation, checks and changed files remain inspectable after merge.
27+
Use **Next step** with Enter or Space to continue from the same control. At the
28+
last step, focus returns to content. **New run** preserves the completed run's
29+
export. **Pause cycle** stops future scheduled steps; a step already sent to the
30+
service can finish. A failed step never advances the view optimistically, and
31+
**Retry** refreshes the saved state without repeating the write.
2732
At narrow widths, focus the code region and use arrow keys or swipe sideways to
2833
read complete lines. Scenario checks are predefined results, not executed code.
2934

‎docs/HANDOFF-2026-10-19.md‎

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@ tracks dated decisions and receipts; this file is the operational entry point.
88
## Repositories and state
99

1010
- Working repository: `X:\ai-github`, branch `codex/development-foundation`,
11-
latest fully checked local commit `e61e129` at this checkpoint. The local data and model
11+
latest fully checked local commit `dfa9ecb` at this checkpoint. The local data and model
1212
installation are here. Recheck status before acting; this file can age.
1313
- Public repository: [antropos17/commit-zero](https://github.com/antropos17/commit-zero),
14-
`main` at `e788d0e2f522585cd4777047160509dbbe4982f3` after a normal push.
14+
`main` at `5392fc00b2ac2f8faedc507acc63311705a93dcc` after a normal push.
1515
Its separate checkout is `.cache/publication`. The histories are unrelated;
16-
the public tree matches local `e61e129` (`91e7019472b547a688a36e4822fe6b7677786352`).
17-
Service-health recovery/manual-refresh focus changes are awaiting final gates.
16+
the public tree matches local `dfa9ecb` (`ceec86201675ecda32f8c844123f5994c1b8ac28`).
17+
Keyboard scenario-control changes are awaiting final gates.
1818
Do not merge histories, reset the local branch or force push. Recheck remote
1919
before publishing anything else.
20-
- Public CI [run 39228142114](https://github.com/antropos17/commit-zero/actions/runs/39228142114)
21-
passed full gate, Chromium and runtime dependency audit for `e788d0e`. Fresh
22-
`evidence:status -- --github` confirmed exact main/CI and both local receipts. The
20+
- Public CI [run 39233009471](https://github.com/antropos17/commit-zero/actions/runs/39233009471)
21+
passed full gate, Chromium and runtime dependency audit for `5392fc0`. Local
22+
`evidence:status` confirmed equal trees and current full/browser receipts. The
2323
preceding retry-fixture failure at `5f9f88e` is preserved in the mission log.
2424
- This mission has not run local or hosted model inference, spawned product
2525
agents, submitted promotional posts or created a new release. Prior retained
@@ -116,22 +116,25 @@ source-evidence unit passed at `e61e129`. Its preflight compares both full recei
116116
on the same frozen source. `npm run evidence:status -- --github` is the live operational check;
117117
hardcoded revisions here describe the last checkpoint at documentation time.
118118

119-
The pending health unit adds a named busy region, settled failure and explicit
119+
The health unit adds a named busy region, settled failure and explicit
120120
last-available data. Environment remains accessible without a workspace snapshot;
121121
unknown repository counts are omitted. Manual workspace/health recovery restores
122122
its control or content entry after React updates, while respecting another focus
123123
choice or route. Four focused Chrome tests and UI DOM/axe/build/serving passed.
124124
The scenario assertion follows the actual returned step and forbids reset/advance
125125
requests. [Desktop error](media/service-health-unavailable-2026-10-19.png) and
126126
[narrow dark retained state](media/service-health-last-known-2026-10-19.png)
127-
are real disposable-service captures. Full source/browser gates remain.
127+
are real disposable-service captures. Full 81/81 and Chrome 18/18 passed on the
128+
same frozen source before commit/publication. The next keyboard unit preserves
129+
manual step focus and keeps Pause usable during the current transaction; its
130+
four focused Chrome tests passed, with full gates pending.
128131

129-
- Latest local frozen full gate at `e61e129`: 81/81 Node tests, compiled DOM/axe
132+
- Latest local frozen full gate at `dfa9ecb`: 81/81 Node tests, compiled DOM/axe
130133
2/2, build and static serving passed. Stable source hash
131-
`d3ab286ac18b39386976ac5278b923aebc2e4e066c7e509a26208793c3cce5e5`;
132-
receipts `runtime/verification/evidence-preflight-{full,browser}-2026-10-19.json`
133-
and `evidence-status-hosted-2026-10-19.json` (ignored by Git).
134-
- Installed Chrome browser suite passed 15/15 at desktop and 390px. Real captures
134+
`b68e7f8a312d9ac724e2e845eb690f0db19313e4badf3e96fb5c6590398d9360`;
135+
receipts `runtime/verification/health-recovery-{full,browser}-2026-10-19.json`
136+
(ignored by Git).
137+
- Installed Chrome browser suite passed 18/18 at desktop and 390px. Real captures
135138
are `runtime/verification/commons-first-run-{desktop,narrow}-2026-10-19.png`,
136139
`commons-provider-offline-desktop-2026-10-19.png` and catalog captures. Tests
137140
used in-memory services; provider-health responses were controlled in the
@@ -177,14 +180,16 @@ are real disposable-service captures. Full source/browser gates remain.
177180
`runtime/verification/startup-busy-baseline-2026-10-19/`. Focused UI and all 12
178181
Chrome journeys passed, including actual Tab/Enter and the real retry HTTP 200;
179182
its full gate and public CI passed at `746729d`. [Actual error view](media/workspace-unavailable-2026-10-19.png).
180-
- The pending identity unit adds `shared/local-model-artifact.mjs` and
183+
- The completed identity unit adds `shared/local-model-artifact.mjs` and
181184
`npm run model:inspect [-- --hash]`. It checks file metadata/digest without
182185
reading a token, loading a model or probing a provider. Synthetic fixtures cover
183186
missing/mismatch/escape/cancellation; the real stream cancelled after 165 MB.
184187
The declared 4096-token local window and input/output budget are preparation,
185188
with tokenizer and hardware fit unqualified. Actual byte identity does not
186189
qualify either proposed role. Focused UI and grouped Chrome 12/12 passed,
187-
including narrow artifact details. The frozen real CLI hash and full gate remain.
190+
including narrow artifact details. The frozen real CLI hash matched the pinned
191+
artifact and full gate passed; the later public retry-fixture failure was
192+
repaired in `ae6569b`, without model inference.
188193
- `npm run benchmark:backend` used a disposable PGlite snapshot of five projects
189194
and 1,000 messages. Twenty samples per path: current normalized message-write
190195
p50 9.09 ms versus retained legacy pattern 42.99 ms. This verifies a prior
@@ -198,7 +203,7 @@ are real disposable-service captures. Full source/browser gates remain.
198203

199204
## Next work, in order
200205

201-
1. Complete health/retry recovery: run grouped Chrome and `npm run check` on frozen source,
206+
1. Complete keyboard scenario controls: run grouped Chrome and `npm run check` on frozen source,
202207
commit it, copy the unpublished local commit into the separate public
203208
checkout, compare Git trees, push without force and inspect public CI.
204209
Record exact SHA and receipt.

‎docs/MISSION-2026-10-19.md‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Start: 03:46:17 UTC. Deadline: 15:46:17 UTC. Final integration reserve begins 14
1212

1313
## Current action
1414

15-
Finish service-health recovery and manual workspace refresh focus. Four actual Chrome failures were reproduced and preserved; four focused recovery tests now pass. Run focused UI, then freeze source for full Chrome/full gates and publication. Keep all new profiles disabled. The final integration reserve still begins at 14:16:17 UTC.
15+
Finish keyboard scenario controls after two preserved Chrome failures. Next step now retains entry, terminal/error steps fall back to content, and Pause remains available during a transaction without cancelling its committed work. Verify current-step completion, no future scheduling, chosen-input focus and preserved exports; then frozen full gates and publication. Keep all new profiles disabled. The final integration reserve still begins at 14:16:17 UTC.
1616

1717
## Decisions and limits
1818

@@ -90,4 +90,7 @@ Finish service-health recovery and manual workspace refresh focus. Four actual C
9090
- 09:36 UTC: Chrome exposed and preserved four UI failures: settled health errors kept Checking services; initial workspace Retry stole the search focus; Environment disappeared when the workspace snapshot failed; the toolbar refresh lost focus after its temporary disabled state. Baselines are under `runtime/verification/health-focus-baseline-2026-10-19`, `health-without-workspace-baseline-2026-10-19` and `workspace-toolbar-focus-baseline-2026-10-19`. New scoped busy/error/last-available states, independent diagnostics and manual focus restoration passed four focused Chrome tests, including light/dark 390px axe. Diagnostic refresh checks the exact returned scenario step and rejects reset/advance requests. Real captures were inspected and copied to docs/media with digests `d26cd5a6` and `032e4796`. Focused UI and frozen full gates remain. Vendored Impeccable craft/state guidance was read as a reference; its separate context engine was not run, PRODUCT.md is absent, and existing DESIGN.md remains authoritative.
9191
## Next checkpoint
9292

93-
Focused health/workspace Chrome passed 4/4, and focused UI passed DOM/axe 2/2, build and serving. Freeze source for the complete 18-test browser suite and full gate; then commit/publish and validate the exact source/public CI association. Next inspect keyboard use of scenario controls. Keep the final 90-minute reserve from 14:16:17 UTC.
93+
- 09:50 UTC: health/manual-refresh recovery committed locally as `dfa9ecb16afea0c7d5e31ff6bc029a9483fef1ac` after full 81/81 and Chrome 18/18 on the same frozen hash `b68e7f8a312d9ac724e2e845eb690f0db19313e4badf3e96fb5c6590398d9360`. Receipts: `runtime/verification/health-recovery-{full,browser}-2026-10-19.json`. Normal publication produced `5392fc00b2ac2f8faedc507acc63311705a93dcc`, identical tree `ceec86201675ecda32f8c844123f5994c1b8ac28`. CI39233009471 passed all three jobs. Local preflight confirmed current full/browser receipts and both clean equal trees.
94+
- Chrome then reproduced Next step losing focus after a successful transaction and Pause being disabled while a cycle request was pending. Both traces are retained under `runtime/verification/scenario-keyboard-baseline-2026-10-19`. An initial three-test focused correction passed; the strengthened pause cases also distinguish restoring the control from respecting another chosen input. No model calls or retained-store writes.
95+
96+
Run focused UI, freeze complete source for all browser groups and full gate, then commit/publish the keyboard unit. Next inspect competing bookmark writes and remaining release acceptance gaps. Keep the final 90-minute reserve from 14:16:17 UTC.

‎prototype/app/App.jsx‎

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -186,17 +186,17 @@ export function App() {
186186
[toast, setToast] = useState("");
187187
const main = useRef(null);
188188
const handledRoute = useRef(null);
189-
const refreshOrigin = useRef(null);
189+
const operationOrigin = useRef(null);
190190
useLayoutEffect(() => {
191191
if (busy) return;
192-
const pending = refreshOrigin.current;
193-
refreshOrigin.current = null;
192+
const pending = operationOrigin.current;
193+
operationOrigin.current = null;
194194
if (pending && location.hash === pending.hash &&
195195
(document.activeElement === document.body || document.activeElement === pending.trigger))
196-
(pending.trigger.isConnected ? pending.trigger : main.current)?.focus({ preventScroll: true });
196+
(pending.trigger.isConnected && !pending.trigger.disabled ? pending.trigger : main.current)?.focus({ preventScroll: true });
197197
}, [busy, data, error]);
198198
function refreshWorkspace(event) {
199-
refreshOrigin.current = { trigger: event.currentTarget, hash: location.hash };
199+
operationOrigin.current = { trigger: event.currentTarget, hash: location.hash };
200200
workspace.setPlaying(false);
201201
void workspace.refresh();
202202
}
@@ -389,10 +389,16 @@ export function App() {
389389
</span>
390390
<button
391391
id="playback-toggle"
392-
disabled={!data || busy || Boolean(error)}
393-
aria-pressed={playing}
394-
onClick={() => {
392+
disabled={!data || (busy && !playing) || Boolean(error)}
393+
title={playing ? "Pause future steps. The current step can finish." : undefined}
394+
onClick={(event) => {
395+
if (playing) {
396+
if (busy) operationOrigin.current = { trigger: event.currentTarget, hash: location.hash };
397+
workspace.setPlaying(false);
398+
return;
399+
}
395400
if (data.step === 10) {
401+
operationOrigin.current = { trigger: event.currentTarget, hash: location.hash };
396402
void workspace.newRun().then((next) => {
397403
if (next && next.runId !== data.runId) {
398404
routeScroll.delete("#/home");
@@ -405,18 +411,15 @@ export function App() {
405411
workspace.setPlaying(!playing);
406412
}}
407413
>
408-
{data?.step === 10
409-
? "New run"
410-
: playing
411-
? "Pause cycle"
412-
: "Play cycle"}
414+
{playing ? "Pause cycle" : data?.step === 10 ? "New run" : "Play cycle"}
413415
</button>
414416
<button
415417
id="playback-next"
416418
disabled={
417419
!data || busy || Boolean(error) || data.step === 10
418420
}
419-
onClick={() => {
421+
onClick={(event) => {
422+
operationOrigin.current = { trigger: event.currentTarget, hash: location.hash };
420423
workspace.setPlaying(false);
421424
void workspace.advance();
422425
}}

‎scripts/project-map.mjs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const areas = {
2525
"prototype/app/components/project-contributions.jsx",
2626
"prototype/app/components/project-timeline.jsx",
2727
],
28-
tests: ["tests/interface.dom.mjs", "tests/agent-catalog.test.mjs", "tests/agent-fixtures.test.mjs", "tests/browser/commons-first-run.spec.mjs", "tests/browser/scenario-pr.spec.mjs", "tests/browser/workspace-recovery.spec.mjs", "tests/browser/service-health.spec.mjs"],
28+
tests: ["tests/interface.dom.mjs", "tests/agent-catalog.test.mjs", "tests/agent-fixtures.test.mjs", "tests/browser/commons-first-run.spec.mjs", "tests/browser/scenario-pr.spec.mjs", "tests/browser/workspace-recovery.spec.mjs", "tests/browser/service-health.spec.mjs", "tests/browser/scenario-keyboard.spec.mjs"],
2929
docs: ["DESIGN.md", "docs/AGENT-CATALOG.md", "docs/FIRST-RUN.md"],
3030
},
3131
commons: {

‎scripts/test-ui.mjs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ export const browserGroups = Object.freeze([
2626
name: "account-recovery",
2727
files: Object.freeze(["account-recovery.spec.mjs"]),
2828
}),
29+
Object.freeze({
30+
name: "scenario-keyboard",
31+
files: Object.freeze(["scenario-keyboard.spec.mjs"]),
32+
}),
2933
Object.freeze({
3034
name: "history-and-pr",
3135
files: Object.freeze([

0 commit comments

Comments
 (0)