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

Each release counts the crew runs it interrupted, and the release card shows the number #11922

opened this

Check · Review · Land · Live — Its check is running. Next: reviewer, no review yet.

Ready to land

Each swap release now records how many crew runs were still running in the old process when the switch drained it. The count shows on `/releases` beside the stage timings, e.g. "… · switch 1 s · interrupted 2 runs · verify …". `release_keeper` and `GET /api/v1/keeper` return it as `interruptedRuns`.

7 files · +80 −8

working checking now deploy 0018ca1

Check running · 4 min · 3963 passed, 0 failedCheck of 0018ca1checked against main at 50667a9fast tier: running · full gate runs on land

Website spec: 23 findings (report only)
opened this

Each swap release now records how many crew runs were still running in the old process when the switch drained it. The count shows on /releases beside the stage timings, e.g. "… · switch 1 s · interrupted 2 runs · verify …". release_keeper and GET /api/v1/keeper return it as interruptedRuns.

  • Migration 20261113120000-keeper-interrupted-runs adds a nullable interrupted_runs column to keeper_release, and it is pinned. Null means the release didn't count, so older releases and kube-mode releases show nothing rather than a false "0 runs".
  • src/keeper/record.ts: new keepInterrupted(db, id, runs) takes the count as a plain number and writes it only on a release that is still rolling, the same rule as keepTimings.
  • src/keeper/wire.ts: the swapper's timed callback, which runs just before the drain, is now an exported switched(db, runs). It writes the timings and then the count from runningAgentRuns() (src/crew/running.ts, this process's registry of agent runs in flight). It was pulled out so a test can call it directly.
  • src/keeper/landed.ts: the stage line includes the count. The card's text comes from this line, so src/web/pages/keeper-panel.ts is unchanged and the design lint doesn't apply.
  • src/http/mcp/tools/release_keeper.ts: the tool's doc now describes the new field.

Not done:

  • The number is the runs in flight at the moment of the switch. The drain still lets them finish (crew.stop({ drain: true })), so it counts runs the switch disturbed, not ones confirmed killed.
  • Kube-mode releases don't count anything.
  • The release workflow and the chart are untouched.

Tests:

  • test/keeper-interrupted-runs.test.ts: two runs in flight at the switch record 2, and both the panel and keeperAnswer report it. A quiet switch says "interrupted 0 runs", and a release that never counted says nothing.
  • bun scripts/gate.ts and bun x tsc --noEmit pass.
  • scripts/fast.ts named 1,908 test files because the change adds a migration, so I ran 29 keeper, release, schema, swap and MCP-tool test files plus the migration-pin test. The pin test failed once until the new migration was pinned; everything passes now.

To try: after a swap release, open /releases and read the release keeper table's notes row.

🤖 Generated with Claude Code

Closes #11917

commented

Each swap release now records how many crew runs were still running in the old process when the switch drained it. The count shows on /releases beside the stage timings, e.g. "… · switch 1 s · interrupted 2 runs · verify …". release_keeper and GET /api/v1/keeper return it as interruptedRuns.

  • Migration 20261113120000-keeper-interrupted-runs adds a nullable interrupted_runs column to keeper_release, and it is pinned. Null means the release didn't count, so older releases and kube-mode releases show nothing rather than a false "0 runs".
  • src/keeper/record.ts: new keepInterrupted(db, id, runs) takes the count as a plain number and writes it only on a release that is still rolling, the same rule as keepTimings.
  • src/keeper/wire.ts: the swapper's timed callback, which runs just before the drain, is now an exported switched(db, runs). It writes the timings and then the count from runningAgentRuns() (src/crew/running.ts, this process's registry of agent runs in flight). It was pulled out so a test can call it directly.
  • src/keeper/landed.ts: the stage line includes the count. The card's text comes from this line, so src/web/pages/keeper-panel.ts is unchanged and the design lint doesn't apply.
  • src/http/mcp/tools/release_keeper.ts: the tool's doc now describes the new field.

Not done:

  • The number is the runs in flight at the moment of the switch. The drain still lets them finish (crew.stop({ drain: true })), so it counts runs the switch disturbed, not ones confirmed killed.
  • Kube-mode releases don't count anything.
  • The release workflow and the chart are untouched.

Tests:

  • test/keeper-interrupted-runs.test.ts: two runs in flight at the switch record 2, and both the panel and keeperAnswer report it. A quiet switch says "interrupted 0 runs", and a release that never counted says nothing.
  • bun scripts/gate.ts and bun x tsc --noEmit pass.
  • scripts/fast.ts named 1,908 test files because the change adds a migration, so I ran 29 keeper, release, schema, swap and MCP-tool test files plus the migration-pin test. The pin test failed once until the new migration was pinned; everything passes now.

To try: after a swap release, open /releases and read the release keeper table's notes row.

🤖 Generated with Claude Code

commented

Each release now counts the crew runs its switch interrupted, and shows that number next to the stage timings in the release keeper table on /releases, in the MCP release_keeper tool and on the landed record.

  • Counting: just before the swap drains, switched() in src/keeper/wire.ts saves the build, proof and switch timings as before. It also saves how many crew runs are still running on the release that is rolling out (keepInterrupted in src/keeper/record.ts).
  • Storage: a migration adds the column, with its migration pin.
  • Tests: test/keeper-interrupted-runs.test.ts covers the count being saved and shown.

This merges main. The only conflict was in src/keeper/wire.ts: main added phonePages() in the same place this branch added switched(). Both functions are kept, and the swapper's timed hook still goes through switched().

The gate script and bun x tsc --noEmit pass. scripts/fast.ts could not narrow the diff after the merge, so I ran the test files that cover the keeper and swap by hand: keeper-interrupted-runs, releases-timing, release-keeper-swap, release-keeper-cadence and keeper-covered. All 44 tests in them pass. The forge's check runs the full suite on this push.

Try it: after a release goes out by swap, open /releases. The release keeper table shows "interrupted N runs" next to the switch time.

🤖 Generated with Claude Code

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs