Each e2e run serves sak on a free port of its own, so two runs on one host no longer collide #140

Merged
agra merged 3 commits from task/3776-sak-s-e2e-suites-serve-on-fixed-ports-18 into master 2026-10-25 05:19:53 +02:00
Owner

Tracker: #3776

The e2e suites served sak on fixed loopback ports: 18987 (main and shots), 18988 (runner), 19000 (navigator), 19001 (perf), and 19002 and 19003 for the navigator's crowded and tall-project servers. A second e2e run on the same host took the same port. That second run could be another runner's gate, an agent running the suites by hand, or a session outside sak. One of the runs then failed at global setup with sak serve never answered on http://127.0.0.1:18988, or its specs talked to the other run's sak.

What this PR delivers

  • A port per run. web/e2e/server.ts picks the run's port. The first process of a run that loads it asks the kernel for a free loopback port, the same way sandbox.free_port() does for the sx tests, and stores it in SAK_E2E_PORT. The Playwright workers inherit that variable, so the config's baseURL, the global setup's sak serve and every spec use the same port. If SAK_E2E_PORT is already set, the run serves on that port.
  • Every suite uses it. The runner suite's sak serve and sak-runner --url, the navigator suite and the perf suite all serve on the run's port. The navigator's crowded and tall-project servers each pick a free port of their own (freePort()).
  • Goldens unchanged. The Add a runner install command and the New token runner command show location.origin. Before each shot, drawOrigin sets the origin in that text to one fixed reading, http://127.0.0.1:18987, the same way freeze fixes ids and clocks. Golden set added or changed: none.
  • README. It says a Playwright run serves on a free port, or on SAK_E2E_PORT.

Regression: the runner suite twice at once

Each arm is a git archive copy of the tree, with dist/sak and dist/sak-runner built by sak-gate fast and the gate cache's node_modules. In each pair, both arms ran npx playwright test -c playwright.runner.config.ts at the same moment on m5.

  • Fail-before, master 8cda22f: one arm passed 10/10. The other failed at global setup with sak serve exited with code 1 and Error: sak serve never answered on http://127.0.0.1:18988.
  • Pass-after, head d22af19: both arms passed 10/10. Run again with ps sampling, they again passed 10/10 each, serving on ports 62096 and 62097.

Other checks

  • Mutation. With drawOrigin removed from Add a runner, all 8 of its goldens fail by 89–90 px. With it in place, add-a-runner.spec.ts and tokens.spec.ts pass 25/25 on a picked port.
  • Navigator suite at the head.
    • First run: 163 passed, and hud.spec.ts:200 "Phone finder golden, light" failed by 51 px. Every differing pixel was at the dialog's four rounded corners, which sit over the WebGL canvas. No text differed.
    • That test passed 6/6 with --repeat-each 3 at master and 6/6 at the head.
    • The whole suite then passed 164/164 at the head.
  • Not run: the perf suite (npm run e2e:perf). It measures frame rate on the host's GPU. Its only change is that it takes its port from server.ts.

Gates at the head

  • fast, tracker gate run 357 (Implementer run 644's #1), passed. It ran on base 8cda22f with the change not yet committed.
  • full, tracker gate run 359 (run 644's #2), passed at head d22af19 on a clean tree, on m5. Every step passed:
    • setup, builds and vitest (401/401);
    • tests/*.sx;
    • release with step9, and the deploy contract;
    • main Playwright config: 740 passed;
    • runner Playwright config: 10 passed.
  • The gate step's full (job 131, s32) failed at d22af19 on one shot only: accounts.spec.ts "dark › paints a sign-in waiting on its device code", by 144 px. Its main Playwright config took 10.4 min, against the usual 4–5. That shot is the sign-in flake of #3796, and this PR touches no accounts file.
    • The same shots under a 6× CDP CPU throttle, from git archive arms on s32: base 8cda22f failed 8 of 8 device-code sign-in shots at 1280×800 (79, 143 and 144 px), and head d22af19 failed 6 of 8. The phone shots and the pasted-code shots passed in both.
    • With #3796's aaec0d0 applied unchanged to the head, all 24 passed.
  • full, tracker gate run 383 (Implementer run 689's #1), passed at head d22af19 on a clean tree, on s32. Every step passed:
    • vitest (401/401);
    • tests/*.sx;
    • release with step9, and the deploy contract;
    • main Playwright config: 740 passed and 1 skipped, in 4.8 min;
    • runner Playwright config: 10 passed.
Tracker: [#3776](https://sak.swipelab.com/tasks/3776) The e2e suites served sak on fixed loopback ports: 18987 (main and shots), 18988 (runner), 19000 (navigator), 19001 (perf), and 19002 and 19003 for the navigator's crowded and tall-project servers. A second e2e run on the same host took the same port. That second run could be another runner's gate, an agent running the suites by hand, or a session outside sak. One of the runs then failed at global setup with `sak serve never answered on http://127.0.0.1:18988`, or its specs talked to the other run's sak. ## What this PR delivers - **A port per run.** `web/e2e/server.ts` picks the run's port. The first process of a run that loads it asks the kernel for a free loopback port, the same way `sandbox.free_port()` does for the sx tests, and stores it in `SAK_E2E_PORT`. The Playwright workers inherit that variable, so the config's `baseURL`, the global setup's `sak serve` and every spec use the same port. If `SAK_E2E_PORT` is already set, the run serves on that port. - **Every suite uses it.** The runner suite's `sak serve` and `sak-runner --url`, the navigator suite and the perf suite all serve on the run's port. The navigator's crowded and tall-project servers each pick a free port of their own (`freePort()`). - **Goldens unchanged.** The Add a runner install command and the New token runner command show `location.origin`. Before each shot, `drawOrigin` sets the origin in that text to one fixed reading, `http://127.0.0.1:18987`, the same way `freeze` fixes ids and clocks. Golden set added or changed: none. - **README.** It says a Playwright run serves on a free port, or on `SAK_E2E_PORT`. ## Regression: the runner suite twice at once Each arm is a `git archive` copy of the tree, with `dist/sak` and `dist/sak-runner` built by `sak-gate fast` and the gate cache's `node_modules`. In each pair, both arms ran `npx playwright test -c playwright.runner.config.ts` at the same moment on m5. - **Fail-before, master 8cda22f:** one arm passed 10/10. The other failed at global setup with `sak serve exited with code 1` and `Error: sak serve never answered on http://127.0.0.1:18988`. - **Pass-after, head d22af19:** both arms passed 10/10. Run again with `ps` sampling, they again passed 10/10 each, serving on ports 62096 and 62097. ## Other checks - **Mutation.** With `drawOrigin` removed from Add a runner, all 8 of its goldens fail by 89–90 px. With it in place, `add-a-runner.spec.ts` and `tokens.spec.ts` pass 25/25 on a picked port. - **Navigator suite at the head.** - First run: 163 passed, and `hud.spec.ts:200` "Phone finder golden, light" failed by 51 px. Every differing pixel was at the dialog's four rounded corners, which sit over the WebGL canvas. No text differed. - That test passed 6/6 with `--repeat-each 3` at master and 6/6 at the head. - The whole suite then passed 164/164 at the head. - **Not run:** the perf suite (`npm run e2e:perf`). It measures frame rate on the host's GPU. Its only change is that it takes its port from `server.ts`. ## Gates at the head - `fast`, tracker gate run 357 (Implementer run 644's #1), passed. It ran on base 8cda22f with the change not yet committed. - `full`, tracker gate run 359 (run 644's #2), passed at head d22af19 on a clean tree, on m5. Every step passed: - setup, builds and vitest (401/401); - tests/*.sx; - release with step9, and the deploy contract; - main Playwright config: 740 passed; - runner Playwright config: 10 passed. - The gate step's `full` (job 131, s32) failed at d22af19 on one shot only: `accounts.spec.ts` "dark › paints a sign-in waiting on its device code", by 144 px. Its main Playwright config took 10.4 min, against the usual 4–5. That shot is the sign-in flake of [#3796](https://sak.swipelab.com/tasks/3796), and this PR touches no accounts file. - The same shots under a 6× CDP CPU throttle, from `git archive` arms on s32: base 8cda22f failed 8 of 8 device-code sign-in shots at 1280×800 (79, 143 and 144 px), and head d22af19 failed 6 of 8. The phone shots and the pasted-code shots passed in both. - With #3796's aaec0d0 applied unchanged to the head, all 24 passed. - `full`, tracker gate run 383 (Implementer run 689's #1), passed at head d22af19 on a clean tree, on s32. Every step passed: - vitest (401/401); - tests/*.sx; - release with step9, and the deploy contract; - main Playwright config: 740 passed and 1 skipped, in 4.8 min; - runner Playwright config: 10 passed.
agra merged commit 1681a1c823 into master 2026-10-25 05:19:53 +02: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!140
No description provided.