Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Generated by `t27c gen-ts` from review_first.t27. Do not edit.
//
// Every name, value and type here comes from that spec. Change the spec and
// regenerate; an edit made here is lost the next time anyone builds.

export const KIND_BACKLOG = 0 satisfies number;
export const KIND_REWORK = 1 satisfies number;
export const KIND_ASSIGNED = 2 satisfies number;
// t27c gen-ts: fn kind_of was not emitted -- this backend lowers declarations, not bodies.
export const RS_NONE = 0 satisfies number;
export const RS_WAIT = 1 satisfies number;
export const RS_OTHER = 2 satisfies number;
// t27c gen-ts: fn in_review_queue was not emitted -- this backend lowers declarations, not bodies.
export const REVIEW_QUEUE_MAX = 0 satisfies number;
export const R_ADMIT = 0 satisfies number;
export const R_REVIEW_FIRST = 1 satisfies number;
export const REFUSAL_TAIL = " dispatches wait in review; the backlog is closed until the review queue is empty" satisfies string;
// t27c gen-ts: fn backlog_open was not emitted -- this backend lowers declarations, not bodies.
// t27c gen-ts: fn admission was not emitted -- this backend lowers declarations, not bodies.
// t27c gen-ts: fn admits was not emitted -- this backend lowers declarations, not bodies.
// t27c gen-ts: fn round_refused was not emitted -- this backend lowers declarations, not bodies.
// t27c gen-ts: a TestBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a TestBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a TestBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a TestBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a TestBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a TestBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a TestBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a TestBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a InvariantBlock was not emitted -- it is checked by the compiler, not by the artifact.
// t27c gen-ts: a InvariantBlock was not emitted -- it is checked by the compiler, not by the artifact.

// Declaration order, which the spec's own laws depend on.
export const __STRUCT_ORDER__ = [] as const;
export const __DECL_ORDER__ = ["KIND_BACKLOG", "KIND_REWORK", "KIND_ASSIGNED", "RS_NONE", "RS_WAIT", "RS_OTHER", "REVIEW_QUEUE_MAX", "R_ADMIT", "R_REVIEW_FIRST", "REFUSAL_TAIL"] as const;

