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

Kill a run past its budget: re-queued once, a card the second time (#1270) #1352

Merged opened this

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

Merged

A run that overruns its budget is now killed, re-queued once, and failed on the second overrun. The crew test that failed the check hasn't been re-run, because I can't run it here. The sandbox refuses unix sockets, so `test/crew.test.ts` can't start. I did run `test/check-budget.test.ts`, which passes. `bunx tsc --noEmit` couldn't run because it can't find the `bun` type definitions here.

shipped production is serving it deploy a9b30ef

opened this

A run that overruns its budget is now killed, re-queued once, and failed on the second overrun. The crew test that failed the check hasn't been re-run, because I can't run it here. The sandbox refuses unix sockets, so test/crew.test.ts can't start. I did run test/check-budget.test.ts, which passes. bunx tsc --noEmit couldn't run because it can't find the bun type definitions here.

What was wrong. The first overrun found the second one by comparing the run's env, commit_oid and branch with those of the earlier cancelled run. A reviewer notes its branch while it works, but its queued retry starts with an empty one. The retry therefore never matched its predecessor, so a second overrun was re-queued again instead of failing. That is my best guess at why "the second overrun fails it" failed. It comes from reading the code, not from a run.

What changed. overranBefore in src/core/runs.ts now looks for a cancelled budget: run one attempt lower in the same chain. That chain is the same kind, repo, reason and issue. Checks and the crew both queue the retry with attempt + 1, so both use the same match.

What's still open.

  • Test to watch. The forge's check on this push is the first real run of "a review run past its budget is queued again once". If it fails again, the log will show whether the cause is something other than this match.
  • Not done. The 15 min gate budget the issue asked about. Per the issue, the gate takes 18–25 min alone and 45 min beside another check, so BUDGETS.gate stays at 60 min until the gate is sharded under 15.
  • Not changed. No fast-tier budget, because there is no fast tier to measure.

Closes #1271

commented

The failure is the sandbox refusing to bind a unix socket (EPERM). It isn't the code. So I couldn't run this test locally, and I pushed without having seen it pass.

The vitals query-count test failed on expect(before).toBe(2), because the earlier budget change added a third constant query to vitals(): budgetFailures, which lists runs killed twice for their budget in the last day. The count doesn't grow with the number of runs, which is what the test is for. I updated the expected count to 3 and the comment to match, in test/vitals.test.ts. The forge's check on this push will be the first real run of that test.

Changes requested — before the latest push

The behaviour reads right (kill, requeue once, fail the second time, a vitals card for a day) and both paths have tests. One miss on the cleanliness bar: BUDGET_PREFIX is exported but nothing imports it, and the budget: literal is hard-coded in two SQL queries in src/core/runs.ts (overranBefore, budgetFailures). The prefix has three spellings and the constant is dead code. Fix first: make budgetSummary build its string from BUDGET_PREFIX, and have the two queries bind it as a parameter (summary LIKE ?1 || '%') instead of repeating the literal. Or delete the constant. Smaller points: the new import in src/crew/runner.ts sits among the actions imports, and overranBefore is out of order in the runs import list. The README says a reviewer is killed at review but not that the limit is 10 min; say it. I read the diff only and did not exercise the preview or view the screenshots.

commented

I've pushed the fixes for juniper's review to the same branch.

  • Prefix constant: budgetSummary in src/kernel/budgets.ts now builds its string from BUDGET_PREFIX. overranBefore and budgetFailures in src/core/runs.ts bind it as a parameter (summary LIKE ?N || '%'). The budget: prefix is spelled once in code, and the constant is used.
  • Imports: in src/crew/runner.ts the budgets import now sits with the kernel imports. overranBefore is back in alphabetical order in the runs import list.
  • README: it now says the gate limit is 60 min and the reviewer limit is 10 min.

The type check and test/check-budget.test.ts pass. test/vitals.test.ts can't run in this sandbox: it fails on a socket listen with EPERM, and it fails the same way with my changes stashed. So the budgetFailures change is checked only by the type check, not by that test. The forge's check will run it.

Approved — before the latest push

Approved. The change does what #1270 asks: a check past gate or a review run past review is killed with a plain budget: <what> took <n> min, limit <m>, queued again once, and failed on the second overrun. The vitals carry that failure as a need for a day. The budget lives in one small module (src/kernel/budgets.ts), the prefix is spelled once, and the README says why the gate limit is 60 min. Each path has a test that would fail without it (test/check-budget.test.ts, the new case in test/crew.test.ts), and the vitals query-count test was updated for the extra constant query. There is no new dependency, no new input surface and no new write door. I read the diff and did not exercise the preview, since the change has no page of its own.

Two things I would do next:

  1. Make the vitals card clearer and let it clear. A run was killed twice: budget: a full gate took 61 min, limit 60. reads like a log line. Name the repository and the pull, link the run, and drop the card once a later run of the same chain passes, rather than leaving it up for the full 24 h. A banner that outlives its fix is the red noise pillar 0 rules out.
  2. Back budgetFailures with an index, or filter on state and finished_at first. It runs on every vitals call and summary LIKE ? || "%" cannot use an index, so it scans every failed run in the last day. Also confirm that resumeLater after cancelRun in the review path does not cancel the run twice.
commented

The full gate on land was red; the pull is open again. Red tests:

  • the gate's list > every test/*.test.ts is in exactly one list, and every entry exists
  • the gate's list > every test/*.test.ts is in exactly one list, and every entry exists [0.64ms] [shard 186]
commented

I fixed the red gate by adding the new test file to the gate's list. I haven't run the full gate; I ran test/check-list.test.ts and test/check-budget.test.ts (10 pass) and left the rest to the forge's check on this push.

Cause: test/check-budget.test.ts was in neither GATE nor EXCLUDED in scripts/gate.ts. The "every test/*.test.ts is in exactly one list" guard failed on that.

Fix: I added test/check-budget.test.ts to GATE, where its budget tests now run on every push. I changed nothing else.

Not done from juniper's review: I left these out of this fix.

  • The clearer vitals card, with the repository and pull named, a link to the run, and clearing once a later run in the chain passes.
  • The index or earlier filter for budgetFailures.
  • Checking whether resumeLater after cancelRun in the review path cancels the run twice.

I can take them as a follow-up on this branch or as separate issues.

Approved

Approved. The change is backend-only (no new page, so the preview has nothing to show), and it does what #1270 asked: a check past its budget or a reviewer run past 10 min is killed with a plain budget: ... summary, queued once, and failed the second time. The vitals carry it as a need for a day. The budget lives in one small module, a test per path would fail without it, the gate list is fixed, and the README explains the 60 min gate (not the 15 min in the plan) from measurement. Two things I would do next: (1) make the vitals card actionable: name the repository and pull, link the run, and clear it once a later run in the chain passes, so it is not a nameless line for 24 h; (2) confirm the review path does not cancel the run twice (cancelRun here, then resumeLater), and give budgetFailures an index or earlier filter on finished_at so it stays cheap as runs grow. Neither blocks: no usability, security or terminal-parity issue found, as the need appears wherever vitals are read.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs