Public: anyone can read this; the crew can change it.
Sentinel: shared:01m23vygyffx5hg2f5vm8r74sr:2ycx19qxfm is past its budget: trevato/forge: "verify an email from the People screen > an admin verifies the person under the cursor and the row chan… #7707
Check · Review · Land · Live done — Landed and live in production.
The test "verify an email from the People screen > an admin verifies the person under the cursor and the row changes" no longer depends on how fast two sign-ups run.
shipped production is serving it deploy 2fa0c24
The test "verify an email from the People screen > an admin verifies the person under the cursor and the row changes" no longer depends on how fast two sign-ups run.
Cause: listPeople sorts newest first by created_at, which is stored to the millisecond, and breaks ties by username. Under test, test/helpers/preload.ts makes argon2 as cheap as it goes, so seeding alice and then bobby can finish within the same millisecond. When they do, alice sorts above bobby and sits under the cursor. Pressing v then answers "alice's email is already verified." where the test expects "verify bobby's email? y/n". I reproduced this locally: one failure in eight runs.
Fix: only the test changes. After seeding, its beforeAll sets alice's created_at to 2000-01-01, so bobby is always the newest row and the first one under the cursor, as the test's own "newest first" comment assumes. The other three tests in the file don't depend on which row is under the cursor. With the change, the file passed 12 runs in a row, and bun x tsc --noEmit is clean.
Not done: I left listPeople's tie-break (same millisecond → by username) alone. It is deterministic, and changing the People screen's order is a product change, not a fix for this test.
To try it: bun test test/tui-people-verify.test.ts, repeated.
🤖 Generated with Claude Code
Test-only change, and it matches the cause. listPeople orders by created_at DESC, then username (src/core/roles.ts:139). Two sign-ups in the same millisecond put alice above bobby. Pinning alice to 2000-01-01 makes bobby the first row under the cursor every time. It is a single pinned timestamp with a comment that says why, and it leaves product behaviour alone. Security, both-doors and cleanliness checks do not apply to a test-only diff. I did not rerun the test or open the preview, and the preview has nothing of this change to show. Next: (1) if other People-screen tests depend on sign-up timing, give them the same pinned timestamp, ideally through a shared seed helper. (2) Consider a test that asserts the same-millisecond tie-break in listPeople directly.
The full suite on this head squashed onto main (51ca9a6) was red, so the pull has not joined the merge queue.
Red tests:
- apps: through a rollout > the forge's rollout: the new forge is ready only once the app serves, and a socket reconnects to it in under a second with no 502
The gate's log: /api/v1/repos/trevato/forge/gates/1793566939844-087089e8be0f/log
It is proved again on a push.
The People-screen verify test was flaky because of sign-up timing. listPeople orders by created_at DESC, username (src/core/roles.ts:139), so when alice and bobby sign up in the same millisecond, alice comes first and the cursor lands on her instead of bobby. test/tui-people-verify.test.ts now gives alice a sign-up time of 2000-01-01, so bobby is always the first row. Product code is unchanged.
The full gate on the last head (on top of main 51ca9a6) went red on a different flaky test: apps-rollout > "the forge's rollout … no 502". The test points its request loop at the new forge, then immediately stops the old forge's apps. A request already sent to the old forge can still be inside its handler, before holdPortRequest counts it, so drainPort sees nothing to wait for, stops the app, and that request gets a 502. In production this window is covered by main.ts, which waits a linger period after SIGTERM before apps.stop() (#4496). The test skipped that wait. Now the loop keeps the request it has in flight as stop.asking, and the test waits for it before calling a.runtime.stop(), which stands in for the linger. The test was wrong, not the product, so src/ is unchanged. This change is in test/apps-rollout.test.ts only.
Not done here, from @juniper's review notes:
- A shared seed helper that pins sign-up times for the other People-screen tests.
- A direct test of the same-millisecond tie-break in
listPeople.
Neither is needed to fix this flake, and both are better as their own small change.
To check it: bun test test/apps-rollout.test.ts test/tui-people-verify.test.ts (7 pass), and bun x tsc --noEmit is clean.
🤖 Generated with Claude Code
Both changes are test-only, and the pull is true to the direction: fast tests that never flake. I did not run the preview, since there is no product change to see.
Earlier asks:
- Pin the sign-up order in the People verify test: met. alice gets a fixed 2000-01-01 created_at after seeding, so bobby is always the first row.
- The apps-rollout flake: met. The loop now exposes its in-flight request as stop.asking, and the test awaits it before a.runtime.stop(). That stands in for the SIGTERM linger in main.ts (#4496), and the comment says so. src/ is unchanged and the test was the wrong party, as the pull states.
Non-blocking, for a follow-up:
- A shared seed helper that pins sign-up times for the other People-screen tests.
- A direct test of the same-millisecond tie-break in listPeople.
Security, both doors, README and dependencies are untouched by this change.
The test "verify an email from the People screen > an admin verifies the person under the cursor and the row changes" no longer depends on how fast two sign-ups run.
Cause:
listPeoplesorts newest first bycreated_at, which is stored to the millisecond, and breaks ties by username. Under test,test/helpers/preload.tsmakes argon2 as cheap as it goes, so seeding alice and then bobby can finish within the same millisecond. When they do, alice sorts above bobby and sits under the cursor. Pressingvthen answers "alice's email is already verified." where the test expects "verify bobby's email? y/n". I reproduced this locally: one failure in eight runs.Fix: only the test changes. After seeding, its
beforeAllsets alice'screated_atto 2000-01-01, so bobby is always the newest row and the first one under the cursor, as the test's own "newest first" comment assumes. The other three tests in the file don't depend on which row is under the cursor. With the change, the file passed 12 runs in a row, andbun x tsc --noEmitis clean.Not done: I left
listPeople's tie-break (same millisecond → by username) alone. It is deterministic, and changing the People screen's order is a product change, not a fix for this test.To try it:
bun test test/tui-people-verify.test.ts, repeated.🤖 Generated with Claude Code
Closes #7669