// What this spec holds and this backend did not print. Empty is the whole
// story most of the time; an entry here is a promise the artifact does not
// keep, and reading it is how a tool tells a partial module from a complete
// one without parsing comments.
//
// A LIST, not a map keyed by name. `specs/numeric/formats.t27` declares four
// separate consts called `result`, one per test block, and under an object
// literal three of the four omissions vanished into the fourth -- a record of
// what went missing that itself went missing. A spec is free to reuse a
// name; this file is not free to lose the second one.
export const __NOT_EMITTED__ = Object.freeze([] as const);
38 changes: 38 additions & 0 deletions trios/agent-server/apps/server/src/api/services/queen-tick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {
dispatchByActors,
handRoundToBeeActors,
} from './queen-bee-actors-round'
import { flag, loadCardWasm, u32 } from './queen-card-wasm'
import { githubCiDeps, takeBackRefusedAcceptances } from './queen-ci-verdict'
import { type ClaimLease, claimOf, type DispatchClaim } from './queen-claim'
import {
Expand Down Expand Up @@ -141,6 +142,7 @@ import {
type ReviewCapacity,
startReviewerActors,
} from './queen-review-actors'
import * as RF from './queen-review-first-card.gen'
import type { LaneGate } from './queen-review-lanes'
import { LANE_GO, LANE_STOPPED } from './queen-review-lanes-card.gen'
import {
Expand Down Expand Up @@ -2026,6 +2028,39 @@ export async function runRound(
const assigned = await pendingAssigns(pool).catch(() => [] as number[])
if (assigned.length > 0) candidates = manualFirst(candidates, assigned)

// REVIEW FIRST (review_first.t27, t27#10555, TRIOS_QUEEN_REVIEW_FIRST=on): no
// backlog issue starts while finished work waits in review; send-backs and
// assignments still do. The queue is the sweep's own filter. Off: as above.
let reviewFirst: string | null = null
if ((process.env.TRIOS_QUEEN_REVIEW_FIRST ?? '').trim() === 'on') {
const rf = loadCardWasm('queen/review_first.wasm')
const done = await pool.query(
`SELECT issue, review_state, (outcome NOT LIKE 'reaped%') IS TRUE AS kept
FROM queen_dispatch WHERE started = true AND finished_at IS NOT NULL`,
)
const rs = (s: unknown) =>
s == null ? RF.RS_NONE : s === 'wait' ? RF.RS_WAIT : RF.RS_OTHER
const open = (n: unknown) => flag(issuesNow?.has(Number(n)) ?? true)
const queue = done.rows.filter((r) => {
const row = [1, 1, rs(r.review_state), flag(!r.kept), open(r.issue)]
return rf.call('in_review_queue', ...row) !== 0
}).length
const sentBack = new Set(
inFlight.rows
.filter((r) => r.review_state === 'sendBack')
.map((r) => Number(r.issue)),
)
const kind = (n: number) =>
rf.call('kind_of', flag(assigned.includes(n)), flag(sentBack.has(n)))
const before = candidates.length
candidates = candidates.filter(
(n) => rf.call('admits', kind(n), u32(queue)) !== 0,
)
const held = u32(before - candidates.length)
if (rf.call('round_refused', u32(candidates.length), held) !== 0)
reviewFirst = `${queue}${RF.REFUSAL_TAIL}`
}

// Named, because RING-00 is asked about this exact array a few lines below
// and "the same number" has to be the same number, not a second reading of
// the same idea.
Expand All @@ -2038,6 +2073,9 @@ export async function runRound(
candidateBodies,
tasks: openingBoard,
})
// answer is true unless queend refused for capacity: then the rule says why.
if (reviewFirst && !choice.chosen && swiftCapacityAnswer(choice).answer)
choice.refusal = reviewFirst
// TRIOS_QUEEN_DISPATCH_BATCH=on (t27#9021): one chooser call fills every
// free lane with edits that meet no other (queen-batch-choose.ts); off, the
// round asks queend again after every pick, as before.
Expand Down
3 changes: 3 additions & 0 deletions trios/agent-server/specs/PIN
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,6 @@ claim card: gHashTag/t27 specs/queen/claim.t27 (t27#8765, PR t27#8768 head d4ced
claim: queen/claim.t27 sha256 f031594c8c0c5078a126ad4ed3ec0e3ef6b1179658572878fa24361c4b17cec9
claim: queen/review_valve.t27 sha256 5177806d264aa3611b5187a89b929c2231cbf7f95eb3cb78d246d913b658d8a6
claim: queen/claim.wasm sha256 08fc2b32d46742638c00d20fe1e64dd81289080dcfc8fa662972acc411d4884a
review_first card: gHashTag/t27 specs/queen/review_first.t27 (t27#10555, PR t27#10562), byte-identical; review_first.wasm = t27c gen-c + zig 0.16.0 cc --target=wasm32-wasi -Oz -DNDEBUG -mexec-model=reactor, exports every fn of the card: kind_of,in_review_queue,backlog_open,admission,admits,round_refused (reproducible: two builds, one hash); constants: t27c gen-ts > apps/server/src/api/services/queen-review-first-card.gen.ts
review_first: queen/review_first.t27 sha256 c0ec4028feccb9740ddd434f8a1ee8f4fce9b7a4ce2dd1664de504a0b5d06e88
review_first: queen/review_first.wasm sha256 6c9fbeca0bc9dc98122ee4dcc8cdf1ad0c37c659625422828281309875555f2f
175 changes: 175 additions & 0 deletions trios/agent-server/specs/queen/review_first.t27
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
// SPDX-License-Identifier: Apache-2.0
; specs/queen/review_first.t27 -- no new work from the backlog while finished work waits in review (gHashTag/t27#10555).
; The owner's rule, 2026-10-18: the Queen takes nothing from the backlog while there is a queue in review.
; Measured 2026-10-18 17:09Z on api.t27.ai/queen/status: 69 of 70 workers busy; in the last hour 102
; dispatched, 56 finished, 11 reviewed; reviewable (the review sweep's own queue) 29, unreviewed 362.
; The swarm starts about nine bees for every verdict, so the queue in review only grows, and each new bee
; holds files (claim.t27) that the bees already in review need when they are sent back.
; The rule:
; 1. the review queue is exactly the review sweep's own filter, the one the status page counts as
; `reviewable`: the dispatch started, it finished, its review_state is NULL or 'wait', it was not
; reaped, and its issue is still open (in_review_queue);
; 2. while that queue is longer than REVIEW_QUEUE_MAX (0: not while anything waits) a candidate from
; the backlog is refused, and the round says why (admission, R_REVIEW_FIRST);
; 3. work the review itself asked for is never backlog: an issue the review sent back is dispatched
; again at any queue length (KIND_REWORK), and so is an issue the owner assigned by hand
; (KIND_ASSIGNED, the supervisor's pendingAssigns);
; 4. the queue empties on its own: every outcome of the review that is not an accept has a clock
; (review_valve.t27), so a closed backlog always reopens without a person.
; The host counts the queue and names each candidate's kind; this file decides. Not here: the wiring into
; trios (queen-tick.ts candidate filter, vendored wasm and t27c gen-ts constants), how keys are shared
; between bees and the reviewer, the review verdicts themselves. ASCII only (L3).
; phi^2 + 1/phi^2 = 3 | TRINITY

module QueenReviewFirst;

; --- 1. What a candidate is ---------------------------------------------------------------------------

/// KIND_BACKLOG: an open issue with no dispatch the review is working on. KIND_REWORK: an issue whose
/// last dispatch the review sent back (review_state 'sendBack'). KIND_ASSIGNED: an issue the owner
/// assigned by hand. The codes are mirrored by number: a new kind takes the next code, none moves.
pub const KIND_BACKLOG : u8 = 0;
pub const KIND_REWORK : u8 = 1;
pub const KIND_ASSIGNED : u8 = 2;

/// The owner's hand wins over the review's send-back, and both win over the backlog.
pub fn kind_of(assigned: bool, sent_back: bool) -> u8 {
if (assigned) { return KIND_ASSIGNED; }
if (sent_back) { return KIND_REWORK; }
return KIND_BACKLOG;
}

; --- 2. What the review queue is ----------------------------------------------------------------------

/// A dispatch row's review_state as the host reads it: RS_NONE is NULL (no verdict yet), RS_WAIT is
/// 'wait' (fewer verdicts than criteria, dispatch.t27 REVIEW_RULE), RS_OTHER is any written verdict.
pub const RS_NONE : u8 = 0;
pub const RS_WAIT : u8 = 1;
pub const RS_OTHER : u8 = 2;

/// Whether one dispatch row is in the review queue: the sweep's own filter (trios queen-tick.ts
/// reviewFinishedDispatches, counted as `reviewable` by queen-public-status.ts). A row whose issue was
/// closed is never reviewed, so it never holds the backlog shut.
pub fn in_review_queue(started: bool, finished: bool, state: u8, reaped: bool, issue_open: bool) -> bool {
if (started == false) { return false; }
if (finished == false) { return false; }
if (reaped) { return false; }
if (issue_open == false) { return false; }
if (state == RS_NONE) { return true; }
return state == RS_WAIT;
}

; --- 3. Admission -------------------------------------------------------------------------------------

/// How many dispatches may wait in review while the backlog stays open. Zero, the owner's words: not
/// while anything is in review.
pub const REVIEW_QUEUE_MAX : u32 = 0;

/// R_ADMIT: the candidate may be chosen. R_REVIEW_FIRST: refused, the backlog is closed while the review
/// queue is longer than REVIEW_QUEUE_MAX.
pub const R_ADMIT : u8 = 0;
pub const R_REVIEW_FIRST : u8 = 1;

/// The refusal as the round reports it, after the queue length: "29 dispatches wait in review; ...".
pub const REFUSAL_TAIL : str = " dispatches wait in review; the backlog is closed until the review queue is empty";

pub fn backlog_open(review_queue: u32) -> bool {
return review_queue <= REVIEW_QUEUE_MAX;
}

pub fn admission(kind: u8, review_queue: u32) -> u8 {
if (kind == KIND_REWORK) { return R_ADMIT; }
if (kind == KIND_ASSIGNED) { return R_ADMIT; }
if (backlog_open(review_queue)) { return R_ADMIT; }
return R_REVIEW_FIRST;
}

pub fn admits(kind: u8, review_queue: u32) -> bool {
return admission(kind, review_queue) == R_ADMIT;
}

/// Whether a round that admitted no candidate owes the review-first sentence: some candidate was
/// refused by this rule and none was admitted.
pub fn round_refused(admitted: u32, refused: u32) -> bool {
if (admitted > 0) { return false; }
return refused > 0;
}

; --- 4. Tests -----------------------------------------------------------------------------------------

test the_owner_hand_wins_then_the_review_then_the_backlog {
assert kind_of(false, false) == 0;
assert kind_of(false, true) == 1;
assert kind_of(true, false) == 2;
assert kind_of(true, true) == 2;
}

test the_queue_is_the_sweeps_own_filter {
assert in_review_queue(true, true, RS_NONE, false, true) == true;
assert in_review_queue(true, true, RS_WAIT, false, true) == true;
assert in_review_queue(true, true, RS_OTHER, false, true) == false;
assert in_review_queue(true, false, RS_NONE, false, true) == false;
assert in_review_queue(false, true, RS_NONE, false, true) == false;
assert in_review_queue(true, true, RS_NONE, true, true) == false;
assert in_review_queue(true, true, RS_NONE, false, false) == false;
assert in_review_queue(true, true, RS_WAIT, true, true) == false;
assert in_review_queue(true, true, 7, false, true) == false;
}

test the_backlog_is_closed_while_anything_waits_in_review {
assert admission(KIND_BACKLOG, 0) == 0;
assert admission(KIND_BACKLOG, 1) == 1;
assert admission(KIND_BACKLOG, 29) == 1;
assert admission(KIND_BACKLOG, 4294967295) == 1;
assert backlog_open(0) == true;
assert backlog_open(1) == false;
assert admits(KIND_BACKLOG, 0) == true;
assert admits(KIND_BACKLOG, 1) == false;
}

test work_the_review_asked_for_is_never_backlog {
assert admission(KIND_REWORK, 0) == 0;
assert admission(KIND_REWORK, 1) == 0;
assert admission(KIND_REWORK, 29) == 0;
assert admission(KIND_REWORK, 4294967295) == 0;
assert admits(KIND_REWORK, 362) == true;
}

test the_owners_assignment_is_never_held {
assert admission(KIND_ASSIGNED, 0) == 0;
assert admission(KIND_ASSIGNED, 29) == 0;
assert admits(KIND_ASSIGNED, 4294967295) == true;
}

test an_unknown_kind_is_backlog_and_is_held {
assert admission(3, 0) == 0;
assert admission(3, 1) == 1;
assert admission(255, 29) == 1;
}

test a_round_reports_the_rule_only_when_it_stopped_everything {
assert round_refused(0, 0) == false;
assert round_refused(0, 5) == true;
assert round_refused(1, 5) == false;
assert round_refused(3, 0) == false;
}

test the_measured_round_of_2026_10_18 {
assert admits(kind_of(false, false), 29) == false;
assert admits(kind_of(false, true), 29) == true;
assert admits(kind_of(true, false), 29) == true;
assert admits(kind_of(false, false), 0) == true;
}

; --- 5. Invariants ------------------------------------------------------------------------------------

invariant the_codes_never_move {
assert KIND_BACKLOG == 0 and KIND_REWORK == 1 and KIND_ASSIGNED == 2;
assert RS_NONE == 0 and RS_WAIT == 1 and RS_OTHER == 2;
assert R_ADMIT == 0 and R_REVIEW_FIRST == 1;
}

/// The owner's bound: nothing may wait in review while the backlog is open.
invariant the_bound_is_the_owners {
assert REVIEW_QUEUE_MAX == 0;
}
Binary file added trios/agent-server/specs/queen/review_first.wasm
Binary file not shown.
Loading