Stream page goldens hold one width for each id and clock they hide, and the release test quotes the PATH it hands install.sh #129

Merged
agra merged 3 commits from task/3651-streams-spec-ts-and-tail-stream-spec-ts into master 2026-10-24 09:20:24 +03:00
Owner

Tracker: #3651

Also fixes #3745, which kept this PR's full gate from passing on s32.

What it delivers

The stream page's goldens (#3651)

The stream page's goldens in web/e2e/streams.spec.ts and web/e2e/tail-stream.spec.ts now render the same whatever the stream's id and however long the run before them took.

Cause. The specs' freeze hid the stream id, the task id, the Opened age and the run time with visibility: hidden. A hidden value still takes its width, and system-ui digits are proportional (Stream #42 is 62.58px, #43 62.84px, #47 62.19px). So:

  • The run time. stream-finalized-metadata closes a stream that the file's beforeAll opened. In a normal run that takes under 10 s, and the golden was drawn with a one-digit ran Ns. On a loaded host the fact reaches ran 10s, which is one digit wider, and Session and Context slide right. Probe 2 below reproduces that diff at exactly the gate's 415 pixels, its first failure.
  • The thinking seconds. The same scene's thinking · 0s · 390 tokens counts the seconds between two requests the test makes. Past 500 ms it reads 1s.
  • The cascade. A failed test restarts Playwright's worker, and the file's beforeAll then files every stream again under new ids. A new id moves the done (or running) chip by a fraction of a pixel. Every later shot that shows the stream header then fails by 1px at the chip. That is the other ten failures. Their slowness follows from failing: a failing shot captures twice and writes its diff and trace. In probe 1 the failing shots took 0.5–1.0 s, against about 0.16 s for a passing one.

