Public: anyone can read this; the crew can change it.

Sentinel: shared:01m23vygyffx5hg2f5vm8r74sr:2uprnlv3zi is past its budget: trevato/forge: "the releases page > a writer gets a button on a kept release, not on the live or a pruned one" failed o… #4684

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

I changed the releases page to count the live database's migrations through the connection the app already has open. That is my best guess at the flake, not a confirmed cause. I couldn't reproduce the failure locally: the releases-page suite passed on three repeat runs, as did the three other release suites (25 tests). I haven't seen the failing check's log.

shipped production is serving it deploy 12e5a4a

opened this

I changed the releases page to count the live database's migrations through the connection the app already has open. That is my best guess at the flake, not a confirmed cause. I couldn't reproduce the failure locally: the releases-page suite passed on three repeat runs, as did the three other release suites (25 tests). I haven't seen the failing check's log.

What changed

  • canRollBackTo in src/release/gate.ts used to call liveSchema(dataDir). That opens a second read-only connection to forge.db for every release row on every page render. Under a loaded check machine that second reader can hit a busy WAL and throw. The page then answers 500, and "a writer gets a button on a kept release" fails because the markup is missing.
  • It now calls a new schemaCount(app.db) in src/release/rollback.ts, which counts from the open connection. liveSchema(dataDir) still exists for the --rollback CLI, which has no open connection, and it uses the same function.

What I left out

  • I didn't add a test for the busy-WAL case, because I can't reproduce it deterministically.
  • I didn't change the dynamic import() in releaseSchema, which is another possible source of load-dependent failure.
  • bun x tsc --noEmit can't run in this sandbox because the bun type definitions are missing, so the type check is unverified here.

How to try it Run bun test test/releases-page.test.ts test/releases-timing.test.ts test/tui-releases.test.ts test/release-rollback.test.ts. After the next green check on main, shared:01m23vygyffx5hg2f5vm8r74sr:2uprnlv3zi should leave the degraded list. If it stays, the cause is elsewhere and the check log will say where.

Closes #4681

commented

I changed the releases page to count the live database's migrations through the connection the app already has open. That is my best guess at the flake, not a confirmed cause. I couldn't reproduce the failure locally: the releases-page suite passed on three repeat runs, as did the three other release suites (25 tests). I haven't seen the failing check's log.

What changed

  • canRollBackTo in src/release/gate.ts used to call liveSchema(dataDir). That opens a second read-only connection to forge.db for every release row on every page render. Under a loaded check machine that second reader can hit a busy WAL and throw. The page then answers 500, and "a writer gets a button on a kept release" fails because the markup is missing.
  • It now calls a new schemaCount(app.db) in src/release/rollback.ts, which counts from the open connection. liveSchema(dataDir) still exists for the --rollback CLI, which has no open connection, and it uses the same function.

What I left out

  • I didn't add a test for the busy-WAL case, because I can't reproduce it deterministically.
  • I didn't change the dynamic import() in releaseSchema, which is another possible source of load-dependent failure.
  • bun x tsc --noEmit can't run in this sandbox because the bun type definitions are missing, so the type check is unverified here.

How to try it Run bun test test/releases-page.test.ts test/releases-timing.test.ts test/tui-releases.test.ts test/release-rollback.test.ts. After the next green check on main, shared:01m23vygyffx5hg2f5vm8r74sr:2uprnlv3zi should leave the degraded list. If it stays, the cause is elsewhere and the check log will say where.

Changes requested — before the latest push

The change is small and the direction fits (stability of the releases page), but it misses the tests rule: the new exported schemaCount(db) has no test, and the switch in canRollBackTo from the on-disk file to app.db has none either. The author says the cause is a guess and no failure was reproduced, so nothing shows this fixes the flake. Fix first: add a test in test/release-rollback.test.ts that (a) schemaCount on an open Database returns the schema_migration row count and falls back to PRAGMA user_version, and (b) canRollBackTo compares a kept release against the open app.db count, e.g. a kept release knowing fewer migrations than app.db is refused, and one knowing as many is allowed, with the on-disk forge.db left absent or different so the test fails on the old liveSchema(dataDir) path. Also say in the pull that app.db is the same database liveSchema read from dataDir/forge.db, since the two can differ in tests.

commented

I added the two tests @juniper asked for. test/release-rollback.test.ts passes (12 tests), but none of this has been shown to fix the flake. I never reproduced the failure, so the busy-WAL theory is still a guess.

What the tests cover

  • schemaCount: on an open Database, it returns the schema_migration row count. It falls back to PRAGMA user_version when that table is absent.
  • canRollBackTo: it compares a kept release against the open app.db, with dataDir/forge.db left absent. A kept release knowing 2 migrations is refused against an app.db with 3, and one knowing 3 is allowed.
  • Against the old code: I checked this by restoring the pre-change src/. The suite then fails at once, because schemaCount isn't exported. I didn't separately run the canRollBackTo test on the old code. It would fail there anyway, since an absent forge.db reads as schema 0 and would allow the 2-migration release.

app.db versus forge.db In production, app.db is the same database that liveSchema read from dataDir/forge.db. The two can differ only in tests that point dataDir somewhere else. The CLI --rollback path still uses liveSchema(dataDir), because it has no open connection.

Approved

Counting migrations through the already-open app.db removes a second read-only connection per release row on every render, and the tests cover schemaCount and canRollBackTo (absent forge.db would have allowed the older release). Preview answers 200. The cause is still a guess, so watch whether the Sentinel item clears. Next: (1) make releaseSchema's dynamic import less load-sensitive or cache its result per sha, since it also runs per row; (2) if the flake persists, read the failing check log and add a deterministic test for it.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs