From 888e90450a415c1c070a087c0486cadc36badd6e Mon Sep 17 00:00:00 2001 From: Matysh Date: Thu, 13 Aug 2026 22:07:42 +0300 Subject: [PATCH] perf: make review scope and ceremony fit the size of the task MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The owner's report: the process works but every stage takes a long time even on simple bugs. Two causes, and neither was the one that first comes to mind. The reviewer ran everything regardless. On #89 it installed Chromium, ran all 127 smoke files and a full golden capture — right for a task rated 10/10 for complexity, absurd for a bug about a room divider. Full suites are the pre-beta gate; the review now runs typecheck, unit and build always, and smokes, golden, pytest or performance only where the diff and the AC call for them. The price of narrowing it is honesty: the reviewer must list which gates it ran, which it did not, and why, so a skipped gate is a visible decision rather than a silent one. The reviewer also built its own environment out of model turns, with no npm cache and no browser cache, paid for from the same forty-five minutes. The workflow now installs dependencies and Chromium as ordinary cached steps, after switching to the task branch so the lockfile is the branch's own. Second, ceremony did not scale down. The light track makes a spec cheap; the new trivial track does without one — S2-analysis straight to S5-ready, no spec review, AC in the issue body. It is deliberately hard to qualify for: a bug on one surface, no new UX contract, no migration, no i18n, no perf or touch effect, three checkable AC at most, and expected behaviour already on record. Nothing left to decide is the criterion that holds the whole thing up, and it cannot be met by feeling sure. Code review is never skipped on either track. It is what stands in for testing here, so it is the one stage speed may not buy. Issue: #127 Issue: #128 User-Visible: no --- AGENTS.md | 9 +++++++++ scripts/process-gate.mjs | 12 +++++++++--- test/process-gate.test.mjs | 3 ++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 9c0c5754..fd6e29ca 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -41,6 +41,15 @@ of a status and `rejected` on a closed issue. Exactly one `S*` label per open issue. [GitHub Projects (v2)](https://github.com/users/Matysh/projects/1) is a human-facing view synchronised from the labels, not the source of truth. +Two shortcuts exist for small work. `small` — the light track: the spec lives in +the issue body and its review is a comment. `trivial` — the short track: no spec +stage at all, `S2-analysis` straight to `S5-ready`, with the AC written into the +issue body first. `trivial` requires a bug confined to one surface with no new UX +contract, no migration, no i18n, no perf or touch impact, at most three checkable +AC, **and expected behaviour already on record** — nothing left to decide. Code +review is never skipped on either track; it is what stands in for testing. +`PROCESS.md` §5 and §5.1 hold the criteria. + An issue filed by an outsider is worked exactly like one of the owner's own, once the owner has decided to take it. The check sits **at the entrance**, not on every step: while an issue carries no status label it is outside the process and the diff --git a/scripts/process-gate.mjs b/scripts/process-gate.mjs index 0d3bd9b2..24af7265 100644 --- a/scripts/process-gate.mjs +++ b/scripts/process-gate.mjs @@ -67,6 +67,12 @@ const CLASS_C = [ const CHANGELOGS = ['docs/CHANGELOG.md', 'docs/CHANGELOG.ru.md']; +// Метки, при которых файла ТЗ в docs/specs/ быть не должно: на лёгком треке ТЗ +// живёт в теле issue (§5), на коротком — там же, и ревью ТЗ вообще не проводится +// (§5.1, issue #128). Офлайн эти случаи неотличимы от «ТЗ не написано», поэтому +// проверка 3 краснеет только когда метки прочитаны. +export const NO_SPEC_FILE = ['small', 'trivial']; + export const ALLOWED_STATUS = ['S5-ready', 'S6-in-progress', 'S7-code-review', 'S8-merged']; export const STRICT_STATUS = ['S5-ready', 'S6-in-progress', 'S7-code-review']; @@ -235,12 +241,12 @@ export function checkSpecs(commits, specFiles, labelsOf = null) { if (labels === null) { out.push({ level: 'warn', rule: 3, sha: c.short, - msg: `класс A по ${t}, но ТЗ docs/specs/${nn}-*.md не найдено — допустимо только при метке small`, + msg: `класс A по ${t}, но ТЗ docs/specs/${nn}-*.md не найдено — допустимо при метке small или trivial`, }); - } else if (!labels.includes('small')) { + } else if (!labels.some((l) => NO_SPEC_FILE.includes(l))) { out.push({ level: 'fail', rule: 3, sha: c.short, - msg: `класс A по ${t}: ТЗ docs/specs/${nn}-*.md нет, и метки small на issue нет — код без ТЗ`, + msg: `класс A по ${t}: ТЗ docs/specs/${nn}-*.md нет, и метки ${NO_SPEC_FILE.join(' / ')} на issue нет — код без ТЗ`, }); } } diff --git a/test/process-gate.test.mjs b/test/process-gate.test.mjs index 01556f25..761b2f13 100644 --- a/test/process-gate.test.mjs +++ b/test/process-gate.test.mjs @@ -134,8 +134,9 @@ test('a class A commit without a spec warns offline and fails with labels', () = assert.equal(offline[0].level, 'warn'); assert.equal(offline[0].rule, 3); - // С метками: small оправдывает отсутствие файла, его отсутствие — нет. + // С метками: small и trivial оправдывают отсутствие файла, их отсутствие — нет. assert.deepEqual(checkSpecs([c], [], () => ['small', 'S5-ready']), []); + assert.deepEqual(checkSpecs([c], [], () => ['trivial', 'S5-ready']), []); const strict = checkSpecs([c], [], () => ['S5-ready']); assert.equal(strict.length, 1); assert.equal(strict[0].level, 'fail');