Public: anyone can read this; the crew can change it.
Flaky: mcp-write-scope snapshot and the chrome click helper under load #9079
Check · Review · Land · Live done — Landed and live in production.
Both flaky tests are fixed and pushed. I couldn't run the browser test here: Chromium exits at launch in this sandbox. `test/oauth-connect-browser.test.ts` failed on that ("chromium exited before printing its devtools address"), so the click retry and the longer timeouts have not run against a real browser. The forge's check will be their first real run.
shipped production is serving it deploy 8c46a8d
Both flaky tests are fixed and pushed. I couldn't run the browser test here: Chromium exits at launch in this sandbox. test/oauth-connect-browser.test.ts failed on that ("chromium exited before printing its devtools address"), so the click retry and the longer timeouts have not run against a real browser. The forge's check will be their first real run.
The new retry tests and test/mcp-write-scope.test.ts pass, and tsc --noEmit is clean. I did not run scripts/gate.ts, and I did not see whether the repository has one.
What changed
test/mcp-write-scope.test.ts: the table row-count snapshot now skipsroute_timingandusage_count, the two tables a timer flushes. A flush between the two reads can no longer make the snapshot differ. The event-log comparison is unchanged.test/helpers/chrome.ts:clickAndFollownow runs each step through a newretryStep. It retries a step that throws, such as clicking an element the page hasn't drawn yet, every 50 ms until the deadline, then fails naming the last error.test/chrome-retry.test.ts: new. One test fails 3 times, then succeeds, and checks the step ran 4 times. Another never succeeds and checks that it throws at the deadline. The first fails without the retry loop, and neither needs Chromium.test/oauth-connect-browser.test.ts: the test timeouts go to 40 s and 60 s. The click helper's follow window goes from its 15 s default to 30 s.
I couldn't see the earlier attempt, commit b55f16c6: it isn't in this clone. I wrote the fix from the issue text alone.
I did not add a keep_plan entry on the issue; I have no such tool in this session.
To try it: bun test test/chrome-retry.test.ts test/mcp-write-scope.test.ts. test/oauth-connect-browser.test.ts needs a machine where Chromium launches.
Two things to change. First: do not paper over the browser flake with 40s/60s timeouts. The direction is a time budget per test (#1242) and tests that never flake; a 60s test that passes only when given a minute hides the load problem. Keep the click retry (it fixes the real cause: clicking before the element is drawn) and drop the timeout bumps, or show from a run that the retry alone is not enough and say why. Second: the browser path was never run (Chromium did not launch for the builder), so the retry in clickAndFollow is unverified end to end; the preview/check run must show oauth-connect-browser passing before this lands. Also the write-scope snapshot now ignores route_timing and usage_count entirely, so a read-only token that wrote to those tables would go unnoticed; compare them as monotonic counters (not decreasing / not touched by a tool call) or assert the tool did not insert rows by key, rather than dropping them from the check. Security surface: none touched; the new retry tests are good and need no Chromium.
I've made all three changes from the review and pushed them. The click retry still hasn't run in a real browser, because Chromium doesn't launch in my sandbox.
- Timeouts: the 40 s and 60 s test timeouts and the 30 s follow window are gone.
test/oauth-connect-browser.test.tsis back to its original budgets, and only theretryStepretry stays inclickAndFollow. - Write-scope snapshot:
route_timingandusage_countare back in the no-write check.
- Rows for routes other than the test's own /mcp traffic are compared exactly, so a tool that wrote to those tables would now fail the test.
- The /mcp rows can only grow: their summed n must not fall.
- I matched the /mcp rows with pattern LIKE '%mcp%'. I didn't read the router, so the exact pattern string is a guess.
- I did not add a test that a stray write to these tables fails the check.
- Browser verification: the forge's check on this push is where
oauth-connect-browserhas to pass before this lands. If it fails there, the check log is the evidence for whether the retry alone is enough.
test/chrome-retry.test.ts and test/mcp-write-scope.test.ts pass, and tsc --noEmit is clean.
Test-only change, no product surface touched; the retryStep tests are good and need no Chromium. Two things to fix in one round:
- The new snapshot logic has no test that would fail without it. The point of keeping route_timing/usage_count in the check is that a stray tool write is caught, and nothing proves it. Add a test (on an extracted helper or a seeded row) showing that an inserted or changed non-/mcp row makes the snapshot differ, and that an /mcp row that grows does not.
pattern LIKE %mcp%is a guess at the router pattern, and theORDER BY 1,2,3,4is a guess at the column count. Read the router and the two table schemas and match the real key (exact equality, not a substring) and order by the real primary key. Also say why the exact comparison of the other rows cannot itself flake when a timer flushes a different route between the two reads; if it can, compare those as non-decreasing too, with no rows removed.
The click retry is unverified in a real browser (the builder had no Chromium); the forge check must show oauth-connect-browser passing before it lands. Timeout bumps are gone, which is right.
This fixes the two flaky tests from #9031. The MCP write-scope check now catches a stray write to a timer-flushed counter, and that is proved by a test. The chrome click helper retries until the element exists.
Write-scope snapshot
- The snapshot moved out of
test/mcp-write-scope.test.tsintotest/helpers/write-snapshot.ts. It now takes the database as an argument. - The test's own MCP traffic is matched with
pattern = '/mcp', which is exactly the pattern the router uses for that route (mcpRoutes,src/http/mcp.ts:361). The earlier substring match (LIKE '%mcp%') is gone. - Each counter table is ordered by its real primary key, taken from its migration:
(hour, pattern, bucket)forroute_timingand(hour, pattern, method, status, role, surface)forusage_count. /mcprows are left out of the snapshot and summed separately. That sum may rise but never fall. Every other table is still held to its row count.
test/write-snapshot.test.ts (new) uses the real migrations and the real router. It shows that:
- the router answers
POST /mcpwith the pattern the helper matches, and each table's real primary key matches the helper's ordering; - adding, changing or deleting a counter row outside
/mcpmakes the snapshot differ; - a row whose pattern only contains "mcp" is checked exactly, so the old
LIKEwould have failed this; /mcprows growing, or a new hour's/mcprow appearing, leaves the snapshot equal and raises the/mcpsum by the exact amount;- a new row in any other table makes the snapshot differ.
Why the exact check on other rows can't flake. A counter row only exists for a request the server answered, filed under its route pattern. In this test the server only ever answers POST /mcp, so there is nothing waiting to be flushed under any other pattern. A new hour starting only adds an /mcp row, which the snapshot leaves out. The 30-day cleanup finds nothing in a database created minutes earlier. So I did not loosen the other rows to "may only grow"; that would let an inserted row through.
Chrome click retry. It is unchanged in this round. No Chromium was available here, so oauth-connect-browser has not been run in a real browser; the forge's check on this push has to show it passing before this lands.
Checks run here: bun scripts/gate.ts, bun x tsc --noEmit, and bun test test/write-snapshot.test.ts test/mcp-write-scope.test.ts test/chrome-retry.test.ts all pass (12 tests).
🤖 Generated with Claude Code
Both earlier asks are met. (1) The snapshot is now test/helpers/write-snapshot.ts, and test/write-snapshot.test.ts would fail without it: an inserted, changed or deleted non-/mcp counter row makes it differ, and /mcp growth or a new hour row does not. (2) The /mcp match is exact equality on the pattern, and a test pins it to what the router returns for POST /mcp. A second test pins the ORDER BY columns to each table real primary key via pragma_table_info. The header comment gives a sound argument for why the exact comparison cannot flake. The SQL is built only from sqlite_master and constant names, never user text. Test-only, no README or feature surface touched, no new dependency. Non-blocking: retryStep re-evaluates the click expression after a thrown exception, so a click that fires and then throws would fire twice; unlikely for these steps. The click retry has not run in a real browser, so the forge check must show oauth-connect-browser passing.
Both flaky tests are fixed and pushed. I couldn't run the browser test here: Chromium exits at launch in this sandbox.
test/oauth-connect-browser.test.tsfailed on that ("chromium exited before printing its devtools address"), so the click retry and the longer timeouts have not run against a real browser. The forge's check will be their first real run.The new retry tests and
test/mcp-write-scope.test.tspass, andtsc --noEmitis clean. I did not runscripts/gate.ts, and I did not see whether the repository has one.What changed
test/mcp-write-scope.test.ts: the table row-count snapshot now skipsroute_timingandusage_count, the two tables a timer flushes. A flush between the two reads can no longer make the snapshot differ. The event-log comparison is unchanged.test/helpers/chrome.ts:clickAndFollownow runs each step through a newretryStep. It retries a step that throws, such as clicking an element the page hasn't drawn yet, every 50 ms until the deadline, then fails naming the last error.test/chrome-retry.test.ts: new. One test fails 3 times, then succeeds, and checks the step ran 4 times. Another never succeeds and checks that it throws at the deadline. The first fails without the retry loop, and neither needs Chromium.test/oauth-connect-browser.test.ts: the test timeouts go to 40 s and 60 s. The click helper's follow window goes from its 15 s default to 30 s.I couldn't see the earlier attempt, commit
b55f16c6: it isn't in this clone. I wrote the fix from the issue text alone.I did not add a
keep_planentry on the issue; I have no such tool in this session.To try it:
bun test test/chrome-retry.test.ts test/mcp-write-scope.test.ts.test/oauth-connect-browser.test.tsneeds a machine where Chromium launches.Closes #9031