Fix. freeze moves into web/e2e/stream-fixture.ts, which both specs import. Each hidden value now reads as one fixed value before it is hidden, so it always takes the same width:

  • an id reads as four digits (Stream #0000, #0000), as view-stream.spec.ts already does;
  • the Opened age reads just now;
  • the run time reads ran 0s or running 0s.

stream-finalized-metadata also pins its thinking line's seconds to 0s before the shot.

The release test's PATH (#3745)

tests/step9_release.sx runs install.sh on this Mac through env -u XDG_CONFIG_HOME HOME=… PATH=…/stubs:$PATH sh -c "…", with $PATH unquoted. A run PATH that holds a directory with a space (s32's holds /Users/agra/Library/Application Support/JetBrains/Toolbox/scripts) splits that assignment at the space, and env runs the rest as a command: env: Support/JetBrains/Toolbox/scripts: No such file or directory. Three checks of install.sh then fail, so full fails on s32 for every branch.

Fix. The PATH assignment is quoted. The launchctl stub's directory is named with a space, so the check hands install.sh a PATH with a spaced entry on every host, not only on s32. No other sh(...) call in the file splices $PATH.

Regressions, fail before and pass after

The stream page's goldens

The goldens of the failing scenes are the regressions. Three scratch probes, none of them committed, recreate the conditions that failed them. Every probe was run on master 3ecd9d1 and again at 8da18d1:

  1. A stream filed before the specs. A scratch spec e2e/stream-probe.spec.ts files one project, task and stream. Then npx playwright test e2e/stream-probe.spec.ts e2e/streams.spec.ts e2e/tail-stream.spec.ts.
    • Base: 15 failed. These are every shot that shows the stream header: stream-transcript, agy-transcript, stream-progress ×2, stream-finalized-metadata, stream-drop ×4, stream-tail-http-error, stream-transcript-dark and stream-follow ×4. Each diff is at the chip, as in the gate run.
    • Head: 53 passed.
  2. A slow run up to the scene. A 10 s wait at the start of follows a running stream through another client's append and close, run with -g.
    • Base: failed, 415 pixels, with Session and Context shifted.
    • Head: passed.
  3. A slow follow. A 600 ms wait before the test posts thought(390).
    • Base: failed, 100 pixels, the shot reading thinking · 1s · 390 tokens.
    • Head: passed.

The release test's PATH

The changed check in tests/step9_release.sx is the regression. These arms ran by hand on m5 on 2026-10-24, from the checkout after one scripts/release.sh, with the gate cache's pinned sx. m5's own run PATH holds no entry with a space.

Arm Run PATH Result
master's test (3ecd9d1) m5's STEP9 OK, 39 ok
master's test m5's, after a directory named spaced dir STEP9 FAIL (3 checks), env: dir:/tmp/…: No such file or directory, the gate job's three install.sh checks
this PR's test without the quoting m5's STEP9 FAIL (3 checks), env: bin:/tmp/…: No such file or directory
this PR's test m5's STEP9 OK, 39 ok
this PR's test m5's, after spaced dir STEP9 OK, 39 ok

So the check now fails before the fix on any host, not only on s32.

Golden set

The following 15 goldens were regenerated in one full run of playwright.config.ts (chromium, darwin). Each moves only where a hidden id or clock took a different width. No other snapshot changes. The #3745 fix changes no golden.

  • web/e2e/streams.spec.ts-snapshots/: stream-transcript, stream-transcript-dark, agy-transcript, stream-progress-light, stream-progress-dark, stream-finalized-metadata, stream-drop-1280-light, stream-drop-1280-dark, stream-drop-390-light, stream-drop-390-dark, stream-tail-http-error (-chromium-darwin.png)
  • web/e2e/tail-stream.spec.ts-snapshots/: stream-follow-light, stream-follow-dark, stream-follow-phone-light, stream-follow-phone-dark (-chromium-darwin.png)

Gates at the head

The head is 95b3d2d, which merges master 4bd0747 into 3ee9597. The merge was clean and leaves the branch's diff byte for byte as review run 478 approved it at 3ee9597 (git diff 3ecd9d1 3ee9597 equals git diff 4bd0747 95b3d2d). Master 4bd0747 carries fa0995c, the clock-timed tail heartbeat (ec78bde's src/api.sx), which is what the tests/step_concurrency.sx lease check needed. This branch changes nothing in src/ or runner/, and in tests/ only step9_release.sx.

  • sak-gate full at 95b3d2d (tracker gate run 270), started by the run that made the merge: cancelled at 07:45 EEST, when that run was killed mid-gate along with another run on the same runner.
  • sak-gate full at 95b3d2d on runner m5, this run's gate #1 (tracker gate run 273), 07:49–08:13 EEST: failed at its last step only. Every earlier step passed: setup, both sx builds, npm run build (vitest 401/401), the libc grep, every tests/*.sx file (tests/step_concurrency.sx included), the release step with tests/step9_release.sx, the deploy contract, and the main Playwright config (740 passed, 1 skipped, 4.2 min, no golden failed). The runner Playwright config then failed at global setup: sak serve exited with code 1, sak serve never answered on http://127.0.0.1:18988. A session outside the runner's gate queue, reviewing another sak branch in its own checkout, ran the same configs on the same fixed ports at that moment. Its main config failed at 08:11:58 because this gate held 18987. Its runner config then held 18988 from 08:11:58 to 08:12:37 (10 passed), the window in which this gate's runner config tried to start there.
  • sak-gate full at 95b3d2d on runner m5, this run's gate #2 (tracker gate run 278), 08:15–08:45 EEST: passed. Every step passed: setup, both sx builds, npm run build (vitest 401/401), the libc grep, every tests/*.sx file, the release step (vitest 401/401 again inside the release build, then tests/step9_release.sx), the deploy contract, the main Playwright config (740 passed, 1 skipped, 4.6 min, no golden failed) and the runner Playwright config (10 passed).

Earlier gates, at 3ee9597 (before the master merge)

All at 3ee9597 on runner m5, 2026-10-24. The head merges cleanly with master 6e5e668. This branch changes nothing in src/ or runner/, and in tests/ only step9_release.sx.

  • sak-gate full, this run's gate #1 (tracker gate run 263), 06:09–06:25 EEST: failed in tests/*.sx, only at the tests/step_concurrency.sx check "the slot a dropped tail left behind is handed on once its lease lapses" (CONCURRENCY FAIL (1 checks)). Every step before it passed: setup, both sx builds, npm run build (vitest 390/390), the libc grep, and every other tests/*.sx file. The gate stops at the first failed step, so it never reached the release step or Playwright.
    • That check is #3734. On m5 at night a 100 ms sleep took 102–251 ms (average 196, UserIsActive 0). The tail's heartbeat counts its polls, so a dropped tail keeps its slot past the check's fixed wait. Its fix is ec78bde, which reaches master through PR sx/sak#128.
    • By hand from two git archive copies of the head, run side by side with the gate cache's pinned sx: the head as it is failed the check 2 of 2; the head with ec78bde's src/api.sx passed 2 of 2 (CONCURRENCY OK).
  • The gate's later steps, by hand at the head in the checkout with the gate cache's pinned sx and browsers:
    • scripts/release.sh plus tests/step9_release.sx: passed (vitest 390/390 inside the release build, STEP9 OK, 39 ok). An earlier attempt during a load spike (one-minute load 18–34) failed in the release build's own vitest, on force.test.ts "spaces the anchors after an in-session grow…" at 6665 ms against 5 s. That is #3731.
    • bash tests/deploy_contract.sh: passed.
    • npx playwright test (main config, no snapshot update): 723 passed, 1 skipped, in 8.1 min on a loaded host against its usual 3.6–5. No golden failed.
    • npx playwright test -c playwright.runner.config.ts: 10 passed.

Earlier, at 8da18d1 (the golden fix alone)

Review run 428 approved 8da18d1. The flow's gate step then failed three times, each outside this diff: job 76 on #3731, job 78 on #3734, and job 82 (s32) on #3745, which the second commit fixes. By hand at 8da18d1 on s32, the main Playwright config passed three times (723 passed, 1 skipped), with no golden failing.

Tracker: [#3651](https://sak.swipelab.com/tasks/3651) Also fixes [#3745](https://sak.swipelab.com/tasks/3745), which kept this PR's `full` gate from passing on s32. ## What it delivers ### The stream page's goldens (#3651) The stream page's goldens in `web/e2e/streams.spec.ts` and `web/e2e/tail-stream.spec.ts` now render the same whatever the stream's id and however long the run before them took. **Cause.** The specs' `freeze` hid the stream id, the task id, the Opened age and the run time with `visibility: hidden`. A hidden value still takes its width, and system-ui digits are proportional (`Stream #42` is 62.58px, `#43` 62.84px, `#47` 62.19px). So: - **The run time.** `stream-finalized-metadata` closes a stream that the file's `beforeAll` opened. In a normal run that takes under 10 s, and the golden was drawn with a one-digit `ran Ns`. On a loaded host the fact reaches `ran 10s`, which is one digit wider, and Session and Context slide right. Probe 2 below reproduces that diff at exactly the gate's 415 pixels, its first failure. - **The thinking seconds.** The same scene's `thinking · 0s · 390 tokens` counts the seconds between two requests the test makes. Past 500 ms it reads `1s`. - **The cascade.** A failed test restarts Playwright's worker, and the file's `beforeAll` then files every stream again under new ids. A new id moves the `done` (or `running`) chip by a fraction of a pixel. Every later shot that shows the stream header then fails by 1px at the chip. That is the other ten failures. Their slowness follows from failing: a failing shot captures twice and writes its diff and trace. In probe 1 the failing shots took 0.5–1.0 s, against about 0.16 s for a passing one. **Fix.** `freeze` moves into `web/e2e/stream-fixture.ts`, which both specs import. Each hidden value now reads as one fixed value before it is hidden, so it always takes the same width: - an id reads as four digits (`Stream #0000`, `#0000`), as `view-stream.spec.ts` already does; - the Opened age reads `just now`; - the run time reads `ran 0s` or `running 0s`. `stream-finalized-metadata` also pins its thinking line's seconds to `0s` before the shot. ### The release test's PATH (#3745) `tests/step9_release.sx` runs `install.sh` on this Mac through `env -u XDG_CONFIG_HOME HOME=… PATH=…/stubs:$PATH sh -c "…"`, with `$PATH` unquoted. A run PATH that holds a directory with a space (s32's holds `/Users/agra/Library/Application Support/JetBrains/Toolbox/scripts`) splits that assignment at the space, and `env` runs the rest as a command: `env: Support/JetBrains/Toolbox/scripts: No such file or directory`. Three checks of `install.sh` then fail, so `full` fails on s32 for every branch. **Fix.** The PATH assignment is quoted. The launchctl stub's directory is named with a space, so the check hands `install.sh` a PATH with a spaced entry on every host, not only on s32. No other `sh(...)` call in the file splices `$PATH`. ## Regressions, fail before and pass after ### The stream page's goldens The goldens of the failing scenes are the regressions. Three scratch probes, none of them committed, recreate the conditions that failed them. Every probe was run on master 3ecd9d1 and again at 8da18d1: 1. **A stream filed before the specs.** A scratch spec `e2e/stream-probe.spec.ts` files one project, task and stream. Then `npx playwright test e2e/stream-probe.spec.ts e2e/streams.spec.ts e2e/tail-stream.spec.ts`. - Base: 15 failed. These are every shot that shows the stream header: `stream-transcript`, `agy-transcript`, `stream-progress` ×2, `stream-finalized-metadata`, `stream-drop` ×4, `stream-tail-http-error`, `stream-transcript-dark` and `stream-follow` ×4. Each diff is at the chip, as in the gate run. - Head: 53 passed. 2. **A slow run up to the scene.** A 10 s wait at the start of `follows a running stream through another client's append and close`, run with `-g`. - Base: failed, 415 pixels, with Session and Context shifted. - Head: passed. 3. **A slow follow.** A 600 ms wait before the test posts `thought(390)`. - Base: failed, 100 pixels, the shot reading `thinking · 1s · 390 tokens`. - Head: passed. ### The release test's PATH The changed check in `tests/step9_release.sx` is the regression. These arms ran by hand on m5 on 2026-10-24, from the checkout after one `scripts/release.sh`, with the gate cache's pinned sx. m5's own run PATH holds no entry with a space. | Arm | Run PATH | Result | | --- | --- | --- | | master's test (3ecd9d1) | m5's | `STEP9 OK`, 39 ok | | master's test | m5's, after a directory named `spaced dir` | **`STEP9 FAIL (3 checks)`**, `env: dir:/tmp/…: No such file or directory`, the gate job's three install.sh checks | | this PR's test without the quoting | m5's | **`STEP9 FAIL (3 checks)`**, `env: bin:/tmp/…: No such file or directory` | | this PR's test | m5's | `STEP9 OK`, 39 ok | | this PR's test | m5's, after `spaced dir` | `STEP9 OK`, 39 ok | So the check now fails before the fix on any host, not only on s32. ## Golden set The following 15 goldens were regenerated in one full run of `playwright.config.ts` (chromium, darwin). Each moves only where a hidden id or clock took a different width. No other snapshot changes. The #3745 fix changes no golden. - `web/e2e/streams.spec.ts-snapshots/`: `stream-transcript`, `stream-transcript-dark`, `agy-transcript`, `stream-progress-light`, `stream-progress-dark`, `stream-finalized-metadata`, `stream-drop-1280-light`, `stream-drop-1280-dark`, `stream-drop-390-light`, `stream-drop-390-dark`, `stream-tail-http-error` (`-chromium-darwin.png`) - `web/e2e/tail-stream.spec.ts-snapshots/`: `stream-follow-light`, `stream-follow-dark`, `stream-follow-phone-light`, `stream-follow-phone-dark` (`-chromium-darwin.png`) ## Gates at the head The head is 95b3d2d, which merges master 4bd0747 into 3ee9597. The merge was clean and leaves the branch's diff byte for byte as review run 478 approved it at 3ee9597 (`git diff 3ecd9d1 3ee9597` equals `git diff 4bd0747 95b3d2d`). Master 4bd0747 carries fa0995c, the clock-timed tail heartbeat (ec78bde's `src/api.sx`), which is what the `tests/step_concurrency.sx` lease check needed. This branch changes nothing in `src/` or `runner/`, and in `tests/` only `step9_release.sx`. - `sak-gate full` at 95b3d2d (tracker gate run 270), started by the run that made the merge: **cancelled** at 07:45 EEST, when that run was killed mid-gate along with another run on the same runner. - `sak-gate full` at 95b3d2d on runner m5, this run's gate #1 (tracker gate run 273), 07:49–08:13 EEST: **failed** at its last step only. Every earlier step passed: setup, both sx builds, `npm run build` (vitest 401/401), the libc grep, every `tests/*.sx` file (`tests/step_concurrency.sx` included), the release step with `tests/step9_release.sx`, the deploy contract, and the main Playwright config (740 passed, 1 skipped, 4.2 min, no golden failed). The runner Playwright config then failed at global setup: `sak serve exited with code 1`, `sak serve never answered on http://127.0.0.1:18988`. A session outside the runner's gate queue, reviewing another sak branch in its own checkout, ran the same configs on the same fixed ports at that moment. Its main config failed at 08:11:58 because this gate held 18987. Its runner config then held 18988 from 08:11:58 to 08:12:37 (10 passed), the window in which this gate's runner config tried to start there. - `sak-gate full` at 95b3d2d on runner m5, this run's gate #2 (tracker gate run 278), 08:15–08:45 EEST: **passed**. Every step passed: setup, both sx builds, `npm run build` (vitest 401/401), the libc grep, every `tests/*.sx` file, the release step (vitest 401/401 again inside the release build, then `tests/step9_release.sx`), the deploy contract, the main Playwright config (740 passed, 1 skipped, 4.6 min, no golden failed) and the runner Playwright config (10 passed). ## Earlier gates, at 3ee9597 (before the master merge) All at 3ee9597 on runner m5, 2026-10-24. The head merges cleanly with master 6e5e668. This branch changes nothing in `src/` or `runner/`, and in `tests/` only `step9_release.sx`. - `sak-gate full`, this run's gate #1 (tracker gate run 263), 06:09–06:25 EEST: **failed** in `tests/*.sx`, only at the `tests/step_concurrency.sx` check "the slot a dropped tail left behind is handed on once its lease lapses" (`CONCURRENCY FAIL (1 checks)`). Every step before it passed: setup, both sx builds, `npm run build` (vitest 390/390), the libc grep, and every other `tests/*.sx` file. The gate stops at the first failed step, so it never reached the release step or Playwright. - That check is [#3734](https://sak.swipelab.com/tasks/3734). On m5 at night a 100 ms sleep took 102–251 ms (average 196, `UserIsActive 0`). The tail's heartbeat counts its polls, so a dropped tail keeps its slot past the check's fixed wait. Its fix is ec78bde, which reaches master through PR sx/sak#128. - By hand from two `git archive` copies of the head, run side by side with the gate cache's pinned sx: the head as it is **failed** the check 2 of 2; the head with ec78bde's `src/api.sx` **passed** 2 of 2 (`CONCURRENCY OK`). - The gate's later steps, by hand at the head in the checkout with the gate cache's pinned sx and browsers: - `scripts/release.sh` plus `tests/step9_release.sx`: **passed** (vitest 390/390 inside the release build, `STEP9 OK`, 39 ok). An earlier attempt during a load spike (one-minute load 18–34) failed in the release build's own vitest, on `force.test.ts` "spaces the anchors after an in-session grow…" at 6665 ms against 5 s. That is [#3731](https://sak.swipelab.com/tasks/3731). - `bash tests/deploy_contract.sh`: **passed**. - `npx playwright test` (main config, no snapshot update): **723 passed, 1 skipped**, in 8.1 min on a loaded host against its usual 3.6–5. No golden failed. - `npx playwright test -c playwright.runner.config.ts`: **10 passed**. ### Earlier, at 8da18d1 (the golden fix alone) Review run 428 approved 8da18d1. The flow's gate step then failed three times, each outside this diff: job 76 on #3731, job 78 on #3734, and job 82 (s32) on #3745, which the second commit fixes. By hand at 8da18d1 on s32, the main Playwright config passed three times (723 passed, 1 skipped), with no golden failing.
The stream specs' freeze hid ids and clocks with visibility: hidden, so
each still took its own width. A new stream id after a worker restart
moved the state chip by a fraction of a pixel, and a run time that
reached two digits on a loaded host moved Session and Context. freeze
now lives in stream-fixture.ts and sets each hidden value to one
reading first: a four-digit id, "just now", and "ran 0s" or
"running 0s". The finalized-metadata scene also pins its thinking
seconds, which count the time between two of the test's requests.

Regenerates the 15 stream page goldens those widths moved, in one full
run of playwright.config.ts.

Tracker: https://sak.swipelab.com/tasks/3651
agra changed title from Stream page goldens hold one width for each id and clock they hide to Stream page goldens hold one width for each id and clock they hide, and the release test quotes the PATH it hands install.sh 2026-10-24 06:41:14 +03:00
tests/step9_release.sx ran install.sh through `env ... PATH={}/stubs:$PATH
sh -c ...` with the PATH unquoted. A run PATH that holds a directory with
a space split that assignment, and env ran the rest as a command, so
three install.sh checks failed. s32's run PATH holds "Application
Support", so the full gate failed there for every branch.

The assignment is quoted, and the launchctl stub's directory is named
with a space, so the check hands install.sh a spaced PATH entry on every
host.

Tracker: https://sak.swipelab.com/tasks/3745
agra merged commit 13c9709ff2 into master 2026-10-24 09:20:24 +03:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sx/sak!129
No description provided.