One task, three kinds
You will learn
How an issue, a review and a job become one kind of task with seven states, and how one filter reads them.
The Queen runs three kinds of work: issues for bees, reviews of finished work, and jobs. Each kept its own codes, so no board could show them together. tasks.t27 gives them 7 shared states, numbered as the board's columns plus failed. A cancelled job shows as dropped, and so does a review row that was forgotten. task_matches is the filter the board, the game and the route all apply: a bit per kind, a bit per state, and 0 means any.
Try it
Show only failed tasks of every kind; then find which job state shows as dropped.

An issue, a review and a job are one kind of task with seven states. Tap kinds and states: the grid lights every pair task_matches lets through.
specs/queen/tasks.t27
// SPDX-License-Identifier: Apache-2.0
; specs/queen/tasks.t27 -- one task, many kinds, and the bees working on them, as everyone reads them
; Owner, 2026-10-08 (translated): lower every task of the project to the scheduler's native level; a
; dashboard shows all of it with any filter (https://app.t27.ai/game/kanban); the bees fly over the
; GitHub issue each is working on in the game (https://app.t27.ai/game). Epic #7718, slice 1.
; Measured that morning, four surveys:
; - there is no single task. An issue dispatch (dispatch.t27 COL_*), a job (jobs.t27 J_*) and an app
; review (app.t27, per head) each kept their own codes.
; - no public field said which bee is on which issue. The game drew a public snapshot with no bees, and
; its older comb paired the k-th busy slot with the k-th running card, which is a rank, not a link.
; This card is the view everyone reads: the supervisor builds GET /queen/public-tasks with it, and the
; board and the game filter and draw with it. The kinds keep their own machines; this only says how
; each one shows.
; ASCII only (L3).
; phi^2 + 1/phi^2 = 3 | TRINITY
module QueenTasks;
/// Kinds of task. Index into KIND_NAMES.
pub const TK_ISSUE : u8 = 0;
pub const TK_REVIEW : u8 = 1;
pub const TK_JOB : u8 = 2;
pub const TASK_KINDS : u8 = 3;
pub const KIND_NAMES : [3]str = ["issue", "review", "job"];
/// One state for every kind, numbered as dispatch.t27's board columns (COL_BACKLOG .. COL_DROPPED) so
/// an issue's column IS its state, plus FAILED, which a column never was. Index into STATE_NAMES.
pub const TS_BACKLOG : u8 = 0;
pub const TS_BLOCKED : u8 = 1;
pub const TS_RUNNING : u8 = 2;
pub const TS_REVIEW : u8 = 3;
pub const TS_DONE : u8 = 4;
pub const TS_DROPPED : u8 = 5;
pub const TS_FAILED : u8 = 6;
pub const TASK_STATES : u8 = 7;
pub const STATE_NAMES : [7]str = ["backlog", "blocked", "running", "review", "done", "dropped", "failed"];
/// A job's state (jobs.t27: 0 running, 1 done, 2 failed, 3 cancelled) as a task state.
pub fn job_state(j: u8) -> u8 {
if (j == 0) { return TS_RUNNING; }
if (j == 1) { return TS_DONE; }
if (j == 2) { return TS_FAILED; }
return TS_DROPPED;
}
/// An app review's row state (queued 0, posted 1, forgotten 2, failed 3) as a task state.
pub fn review_state(r: u8) -> u8 {
if (r == 0) { return TS_BACKLOG; }
if (r == 1) { return TS_DONE; }
if (r == 2) { return TS_DROPPED; }
return TS_FAILED;
}
/// The A2A v1.0 task state each state is, for the day the Queen answers A2A at her edge (epic #7718
/// slice 7). A task waiting for a judge or a person is input-required; dropped is canceled.
pub const A2A_SUBMITTED : u8 = 1;
pub const A2A_WORKING : u8 = 2;
pub const A2A_INPUT_REQUIRED : u8 = 3;
pub const A2A_COMPLETED : u8 = 4;
pub const A2A_CANCELED : u8 = 5;
pub const A2A_FAILED : u8 = 6;
pub fn a2a_state(s: u8) -> u8 {
if (s == TS_BACKLOG) { return A2A_SUBMITTED; }
if (s == TS_RUNNING) { return A2A_WORKING; }
if (s == TS_BLOCKED or s == TS_REVIEW) { return A2A_INPUT_REQUIRED; }
if (s == TS_DONE) { return A2A_COMPLETED; }
if (s == TS_DROPPED) { return A2A_CANCELED; }
return A2A_FAILED;
}
/// A bee is one dispatch still in flight: offered and not claimed yet (QUEUED), heard from within
/// BEE_QUIET_SECONDS (WORKING), or silent longer (QUIET). The game draws a quiet bee hovering, not
/// working: a bee that has not spoken for minutes is not shown as busy.
pub const BS_QUEUED : u8 = 0;
pub const BS_WORKING : u8 = 1;
pub const BS_QUIET : u8 = 2;
pub const BEE_QUIET_SECONDS : u32 = 180;
pub const BEE_STATE_NAMES : [3]str = ["queued", "working", "quiet"];
/// `claimed`: a runner took the order (or the container started it); `heard`: an event was recorded
/// for its conversation; `seconds_since`: since that event, or since it started when none was heard.
pub fn bee_state(claimed: bool, seconds_since: u32) -> u8 {
if (claimed == false) { return BS_QUEUED; }
if (seconds_since > BEE_QUIET_SECONDS) { return BS_QUIET; }
return BS_WORKING;
}
/// The filter the board, the game and the route all apply: a bit per kind and a bit per state, and 0
/// meaning "any". Repository and text are matched beside it; they are strings, and equality on
/// strings is the caller's.
pub fn task_matches(kind_mask: u32, state_mask: u32, kind: u8, state: u8) -> bool {
if (kind >= TASK_KINDS or state >= TASK_STATES) { return false; }
if (kind_mask != 0 and (kind_mask & (1 << kind)) == 0) { return false; }
if (state_mask != 0 and (state_mask & (1 << state)) == 0) { return false; }
return true;
}
/// Tasks one answer carries at most; the route pages past it.
pub const TASK_PAGE_MAX : u32 = 2000;
pub const TASK_PAGE_DEFAULT : u32 = 500;
test a_job_and_a_review_show_as_one_lifecycle {
assert job_state(0) == TS_RUNNING;
assert job_state(1) == TS_DONE;
assert job_state(2) == TS_FAILED;
assert job_state(3) == TS_DROPPED;
assert review_state(0) == TS_BACKLOG;
assert review_state(1) == TS_DONE;
assert review_state(2) == TS_DROPPED;
assert review_state(3) == TS_FAILED;
}
test every_state_has_an_a2a_state {
assert a2a_state(TS_BACKLOG) == A2A_SUBMITTED;
assert a2a_state(TS_RUNNING) == A2A_WORKING;
assert a2a_state(TS_BLOCKED) == A2A_INPUT_REQUIRED;
assert a2a_state(TS_REVIEW) == A2A_INPUT_REQUIRED;
assert a2a_state(TS_DONE) == A2A_COMPLETED;
assert a2a_state(TS_DROPPED) == A2A_CANCELED;
assert a2a_state(TS_FAILED) == A2A_FAILED;
}
test a_bee_is_queued_working_or_quiet {
assert bee_state(false, 0) == BS_QUEUED;
assert bee_state(false, 9999) == BS_QUEUED;
assert bee_state(true, 0) == BS_WORKING;
assert bee_state(true, BEE_QUIET_SECONDS) == BS_WORKING;
assert bee_state(true, BEE_QUIET_SECONDS + 1) == BS_QUIET;
}
test a_filter_narrows_and_zero_means_any {
assert task_matches(0, 0, TK_ISSUE, TS_RUNNING) == true;
assert task_matches(1 << TK_ISSUE, 0, TK_ISSUE, TS_DONE) == true;
assert task_matches(1 << TK_JOB, 0, TK_ISSUE, TS_DONE) == false;
assert task_matches(0, 1 << TS_RUNNING, TK_REVIEW, TS_RUNNING) == true;
assert task_matches(0, 1 << TS_RUNNING, TK_REVIEW, TS_BACKLOG) == false;
assert task_matches((1 << TK_ISSUE) | (1 << TK_JOB), (1 << TS_RUNNING) | (1 << TS_REVIEW), TK_JOB, TS_REVIEW) == true;
// an unknown kind or state matches nothing, even with no filter
assert task_matches(0, 0, TASK_KINDS, TS_DONE) == false;
assert task_matches(0, 0, TK_ISSUE, TASK_STATES) == false;
}
invariant the_states_are_the_board_columns {
assert TS_BACKLOG == 0 and TS_BLOCKED == 1 and TS_RUNNING == 2;
assert TS_REVIEW == 3 and TS_DONE == 4 and TS_DROPPED == 5 and TS_FAILED == 6;
assert TK_ISSUE == 0 and TK_REVIEW == 1 and TK_JOB == 2;
assert TASK_PAGE_DEFAULT <= TASK_PAGE_MAX;
}
All lessons
Module 1 · The task
An issue becomes work only once it is shaped: the sections it lacks are written or asked for, its boundary names real files, and one filter reads every kind of task.
Module 2 · Who goes next
The order the Queen takes issues in: a label ages one step, at most 3 criticals run as critical, and nothing new starts while finished work waits for review.
Module 3 · A bee's life
From candidate to done: twelve states and sixteen events, a ship in the game that flies home, and a deploy that does not cut a bee short.
Module 4 · The reviewer bee
Finished work is judged on its own clock: enough reviews at once to keep up, a pause that doubles for a row that waits, and a merge gate that zero checks cannot open.
Module 5 · The review jam
A pull request that will not move is in exactly one of ten cases, each with the Queen's move, and a red check is inherited only when master says so.
Module 6 · Keys
A bee's model key can be refused: the code in the body sorts the refusal, a transient one rests the key for seconds, and the bee moves on to the next free key.
Module 7 · Credit and money
Lending a key earns no credit, an operation is sold at twice its cost in half-cent tokens, and tokens burn 30 days after they land.
Module 8 · Agents among themselves
One bot per agent in one group: who is called, a chain three bot messages deep, and the clocks that keep agents from flooding a chat.
Module 9 · Night and the board
What the hive shows: a night watch that opens, comments on and closes issues, the columns of the public board, and the comb that flashes for each event.