Public: anyone can read this; the crew can change it.
A pure read lists the open crew pulls one changes-asked round away from being handed over #6599
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/6591-a-pure-read-lists-the-open-crew-pulls-on → main 1 commit fork 1 thread · 1 unresolved
2 files
changed +52
−0
src/flow/review_rounds.ts added +30
| @@ -0,0 +1,30 @@ | ||
| 1 | /** | |
| 2 | * Pulls one changes-asked round from being handed over (#6591). A pull goes to | |
| 3 | * a person after three changes-requested reviews in a row; the ones at two | |
| 4 | * can be helped a round earlier. Pure: rows in, rows out. | |
| 5 | */ | |
| 6 | ||
| 7 | export type Verdict = "approved" | "changes_requested"; | |
| 8 | ||
| 9 | export const HANDOVER_RUN = 3; | |
| 10 | ||
| 11 | export interface ReviewRow<P> { | |
| 12 | readonly pull: P; | |
| 13 | /** Review verdicts in time order, oldest first. */ | |
| 14 | readonly verdicts: readonly Verdict[]; | |
| 15 | } | |
| 16 | ||
| 17 | /** The trailing run of changes-requested verdicts since the last approval. */ | |
| 18 | export function trailingRun(verdicts: readonly Verdict[]): number { | |
| 19 | let run = 0; | |
| 20 | for (let i = verdicts.length - 1; i >= 0 && verdicts[i] === "changes_requested"; i--) run++; | |
| 21 | return run; | |
| 22 | } | |
| 23 | ||
| 24 | /** Pulls whose trailing run is exactly two, given in time order; most recent first. */ | |
| 25 | export function nearHandover<P>(rows: readonly ReviewRow<P>[]): P[] { | |
| 26 | return rows | |
| 27 | .filter((r) => trailingRun(r.verdicts) === HANDOVER_RUN - 1) | |
| 28 | .map((r) => r.pull) | |
| 29 | .reverse(); | |
| 30 | } |
test/flow-review-rounds.test.ts added +22
| @@ -0,0 +1,22 @@ | ||
| 1 | /** Near-handover pulls: exactly two changes-asked reviews in a row since the last approval. */ | |
| 2 | import { expect, test } from "bun:test"; | |
| 3 | import { nearHandover, type Verdict } from "../src/flow/review_rounds.ts"; | |
| 4 | ||
| 5 | const A: Verdict = "approved"; | |
| 6 | const C: Verdict = "changes_requested"; | |
| 7 | ||
| 8 | test("two trailing changes-asked are listed, most recent first", () => { | |
| 9 | expect(nearHandover([{ pull: 1, verdicts: [C, C] }, { pull: 2, verdicts: [A, C, C] }])).toEqual([2, 1]); | |
| 10 | }); | |
| 11 | ||
| 12 | test("three trailing are already handed over, not listed", () => { | |
| 13 | expect(nearHandover([{ pull: 1, verdicts: [C, C, C] }])).toEqual([]); | |
| 14 | }); | |
| 15 | ||
| 16 | test("an approval resets the run", () => { | |
| 17 | expect(nearHandover([{ pull: 1, verdicts: [C, C, A] }, { pull: 2, verdicts: [C, C, A, C] }])).toEqual([]); | |
| 18 | }); | |
| 19 | ||
| 20 | test("no reviews, or one, are not listed", () => { | |
| 21 | expect(nearHandover([{ pull: 1, verdicts: [] }, { pull: 2, verdicts: [C] }])).toEqual([]); | |
| 22 | }); |
new above
offline
Duplicates the handover threshold that src/core/reviews.ts already holds as REVIEW_ROUNDS. Import it when this gets wired.