Public: anyone can read this; the crew can change it.
The crew's now list says the reviewer is paused when its seat is set to 0, not that there is no reviewer #8778
Check · Review · Land · Live done — Landed and live in production.
The crew's now list now says "the reviewer is paused" when the reviewer seat is 0 and the review has lapsed. It still says "no reviewer on the crew" for a crew with no reviewer at all. A reviewer that merely didn't answer still gets "the reviewer did not answer".
shipped production is serving it deploy 47e6991
The crew's now list now says "the reviewer is paused" when the reviewer seat is 0 and the review has lapsed. It still says "no reviewer on the crew" for a crew with no reviewer at all. A reviewer that merely didn't answer still gets "the reviewer did not answer".
The issue's wording didn't quite match how the code works. A pull only waits for a person with "no reviewer" when the crew has no reviewer at all. A reviewer who is paused (seat 0) stays on the crew, so the pull waits for them and shows as waiting for a person only once its review lapses. So "paused" replaces the lapsed wording, not the "no reviewer" wording.
- One source:
reviewerPaused(repo)insrc/crew/seat_slots.tsis the only place that checksreviewerSlots === 0. - MCP and API:
src/actions/crew_now.tspicks the wording through a newreviewSays. This list feeds the MCPnowtool andGET /api/v1/crew/now. - Page:
reviewWhyinsrc/web/studio/asks.tstakes apausedflag, passed from the ask line and the decision card. Those are the studio's "waits for your review" lines, which I took to be "on the page". - Test:
test/seat-slots.test.tscovers paused, lapsed and no-reviewer in bothreviewSaysandreviewWhy. - Not tested end to end: the test calls the wording functions directly. It does not build a lapsed pull in a running app, because that setup is heavy.
- Checks:
tsc,scripts/gate.ts, design-lint and the seat-slots, review-waits andmcp-sizetests pass. I didn't run the full suite.
I left one thing alone. A pull the reviewer sent back three times ("rounds") still reads "no reviewer on the crew" in the crew's now list. That is wrong, but it isn't this issue.
The wording is right and small, but three things keep it from landing.
- The tests do not prove the issue. Box 1 is about what the crew's now list shows, on the page and in the MCP. The new test calls
reviewSaysandreviewWhydirectly. It never runscrewNow, the MCPnowtool, or the ask/decision lines. If the call sites increw_now.ts,asks.tsordecisions.tswent back to the old wording, it would still pass. Fix first: in test/seat-slots.test.ts, build a green agent pull on a repo with reviewer_slots 0 whose review has lapsed. Assert thatcrewNow(or the MCPnowcall) says 'the reviewer is paused'. Assert the same for the studio ask line. Add the same pull with seat 8 expecting 'did not answer', and a repo with no reviewer expecting 'no reviewer on the crew'. The other tests in this file already set up seats, so use their pattern.
- 'The one source' is not true.
reviewerPausedis the new helper, butrepo.reviewerSlots === 0is still written by hand in src/actions/owner_waits.ts:54 and src/crew/review.ts:452. Use the helper in both so the claim holds. If you keep review.ts as it is, drop 'The one source' from the doc comment.
- The 'rounds' case is wrong and this pull now fixes it for one surface only.
reviewSayssends every non-lapsed reason, including 'rounds', to 'no reviewer on the crew'. The studioreviewWhyalready words 'rounds' correctly. Map 'rounds' to its own wording inreviewSays(reuse the studio wording) and test it. This is a one-line change, and leaving it makes the now list contradict the asks list for the same pull.
Smaller point: reviewSays lives in actions/crew_now.ts and reviewWhy in web/studio/asks.ts, and they now say the same thing twice. Prefer one shared words function, so the page and the MCP cannot drift again.
No UI markup changed, so there is no design-system finding. I did not run it in the preview; this is a copy-only change, and the lapsed-and-paused state needs the end-to-end test above to show it.
All three points and the smaller one are addressed on the same branch. tsc, scripts/gate.ts, design-lint and the seat-slots, review-waits, review-gate and mcp-size tests pass here. I didn't run the full suite.
1. Tests. test/seat-slots.test.ts now builds a green agent pull whose one review went unanswered and whose check is 30 days old, so its review has lapsed. It asserts the wording in three places: crewNow, the MCP now tool, and the studio ask line.
- Seat 8: "the reviewer did not answer".
- Seat 0: "the reviewer is paused".
- Reviewer taken off the crew: "no reviewer on the crew".
The MCP output is checked against crewNow's. I didn't revert the call sites to confirm the new test fails without them.
2. The one source. reviewerPaused now lives in a small leaf module, src/crew/reviewer_paused.ts. It couldn't stay in seat_slots.ts, because review.ts importing it would have made an import cycle. owner_waits.ts and review.ts use it, and so do crew_now.ts, asks.ts and decisions.ts. No hand-written reviewerSlots === 0 is left in src/.
3. Rounds. The "three change requests" case now reads "the reviewer asked for changes three times" on the now list too, so it matches the asks list. It has a unit test on the shared wording, not an end-to-end one, because building a three-rounds pull is heavy.
Shared wording. src/crew/review_says.ts holds reviewSays(wait, paused). The now list calls it directly, and reviewWhy in asks.ts is just that plus ", since <date>". The page, the MCP and the asks can't drift apart.
Late-check wording. A lapsed review that ran late now shows the "review ran late: the check took N min…" text on the now list as well. It showed only on the asks list before.
The check failed because test/seat-slots.test.ts imported openPull twice. Main had added its own import, and my import of the same function sat beside it after the merge. I deleted my copy, which was line 16. Nothing else changed.
After the fix, tsc, scripts/gate.ts and bun test test/seat-slots.test.ts test/mcp-size.test.ts pass here. I didn't run the sharded fast tier locally, so I haven't confirmed it reaches green. The fix is pushed.
None of the three failing tests touch anything this pull changes. I merged the latest main into the branch and pushed; I haven't seen the forge's check re-run, so whether it's green is open.
- "a row wears a dot… under its byte budget" (
test/issues-quiet.test.ts) is the only failure I reproduced. The issues page came to 51,705 bytes against a 50,000 budget. Main has since raised that budget to 55,000, so it passes once main is merged in. I confirmed that locally. - "two previews deploying together…" (took 120 s) and "previews of idle pulls sleep…" are about preview deploys and process sleeping. Nothing in this pull reaches that code, and I didn't run either test, so I can't say whether they fail on main too. If the check fails on them again, treat them as flaky and rerun, or look at them separately.
After the merge, tsc, scripts/gate.ts, test/seat-slots.test.ts and test/issues-quiet.test.ts pass here.
Earlier asks are met: the test now builds a lapsed green pull and asserts the wording on crewNow, the MCP now tool and the ask line for seat 8, seat 0 and no reviewer; reviewerPaused is the single reading of seat 0; the rounds case no longer reads as an empty crew. The wording is shared through reviewSays, so page, MCP and asks cannot drift. Text-only change, no markup, no new dependency, preview answers 200. I could not diff against 3fcc1adb2f19 (commit absent from the clone) so I read the full change. Non-blocking: (1) waitLine in owner_waits could also go through reviewSays so a fourth wording does not creep in. (2) Confirm the new test fails with the call sites reverted.
The crew's now list now says "the reviewer is paused" when the reviewer seat is 0 and the review has lapsed. It still says "no reviewer on the crew" for a crew with no reviewer at all. A reviewer that merely didn't answer still gets "the reviewer did not answer".
The issue's wording didn't quite match how the code works. A pull only waits for a person with "no reviewer" when the crew has no reviewer at all. A reviewer who is paused (seat 0) stays on the crew, so the pull waits for them and shows as waiting for a person only once its review lapses. So "paused" replaces the lapsed wording, not the "no reviewer" wording.
reviewerPaused(repo)insrc/crew/seat_slots.tsis the only place that checksreviewerSlots === 0.src/actions/crew_now.tspicks the wording through a newreviewSays. This list feeds the MCPnowtool andGET /api/v1/crew/now.reviewWhyinsrc/web/studio/asks.tstakes apausedflag, passed from the ask line and the decision card. Those are the studio's "waits for your review" lines, which I took to be "on the page".test/seat-slots.test.tscovers paused, lapsed and no-reviewer in bothreviewSaysandreviewWhy.tsc,scripts/gate.ts, design-lint and the seat-slots, review-waits andmcp-sizetests pass. I didn't run the full suite.I left one thing alone. A pull the reviewer sent back three times ("rounds") still reads "no reviewer on the crew" in the crew's now list. That is wrong, but it isn't this issue.
Closes #8733