fix(supervise): a refused spawn names the channel and the amounts - #1271
Merged
Merged
Conversation
A budget-exhausted reservation now carries shortfall { channel,
requested, free } (ReservationShortfall, exported), scope.spawn passes
it through, and spawn_worker returns it with a reason a driver can act
on: "the run pool has 58 iterations free and this spawn asked for
budget.maxIterations 100; spawn again with budget.maxIterations at most
58, or ask the caller for a larger root budget". A channel closed by
unmeasured spend says no smaller request fits.
Measured 2026-09-16 on a Discovery director placed on the Tangle
sandbox: its first research child asked for 100 iterations against a
60-iteration pool, was told "the run has no allocation left to give
this worker", spent a 3-iteration probe child to learn the pool still
had room, and then moved its research to local processes.
The same sentence also answered every other refusal: max-live-workers,
depth-exceeded, duplicate-key, key-conflict, invalid-identity and
scope-aborted each read as an empty pool. Each now names its own cause.
The usd-unbudgeted, in-doubt and scope-settled texts are unchanged.
Tests: tests/runtime/spawn-refusal-shortfall.test.ts (pool shortfall per
channel, the scope.spawn pass-through on a real supervisor, the driver
text, and non-budget refusals) fails 5 of 5 on the unmodified source.
Eleven existing assertions that compared a refusal exactly now pin the
amounts. Full suite 4124 passed, 11 skipped; lint and api surface clean.
Review of #1271 found the first version overclaimed. A refusal named only the first channel that did not fit, so a driver that shrank that request could be refused again on a channel it was never told about. And "spawn again with budget.maxTokens at most N" was false for tokens and dollars: a driver's next turn is metered from the same pool before its retry reaches admission, so a retry at exactly N is refused again (reproduced with a scripted driver: 20000 -> "at most 9850" -> 9850 -> "at most 9700" -> never admitted). - reserve() now returns shortfalls: every channel that does not fit. Resource validation throws before any shortfall is computed. usd-unbudgeted still yields to an exhausted channel. - Iterations and named resources say "at most N fits"; driver turns charge neither. Tokens and dollars say N is free right now and to ask for well under it. - A channel closed by unmeasured spend says the run admits no further spawn at any budget (it closes every spawn, not only larger ones). - max-live-workers no longer tells a driver to cancel a worker (drivers have no cancel verb); scope-aborted names the intensity breaker; invalid-identity says to spawn again without a key. Tests: new cases for multi-channel shortfalls and the tokens/dollars advice; two existing assertions now also carry the iterations shortfall they always had. Full suite 4127 passed, 11 skipped; lint, tsc, build and api surface clean.
Contributor
Author
|
Addressed an independent review (4 agents, one finding reproduced by a verifier): the tokens/usd "at most N" advice was false because driver turns meter from the same pool before a retry; refusals named only the first short channel; and five non-budget texts named the wrong next step. All fixed in the latest commit (shortfall -> shortfalls, per-channel advice). Local: 4127 passed / 11 skipped, lint, tsc, build, api surface clean. I am cutting v0.237.0 from the merged main tip once CI is green. |
The review commit renamed shortfall to shortfalls but the generated API reference still described the first version, which failed the docs freshness gate in CI. Regenerated with pnpm run docs:api; docs:freshness passes locally.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
spawn_workeranswered a budget refusal with "the conserved pool refused this spawn (budget-exhausted); the run has no allocation left to give this worker". It named no channel and no amounts. It was also the answer for every other refusal kind.Measured 2026-09-16 on a Discovery director placed on the Tangle sandbox (
mech-interp-foundations-sandbox-a-20260916b): its first research child asked formaxIterations: 100against a 60-iteration pool. The director spent a 3-iteration probe child to learn the pool still had room, concluded the pool could not fund real work, and moved its research to local processes.Change
BudgetPool.reservereturnsshortfall: { channel, requested, free, closedByUnknownSpend? }withbudget-exhausted(ReservationShortfall, exported).freenever reads negative.scope.spawnpasses it through.spawn_workerreturns it, with a reason naming the largest request that fits:the run pool has 58 iterations free and this spawn asked for budget.maxIterations 100; spawn again with budget.maxIterations at most 58, or ask the caller for a larger root budget.max-live-workers,depth-exceeded,duplicate-key,key-conflict,invalid-identity,scope-abortedeach get their own reason instead of the empty-pool sentence.usd-unbudgeted,in-doubt,scope-settledtexts are unchanged.release:preparerun; CHANGELOG, api-surface, docs updated).A consumer that compared a refusal with
toEqual({ ok: false, reason: 'budget-exhausted' })now also receivesshortfall; eleven such assertions in this repo now pin the amounts.Proof (local)
tests/runtime/spawn-refusal-shortfall.test.ts: pool shortfall per channel, pass-through on a real supervisor, driver text, non-budget refusals. Fails 5 of 5 withsrc/stashed.biome check: clean.build+check:api-surface: clean.Release: I will cut v0.237.0 from the merged main tip and say so here before tagging. #1270 is open on unrelated files; if it merges first I will rebase and re-run.
🤖 Generated with Claude Code