t27.aiEnglish

Одна задача, три вида

Вы узнаете

Как задача, ревью и фоновая работа становятся одним видом задачи с семью состояниями и как их читает один фильтр.

Королева ведёт работу трёх видов: задачи для пчёл, ревью готовой работы и фоновые работы. У каждого вида были свои коды, и ни одна доска не могла показать их вместе. tasks.t27 даёт им 7 общих состояний, пронумерованных как колонки доски, плюс failed. Отменённая работа показывается как dropped, и так же — забытая строка ревью. task_matches — фильтр, который применяют доска, игра и маршрут: бит на вид, бит на состояние, а 0 значит любое.

Попробовать

Покажите только упавшие задачи всех видов; затем найдите, какое состояние работы показывается как dropped.

Открыть интерактивный урок →

One task, three kinds: the filter the board and the game share
One task, three kinds: the filter the board and the game share ↗

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;
}

Открыть спеку урока в плеере ↗

Все уроки