Ход Королевы
Вы узнаете
Что Королева делает в каждом заторе и каких заторов она ждёт.
У каждого случая одно действие на той же позиции: no reviewer отправляет ревьюера, refused not fixed отправляет кодера, refused then pushed отправляет повторное ревью, а labeled not merged завершает слияние. jam_action переводит любое значение больше 9 в measure again, так что неизвестный случай никогда не значит «делать нечего». jam_is_queens_turn ложно для 3 случаев — none, draft or fresh и stacked on an open PR: их она ждёт.
Попробовать
Найдите случай, чьё действие — ждать базу; затем дотяните до 200 и прочитайте действие.

Each jam case has one action at the same position. Drag the case: jam_action names the move, and jam_is_queens_turn splits the board into her turn and waiting.
specs/automation/review-jam.t27
// Review jam: which case a stuck pull request is in, and the Queen's action.
// Part of EPIC #5388. Contract: gHashTag/t27#9032 (re-filed from #5700).
// `tri jam` (gHashTag/999-multibots-telegraf) imports these numbers instead
// of hand-copying them.
module review_jam;
// Jam case constants (u8, value = position, starting at 0)
pub const JAM_NONE: u8 = 0;
pub const JAM_NO_REVIEWER: u8 = 1;
pub const JAM_STACKED_ON_OPEN: u8 = 2;
pub const JAM_REFUSED_NOT_FIXED: u8 = 3;
pub const JAM_REFUSED_THEN_PUSHED: u8 = 4;
pub const JAM_LABELED_NOT_MERGED: u8 = 5;
pub const JAM_CONFLICTING: u8 = 6;
pub const JAM_NOISE_RED: u8 = 7;
pub const JAM_DRAFT_OR_FRESH: u8 = 8;
pub const JAM_UNMEASURED: u8 = 9;
// Queen action constants (u8, value = position, starting at 0)
pub const ACT_NOTHING: u8 = 0;
pub const ACT_DISPATCH_REVIEWER: u8 = 1;
pub const ACT_WAIT_FOR_BASE: u8 = 2;
pub const ACT_DISPATCH_CODER: u8 = 3;
pub const ACT_DISPATCH_RE_REVIEW: u8 = 4;
pub const ACT_FINISH_MERGE: u8 = 5;
pub const ACT_REBASE_BY_CODER: u8 = 6;
pub const ACT_NAME_NOISE_AND_REVIEW: u8 = 7;
pub const ACT_WAIT: u8 = 8;
pub const ACT_MEASURE_AGAIN: u8 = 9;
// The jam case of a pull request. The FIRST matching rule wins:
// 1. not measured -> UNMEASURED
// 2. draft or fresh -> DRAFT_OR_FRESH
// 3. stacked on an open PR -> STACKED_ON_OPEN
// 4. conflicting -> CONFLICTING
// 5. labeled reviewed (and still open) -> LABELED_NOT_MERGED
// 6. refused and pushed after -> REFUSED_THEN_PUSHED
// 7. refused -> REFUSED_NOT_FIXED
// 8. only noise checks red -> NOISE_RED
// 9. no reviewer -> NO_REVIEWER
// 10. otherwise -> NONE
pub fn jam_case(measured: bool, draft_or_fresh: bool, stacked_on_open: bool, conflicting: bool, labeled_reviewed: bool, refused: bool, pushed_after_refusal: bool, has_reviewer: bool, only_noise_red: bool) -> u8 {
if !measured {
return JAM_UNMEASURED;
}
if draft_or_fresh {
return JAM_DRAFT_OR_FRESH;
}
if stacked_on_open {
return JAM_STACKED_ON_OPEN;
}
if conflicting {
return JAM_CONFLICTING;
}
if labeled_reviewed {
return JAM_LABELED_NOT_MERGED;
}
if refused && pushed_after_refusal {
return JAM_REFUSED_THEN_PUSHED;
}
if refused {
return JAM_REFUSED_NOT_FIXED;
}
if only_noise_red {
return JAM_NOISE_RED;
}
if !has_reviewer {
return JAM_NO_REVIEWER;
}
JAM_NONE
}
// The Queen's action for a case: the action with the SAME position.
// Any value above 9 is an unknown case, and an unknown case is never
// "nothing to do": it maps to ACT_MEASURE_AGAIN.
pub fn jam_action(case: u8) -> u8 {
if case > 9 {
return ACT_MEASURE_AGAIN;
}
case
}
// Whether the case is the Queen's turn to act: true for every case except
// NONE, DRAFT_OR_FRESH and STACKED_ON_OPEN.
pub fn jam_is_queens_turn(case: u8) -> bool {
case != JAM_NONE && case != JAM_DRAFT_OR_FRESH && case != JAM_STACKED_ON_OPEN
}
// ---- jam_case: one test per case ----
test "unmeasured beats every other flag" {
assert jam_case(false, true, true, true, true, true, true, true, true) == JAM_UNMEASURED;
}
test "unmeasured with every other flag clear" {
assert jam_case(false, false, false, false, false, false, false, false, false) == JAM_UNMEASURED;
}
test "draft or fresh" {
assert jam_case(true, true, false, false, false, false, false, false, false) == JAM_DRAFT_OR_FRESH;
}
test "stacked on open PR" {
assert jam_case(true, false, true, false, false, false, false, true, false) == JAM_STACKED_ON_OPEN;
}
test "conflicting" {
assert jam_case(true, false, false, true, false, false, false, true, false) == JAM_CONFLICTING;
}
test "labeled not merged" {
assert jam_case(true, false, false, false, true, false, false, true, false) == JAM_LABELED_NOT_MERGED;
}
test "refused then pushed" {
assert jam_case(true, false, false, false, false, true, true, true, false) == JAM_REFUSED_THEN_PUSHED;
}
test "refused not fixed" {
assert jam_case(true, false, false, false, false, true, false, true, false) == JAM_REFUSED_NOT_FIXED;
}
test "noise red" {
assert jam_case(true, false, false, false, false, false, false, true, true) == JAM_NOISE_RED;
}
test "no reviewer" {
assert jam_case(true, false, false, false, false, false, false, false, false) == JAM_NO_REVIEWER;
}
test "none" {
assert jam_case(true, false, false, false, false, false, false, true, false) == JAM_NONE;
}
// ---- jam_case: first-match order, each rule against the next one ----
test "draft beats stacked" {
assert jam_case(true, true, true, false, false, false, false, true, false) == JAM_DRAFT_OR_FRESH;
}
test "stacked and unreviewed is stacked, not no reviewer" {
assert jam_case(true, false, true, false, false, false, false, false, false) == JAM_STACKED_ON_OPEN;
}
test "stacked beats conflicting" {
assert jam_case(true, false, true, true, false, false, false, true, false) == JAM_STACKED_ON_OPEN;
}
test "conflicting beats labeled" {
assert jam_case(true, false, false, true, true, false, false, true, false) == JAM_CONFLICTING;
}
test "labeled beats refused then pushed" {
assert jam_case(true, false, false, false, true, true, true, true, false) == JAM_LABELED_NOT_MERGED;
}
test "refused then pushed beats noise red" {
assert jam_case(true, false, false, false, false, true, true, true, true) == JAM_REFUSED_THEN_PUSHED;
}
test "refused not fixed beats noise red" {
assert jam_case(true, false, false, false, false, true, false, true, true) == JAM_REFUSED_NOT_FIXED;
}
test "noise red beats no reviewer" {
assert jam_case(true, false, false, false, false, false, false, false, true) == JAM_NOISE_RED;
}
test "pushed without a refusal is not refused then pushed" {
assert jam_case(true, false, false, false, false, false, true, true, false) == JAM_NONE;
}
// ---- jam_action: same position, unknown -> measure again ----
test "action none to nothing" {
assert jam_action(JAM_NONE) == ACT_NOTHING;
}
test "action no reviewer to dispatch reviewer" {
assert jam_action(JAM_NO_REVIEWER) == ACT_DISPATCH_REVIEWER;
}
test "action stacked to wait for base" {
assert jam_action(JAM_STACKED_ON_OPEN) == ACT_WAIT_FOR_BASE;
}
test "action refused not fixed to dispatch coder" {
assert jam_action(JAM_REFUSED_NOT_FIXED) == ACT_DISPATCH_CODER;
}
test "action refused then pushed to dispatch re-review" {
assert jam_action(JAM_REFUSED_THEN_PUSHED) == ACT_DISPATCH_RE_REVIEW;
}
test "action labeled not merged to finish merge" {
assert jam_action(JAM_LABELED_NOT_MERGED) == ACT_FINISH_MERGE;
}
test "action conflicting to rebase by coder" {
assert jam_action(JAM_CONFLICTING) == ACT_REBASE_BY_CODER;
}
test "action noise red to name noise and review" {
assert jam_action(JAM_NOISE_RED) == ACT_NAME_NOISE_AND_REVIEW;
}
test "action draft or fresh to wait" {
assert jam_action(JAM_DRAFT_OR_FRESH) == ACT_WAIT;
}
test "action unmeasured to measure again" {
assert jam_action(JAM_UNMEASURED) == ACT_MEASURE_AGAIN;
}
test "action first unknown case measures again" {
assert jam_action(10) == ACT_MEASURE_AGAIN;
}
test "action unknown case 200 measures again" {
assert jam_action(200) == ACT_MEASURE_AGAIN;
}
// ---- jam_is_queens_turn ----
test "queens turn for no reviewer" {
assert jam_is_queens_turn(JAM_NO_REVIEWER) == true;
}
test "queens turn for refused not fixed" {
assert jam_is_queens_turn(JAM_REFUSED_NOT_FIXED) == true;
}
test "queens turn for refused then pushed" {
assert jam_is_queens_turn(JAM_REFUSED_THEN_PUSHED) == true;
}
test "queens turn for labeled not merged" {
assert jam_is_queens_turn(JAM_LABELED_NOT_MERGED) == true;
}
test "queens turn for conflicting" {
assert jam_is_queens_turn(JAM_CONFLICTING) == true;
}
test "queens turn for noise red" {
assert jam_is_queens_turn(JAM_NOISE_RED) == true;
}
test "queens turn for unmeasured" {
assert jam_is_queens_turn(JAM_UNMEASURED) == true;
}
test "not queens turn for none" {
assert jam_is_queens_turn(JAM_NONE) == false;
}
test "not queens turn for draft or fresh" {
assert jam_is_queens_turn(JAM_DRAFT_OR_FRESH) == false;
}
test "not queens turn for stacked on open" {
assert jam_is_queens_turn(JAM_STACKED_ON_OPEN) == false;
}
// ---- the two scenarios of #9032, end to end ----
test "scenario bee-reviewed but still open finishes the merge" {
assert jam_action(jam_case(true, false, false, false, true, false, false, true, false)) == ACT_FINISH_MERGE;
}
test "scenario failed read is never reported as free" {
assert jam_action(jam_case(false, false, false, false, false, false, false, true, false)) == ACT_MEASURE_AGAIN;
}
Все уроки
Модуль 1 · Задача
Задача становится работой, только когда её оформили: недостающие разделы дописаны или запрошены, граница называет настоящие файлы, а один фильтр читает задачи всех видов.
Модуль 2 · Кто следующий
Порядок, в котором Королева берёт задачи: метка стареет на одну ступень, критичными идут не больше 3, и ничего нового не начинается, пока готовая работа ждёт ревью.
Модуль 3 · Жизнь пчелы
От кандидата до готовой работы: двенадцать состояний и шестнадцать событий, корабль в игре, который улетает домой, и деплой, который не обрывает пчелу.
Модуль 4 · Пчела-ревьюер
Готовую работу судят по своим часам: столько ревью сразу, чтобы успевать, пауза, которая удваивается для строки в ожидании, и ворота слияния, которые не открыть без проверок.
Модуль 5 · Затор ревью
Застрявший пулл-реквест всегда в одном из десяти случаев, у каждого свой ход Королевы, а красная проверка считается унаследованной, только если так говорит master.
Модуль 6 · Ключи
Ключ модели у пчелы могут отклонить: код в теле ответа сортирует отказ, временный отказ даёт ключу отдохнуть секунды, и пчела переходит к следующему свободному ключу.
Модуль 7 · Заслуги и деньги
Одолженный ключ не приносит заслуг, операция продаётся вдвое дороже своей цены в токенах по полцента, а токены сгорают через 30 дней после зачисления.
Модуль 8 · Агенты между собой
У каждого агента свой бот в одной группе: кого зовут, цепочка глубиной в три сообщения ботов и часы, которые не дают агентам завалить чат.
Модуль 9 · Ночь и доска
Что показывает улей: ночной дозор, который открывает, комментирует и закрывает задачи, колонки публичной доски и соты, которые вспыхивают на каждое событие.