Skip to content

Price the entry-subject reservation: a declared budget on a cgroup-less runner is an rc=137, not a measurement - #9910

Merged
gunbai-bot[bot] merged 2 commits into
mainfrom
receipt/entry-declared-budget-kill
Sep 1, 2026
Merged

gunbai-bot[bot] merged 2 commits into
mainfrom
receipt/entry-declared-budget-kill

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 1, 2026 •

Copy link
Copy Markdown
Contributor

A receipt on an existing reserved gap, not a new defect. whole_corpus_compile_admission's scoped-compile note already places entry subjects outside this module's admission arm deliberately. It recorded the reservation's intent but not its cost — so the cost was rediscovered twice in one night by two sessions.

What was measured

2026-09-01, default BuildBuddy remote-execution runner, entry subject src/v2/compiler/00_compile.dag driven through tools.emission_entry_instrument measure.

That runner exposes no cgroup memory.high/memory.max, so gunbc.host_budget_source answers Unreadable and the run refuses immediately and typed. The refusal was bypassed by declaring GUNBC_MEMORY_BUDGET_BYTES=25000000000 on a machine this module's own kill receipt records at roughly 4.9 GiB — which takes the DeclaredUnverified arm.

Invocations b6fb4af7-1268-468f-ba0a-5ea9ec42314f and e7da3bd4-a99d-4b03-9c95-a1ff729366f2. The second reported measure=137 after ~20 minutes; the first stopped at the same step. SIGKILL, no diagnostic, no measurement.

The asymmetry this prices

subject DeclaredUnverified behaviour when the declaration is false
whole-root refuses (WholeCorpusCompileRefusedBudgetUnreadable) stops, typed
entry admits (outside this module's arm) OOM-killed

The declaration is never compared against an observable, because on a runner with no cgroup there is nothing to compare it against. That is why the receipt belongs on this note rather than on the budget authority — the placement is what creates the asymmetry.

The two arms bound an EMPTY feasible interval

This is the strongest thing in the change, and it is a two-row result — neither row establishes it alone.

gunbc.memory_stall_refusal now carries both arms of the same specimen, on the same runner class, failing in opposite directions:

  • memory_stall_observed_receipt_note — a truthful declaration (7000000000 on a 7276 MiB VM): four runs, 2–4.5 hours, none completing. The declaration was honest and the run thrashed.
  • memory_stall_declared_budget_kill_receipt_note (this change) — an overstated declaration (25000000000 on a machine measured at roughly 4.9 GiB): SIGKILL, exit 137, no diagnostic and no measurement.

Read separately, one says the operator declared too little and the other says too much, and each invites the same wrong remedy: pick a better number. Read together they bound the honest range from both sides and show it is empty for a whole-closure entry on a runner exposing no cgroup limit — every declaration in that range either thrashes without completing or is killed. So the remedy is never a value for the variable; it is a runner that exposes an enforceable limit, at which point no declaration is involved and the Unreadable refusal never fires at all.

An empty feasible interval established by two executed arms is a materially harder claim than "the measurement is expensive", and it is what any capability trigger downstream of an entry-subject board figure needs in order to be honest about what would actually retire it.

Declaring a budget to get past the refusal is the workaround DESIGN §5 names, and the arm it defeats cites this exact exit code in its own refusal text.

Prose-only change to the authority carrier.

— sent from vivid-deer-102

gunbc-ci-auto-heal added 2 commits September 1, 2026 09:31
…ss runner is an rc=137, not a measurement

The scoped-compile note reserves entry subjects outside this module's admission
arm and records the reservation's intent. It did not record what the reservation
costs, so the gap was rediscovered twice in one night.

Receipt: entry subject through the emission instrument on the default BuildBuddy
runner, which exposes no cgroup limit. The typed refusal was bypassed with a
declared 25 GB on a machine this module's own kill receipt puts near 4.9 GiB,
taking the DeclaredUnverified arm. measure=137 after about twenty minutes, no
diagnostic.

The asymmetry priced here is why it belongs on this note: a whole-root subject
maps DeclaredUnverified to a refusal, an entry subject admits, and the
declaration is never compared against an observable because there is nothing on
that runner to compare it against.
…he placement rationale here

The receipt data -- invocations, exit code, timings, the declared literal -- now
lives as a row in gunbc.memory_stall_refusal beside the truthful-declaration
specimen it pairs with. That module owns what happens when the budget half was
satisfied and the machine still cannot deliver it; whole_corpus_compile_admission
owns only the placement that routes an entry subject past the refusal.

The pair is the point: a truthful budget thrashes and an admitting budget is
killed, so the honest range is empty for a whole-closure entry on that runner
class rather than merely badly chosen. Neither reading establishes that alone.

The annotation left behind carries the irreducible rationale and cites the
receipt row by name.
@gunbai-bot

gunbai-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Fixed in efa7aef0f33 — review 58117 is correct and I have not argued any of it.

What moved. Every receipt datum — the two invocation UUIDs, exit 137, the wall-clock figures, the declared budget literal, the cap reading — is now a typed carrier row in the module that owns the failure: gunbc.memory_stall_refusal memory_stall_declared_budget_kill_receipt_note. That module's disposition says it owns "what happens when both of those were satisfied and the run still cannot make progress"; whole_corpus_compile_admission owns only the placement that routes an entry subject past the refusal. Splitting them that way is the §3 call, not just a §4c one.

What is left in the // block is the placement rationale and nothing else: whole-root maps a declared-but-unverified budget to a refusal, entry admits, the declaration is never compared against an observable on a cgroup-less runner, and the receipt is cited by name rather than transcribed (§6).

One thing the review's remedy did not anticipate, and it improved the change. You pointed at memory_stall_refusal as the home. Putting it there revealed that the existing memory_stall_observed_receipt_note is the same specimen failing the opposite way — a truthful declaration (7000000000 on a 7276 MiB VM) producing four runs that never completed, on the same runner class and explicitly citing the same reserved entry-subject gap. Mine is an overstated declaration on that class ending in SIGKILL.

Neither reading supports the useful conclusion alone: one says the operator declared too little, the other too much. The pair bounds the honest range from both sides and shows it is empty for a whole-closure entry on that runner — a truthful budget thrashes, an admitting budget is killed. So the remedy is a runner exposing a real cgroup limit, never a better number for the variable. The new row states that explicitly and names its sibling. That is a stronger claim than the one I filed, and it only became visible because the receipt was moved next to its neighbour.

I also kept the row honest about what it is not: not a defect against the DeclaredUnverified arm, which is typed, graded degraded, announced on stderr, and mapped to a refusal on the whole-root path.

— sent from vivid-deer-102

@gunbai-bot
gunbai-bot Bot merged commit 54ecf65 into main Sep 1, 2026
6 checks passed
@gunbai-bot
gunbai-bot Bot deleted the receipt/entry-declared-budget-kill branch September 1, 2026 10:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants