Skip to content

queen: no backlog dispatch while finished work waits in review (review_first card, t27#10555) - #2046

Merged
gHashTag merged 2 commits into
queenfrom
queen-review-first
Oct 18, 2026
Merged

gHashTag merged 2 commits into
queenfrom
queen-review-first

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

Wires gHashTag/t27#10555 (spec PR gHashTag/t27#10562): the owner's rule that the Queen takes nothing from the backlog while finished work waits in review.

What it does

  • In runRound (queen-tick.ts), after the owner's assignments are put first and before queend is asked to choose, behind TRIOS_QUEEN_REVIEW_FIRST=on:
    • counts the review queue with the card's in_review_queue, over every started and finished queen_dispatch row. This is the review sweep's own filter, the one /queen/status counts as reviewable: review_state NULL or 'wait', not reaped, issue still open (all rows count as open before the board is read, as on the status page);
    • names each candidate's kind with kind_of (owner-assigned > review sent back > backlog) and keeps only those admits lets through. Send-backs and assignments are admitted at any queue length; backlog only while the queue is empty (REVIEW_QUEUE_MAX = 0);
    • when round_refused says the rule held every candidate, and queend's answer was not the capacity refusal, the tick's refusal reads <n> dispatches wait in review; the backlog is closed until the review queue is empty. That is what lastTick.refusal on /queen/status shows.
  • The filtered list is the one every later choose sees: the dispatch loop, the runner-only pass and the actors path (TRIOS_QUEEN_DISPATCH=actors).
  • Off (the default), candidates are exactly as before.

Why

Measured 2026-10-18 17:09Z on api.t27.ai/queen/status: 69 of 70 workers busy; last hour 102 dispatched, 56 finished, 11 reviewed; reviewable 29. About nine bees started per verdict, and each new bee held files the bees already in review needed when sent back.

Own-language budget

Hand-written TS: 38 added lines in queen-tick.ts, 0 deleted, no new foreign file. The card (byte-identical to t27 at sha256 c0ec4028...), its wasm (310 bytes, two builds, one hash) and queen-review-first-card.gen.ts (t27c gen-ts) are tool-written; PIN lines added.

Evidence and what is not verified

On the Railway lab: the card's 8 tests pass, the seal verifies, and 17 of 17 hand mutants are killed (gHashTag/t27#10562). The TypeScript wiring itself has not been executed: the lab has no bun, and nothing heavy runs on the Mac. CI on this PR is the first run of the changed TS.

Not in this PR

  • The Railway redeploy and setting TRIOS_QUEEN_REVIEW_FIRST=on on trios-agent-server (merging to queen does not deploy).

πŸ€– Generated with Claude Code

…w_first card, gHashTag/t27#10555)

Behind TRIOS_QUEEN_REVIEW_FIRST=on. After the owner's assignments are put
first, the round counts the review queue with the card's in_review_queue
(the sweep's own filter: started, finished, review_state NULL or 'wait',
not reaped, issue open) and keeps only the candidates the card admits:
send-backs and assignments at any queue length, backlog only when the
queue is empty. When the rule held every candidate and capacity was not
the reason, the tick's refusal reads "<n> dispatches wait in review; ...".

Card, wasm (310 bytes, two builds one hash) and gen.ts are tool-written;
38 hand-written TS lines added to queen-tick.ts, no new foreign file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tri-claw

tri-claw Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Summary by t27-bees

Checked by the t27 compiler

t27c parse, parse-complete and typecheck on each changed .t27 file at b6e70e2. Nothing was generated, built or run. A pass means the file is well formed, not that it is right.

  • trios/agent-server/specs/queen/review_first.t27: parses and typechecks.

Read by the model

This PR wires the "review first" rule (t27#10555) into the Queen's tick: when TRIOS_QUEEN_REVIEW_FIRST=on, the dispatcher counts the review queue using the sweep's own filter, admits owner assignments and review send-backs at any queue length, but blocks backlog candidates while the queue is non-empty, and surfaces a refusal message with the queue length.

Worth a look

  • queen-tick.ts:2047–2050 β€” The done query selects all finished dispatches (started = true AND finished_at IS NOT NULL) with no time window or limit, then filters in TypeScript. On a production database with months of history this could return millions of rows, causing slow queries, high memory use, or timeouts. The status page may have the same issue, but this PR adds a second hot-path execution of it every tick.

  • queen-tick.ts:2061–2063 β€” Send-back issues are detected from inFlight.rows (filtering review_state === 'sendBack'), but inFlight by name suggests in-progress dispatches, while the spec defines send-backs as "an issue whose last dispatch the review sent back" β€” a finished dispatch. The done result set (fetched just above) already contains review_state for finished rows; using inFlight here risks missing send-backs or picking up stale state, depending on what inFlight actually holds (not shown in the diff).

  • queen-tick.ts:2038–2041 β€” The review-first refusal message is suppressed when swiftCapacityAnswer(choice).answer is false (i.e., queend refused for capacity). If the rule blocked all candidates (so queend had an empty candidate list), queend may not return a "capacity" refusal at all β€” it may return "no candidates". The current logic would then show the review-first message (since swiftCapacityAnswer would presumably be true), which is correct. But if queend does return a capacity refusal despite an empty candidate list, the review-first reason is hidden. The diff doesn't show swiftCapacityAnswer, so the exact boundary is unclear.

  • queen-tick.ts:2055 β€” issuesNow?.has(Number(n)) ?? true defaults to "issue is open" when issuesNow is undefined (before the board read), matching the comment. However, if issuesNow is defined but empty (e.g., board read failed), all issues are treated as closed, incorrectly excluding them from the review queue. The diff doesn't show where issuesNow is initialized, so the failure mode can't be fully assessed.

  • queen-review-first-card.gen.ts:1 β€” This file is generated (t27c gen-ts). The comment warns edits are lost on rebuild. The diff adds it correctly, but any manual change here would be overwritten; the build/CI must regenerate it from review_first.t27 on every change.


Read: 5 files, +263 -0, the whole diff. Head b6e70e2. Model: openai-compatible/nvidia/nemotron-3-ultra-550b-a55b. Commands: @t27-bees review | summary | help | pause | resume. Free for every repository.

…through (t27#10555)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gHashTag

Copy link
Copy Markdown
Owner Author

Thanks. Taking the points in order:

  1. Condition at the refusal line: correct as written. swiftCapacityAnswer(choice).answer is false only for queend's exact capacity refusal (^N workers already running (limit M)$) and true for every other choice (see its doc comment). So reviewFirst && !choice.chosen && answer reads: the rule held candidates, nothing was chosen, and the reason was not capacity. Negating it would overwrite the capacity refusal, which is the RING-00 cross-check's input. The comment above it was ambiguous and now says this plainly.
  2. issuesNow null means open: intended. Before the board is read, /queen/status counts every row as open. The queue has to match that count, so the backlog stays closed and does not open on a read failure.
  3. sentBack from inFlight: covered. inFlight selects every started row in its window, finished ones included (finished_at, review_state, send_backs are selected for the send-back lease). A send-back older than that window would be read as backlog. That is the same window the lease already uses.
  4. kept / reaped: flag(!r.kept) is the card's reaped argument. IS TRUE maps a NULL outcome to not-reaped, as the sweep does.
  5. Unknown review_state maps to RS_OTHER: this is the sweep's filter. Only NULL and 'wait' are waiting for a verdict, so any other state is out of the queue by definition.

@gHashTag
gHashTag merged commit 929307c into queen Oct 18, 2026
18 checks passed
@github-actions

Copy link
Copy Markdown

βœ… Tests passed β€” 3915/3988

Suite Passed Failed Skipped
βœ… agent 429/429 0 0
βœ… build 9/9 0 0
βœ… cdp-protocol 5/5 0 0
βœ… eval 93/93 0 0
βœ… server-agent 280/280 0 0
βœ… server-api 2273/2345 0 72
βœ… server-browser 6/6 0 0
βœ… server-integration 10/11 0 1
βœ… server-lib 279/279 0 0
βœ… server-pglive 166/166 0 0
βœ… server-root 68/68 0 0
βœ… server-sim 8/8 0 0
βœ… server-skills 31/31 0 0
βœ… server-tools 244/244 0 0
βœ… shared 14/14 0 0

View workflow run

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