Skip to content

feat(substrate): a queued execution past maxQueueAgeMs times out; ADRs 0004, 0010, 0012 match the code - #159

Merged
debuggingfuture merged 1 commit into
mainfrom
fix/substrate-queue-age
Sep 24, 2026
Merged

debuggingfuture merged 1 commit into
mainfrom
fix/substrate-queue-age

Conversation

@debuggingfuture

@debuggingfuture debuggingfuture commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

A consumer that queues for a substrate sandbox now gets the queue-age ceiling it asks for, and four ADR statements match what the substrate does.

Problem & Insight

  • AdmissionMode carries {mode:'queue', maxQueueAgeMs} and ADR-0004 promises a typed queue timeout, but nothing in apps/substrate read the value. A queued execution could not time out in the substrate, and a consumer that abandoned its wait left a queue row that only lapsed through the waiter TTL. No consumer queues today: the dispatcher's runtime adapter and fractalbot both call ensureSandbox in refuse mode, and the dispatcher enforces its own ceiling in packages/core/src/run-admission.ts. The change takes effect for the first consumer that opts into queue mode.
  • ADR-0004 described the ticket as an HMAC over "executionKey + pool". It signs consumer, key, pool and expiry, and verifyTicket checks consumer and key, so one consumer cannot boot with another's ticket.
  • ADR-0010 recorded pool selection as shipped from the recipe. classFor reads the consumer only, which leaves the browser and agent classes deployed and unselectable.
  • ADR-0012 and the contract's doc comment named the lost-process status unknown. The type and sandbox-do.ts use gone.

Take

  • ensureSandbox in queue mode refuses an execution that has waited maxQueueAgeMs or longer with timedOut: true and releases its row. Under the ceiling the row stays and the refusal keeps retryAfterMs. timedOut is an optional field on an output type, so CONTRACT_VERSION holds (per apps/docs/substrate/contract-versioning.md).
  • describeRefusal in runtime-cf renders a timeout distinctly from a busy pool.
  • The ADRs are Proposed, so the text is corrected in place. ADR-0010 is marked partial rather than implemented: recipe-based selection waits for the dispatcher's run catalog to move onto the facade, and removing the two unused classes would need a Durable Object migration.
  • The value gone stays; renaming it would be a breaking change to fix a comment.

Key actions

  • facade.workers.test.ts covers both sides of the ceiling. The timeout test fails without the facade change.
  • Lint, typecheck, unit and workers suites pass; the facade API reference is regenerated.
  • fractalbot's vendored contract copy (vendor/substrate-contract) is byte-checked against this file in its CI; refresh the copy and its pin after merge. The change is an additive optional field, so no call site in fractalbot changes.

…loses its row

ensureSandbox in {mode:'queue'} refuses an execution that has waited
maxQueueAgeMs or longer with `timedOut: true` and releases its queue row;
under the ceiling the row stays and the refusal carries retryAfterMs as
before. `timedOut` is an optional field on an output type, so
CONTRACT_VERSION holds.

ADR text matches the code: ADR-0004 names the ticket's signed fields
(consumer, key, pool, expiry) and the queue timeout, ADR-0010 is `partial`
with consumer-only pool selection, and ADR-0012 and the contract comment
name the detached status `gone`.
@debuggingfuture
debuggingfuture marked this pull request as ready for review September 24, 2026 08:31

@flaredispatch-fractalboxdev flaredispatch-fractalboxdev Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI code review — ✅ Approve

Risk tier: lite · 0 critical · 0 warnings · 0 suggestions

Reviewers: security 0 · code-quality 0 · performance 0 · documentation 0

No findings.

📋 View full logs & reviewed diff ↗

@debuggingfuture
debuggingfuture merged commit d303b2b into main Sep 24, 2026
6 checks passed
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.

1 participant