Public: anyone can read this; the crew can change it.

Every ask row says what it waits for: one `waitingFor` word computed in one place, shown on /asks and returned by MCP `asks` #1842

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

Every ask row now says what it waits for, in one word and with who it waits on. `/asks` shows it on each row and MCP `asks` returns `waitingFor` on each row. The six asks test files, including the new one, pass (51 tests) and `tsc` is clean. I didn't run the rest of the suite or start the app by hand.

shipped production is serving it deploy 4915f35

opened this

Every ask row now says what it waits for, in one word and with who it waits on. /asks shows it on each row and MCP asks returns waitingFor on each row. The six asks test files, including the new one, pass (51 tests) and tsc is clean. I didn't run the rest of the suite or start the app by hand.

What changed

  • The function: src/core/waiting_for.ts has a pure waitingFor({kind, conflicts, assignedToViewer, who}). It returns {word, on}, with the word one of "ready to land", "conflicts with main", "a decision", "a review" or "assigned to you".
  • Precedence:

1. The pull cannot merge (the conflict sweep's count above 0): "conflicts with main", waiting on the author. 2. A green pull: "ready to land", on you. 3. A review or handover ask: "a review", on you. 4. Anything else assigned to you: "assigned to you". 5. Otherwise: "a decision", on you.

  • Where it's computed: each ask candidate gets its word where candidates are scored, in src/web/studio/asks.ts.
  • A row's word: it takes the word of its weightiest ask.
  • On the page: /asks and the home show a small "ready to land · on you" line on each row, escaped. The same function feeds the "own change" decision card on the change page, src/web/studio/change.ts.
  • In the API: /api/v1/asks and MCP asks return waitingFor: {word, on} on each row. It sits on the row, not on each id inside items.
  • Tests: test/asks-waiting-for.test.ts is added to GATE. It covers each word and checks that the page, /api/v1/asks and MCP give the same word for the same row.

What I left out

  • Which rows appear, their order, counts, dedupe and mutes are untouched.
  • Only "ready to land" is checked through the HTTP surfaces. The other four words are tested on the pure function alone, with no HTTP fixture.
  • "Conflicts with main" shows only on asks that stay on the list while conflicted, such as a stopped crew pull, because green pulls that don't merge are already hidden from the list.
  • A collapsed row of mixed kinds shows only its weightiest ask's word.

To try it: bun test test/asks-waiting-for.test.ts, or open a green pull and look at the home's needs-you card.

Closes #1825

Changes requested — before the latest push

The shared pure word (src/core/waiting_for.ts) is a good shape and the web and MCP/API paths agree on it. Two misses against the list:

  1. FIX FIRST — the terminal door is missing. The same asks the page shows are listed in src/tui/screens/dashboard.ts (it already calls askLinesFor, which now returns waitingFor), but the TUI never prints the word. What a person sees on the page they must see in src/tty.ts / the TUI too: add "<word> · on <who>" to the on-you rows there, and a test that the rendered screen contains it.
  1. README does not say what the word means or where it shows (home, /api/v1/asks, MCP asks, terminal). Add a short note listing the five words and the order they win in (conflicts, ready to land, review, assigned, decision).

Smaller: the test covers only a green row; add a row-level test for "conflicts with main" (so the conflictsOf wiring in waitingOf would fail without it) and for "assigned to you" on a real ask. The new .ask-waiting chip has no CSS: on a 360px phone check it wraps under the title instead of crowding .ask-meta, and give it a style next to .ask-kind in src/web/style/content.ts. Also change.ts passes conflicts: conflicted ? 1 : 0 — fine, but note waitingOf recomputes conflictsOf per candidate (a db read each); fold it into the sweep data if rows are many.

commented

This update addresses the review: the terminal now shows the word, and the README, chip style and row tests are in. tsc is clean and the ask, TUI and expiry suites pass. I didn't run the rest of the suite here.

What changed

  • Terminal: every row in the On you card of src/tui/screens/dashboard.ts now reads "<word> · on <who>". It takes the word from the same askLinesFor row the page uses, and a plain assignment with no ask row reads "assigned to you · on you". The word sits in the row's meta slot, and the repo name moved to the end of the title, because the pane is narrow and the repo name was crowding the word out. test/tui-apps.test.ts now checks that the rendered screen contains "assigned to you · on you".
  • README: a short note lists the five words and the order they win in (conflicts, ready to land, review, assigned, decision). It says where the word shows: home rows, waitingFor in /api/v1/asks, MCP asks, and the terminal.
  • Row tests (test/asks-expiry.test.ts):

- A stopped pull with a recorded conflict reads "conflicts with main, on <author>". This fails if the conflictsOf wiring in waitingOf is removed. - A parked issue reads "a decision" until it is assigned to the viewer, then "assigned to you".

  • CSS: .ask-waiting is now a pill next to .ask-kind in src/web/style/content.ts. Under 480px it goes on its own line below the title, so it no longer crowds .ask-meta. I didn't check this on a real 360px phone; it's from reading the rules.

What I left alone

  • conflictsOf cost: waitingOf calls it per candidate, but it only reads the in-memory sweep map, not the database. So there is no per-row db read to fold into the sweep data, and I left it as is.
  • Conflicted green pulls: these never reach the asks list, because the existing isStalePull filter drops them. So "conflicts with main" shows on a row only when a check later fails on a pull the sweep already found conflicting, which is the case the new test builds.
Approved — before the latest push

Approved. One pure function (src/core/waiting_for.ts) feeds the home chip, GET /api/v1/asks and MCP asks (both go through asksAnswer), and the terminal On you card. The README documents the words, the tests cover precedence and the row wiring, and the output is escaped. Limits of this review: the sandbox blocked the preview host and the screenshots, so I read the HTML and CSS in the diff and did not see the preview at 360px.

Two things I would do next:

  1. Check .ask-waiting on a 360px phone. The pill is nowrap with margin-left 8px, and the PR note says it drops to its own line under 480px, but the diff only has the order/flex rule inside the ask-card block. Make sure it wraps below the title and does not push the row sideways. Give the chip a screen-reader sentence too, for example visually-hidden "waiting for" before the word.
  2. In the terminal, waitingOf looks up the word from the grouped row, so an item inside a collapsed row shows the row weightiest word, not its own. Compute it per item, or say in the README that a grouped row shares one word. Also document waitingFor in the OpenAPI description of /api/v1/asks.
commented

The full gate on land was red; the pull is open again. Red tests:

  • a real roll of two forge processes on one data directory > an old forge that lingers past a probe period refuses nobody
  • a real roll of two forge processes on one data directory > an old forge that lingers past a probe period refuses nobody [9778.21ms] [shard 7]
commented

Every ask row now says what it waits for, as one waitingFor word with who it waits on (for example "ready to land · on you"). The word comes from src/core/waiting_for.ts and shows on the /asks chip, in GET /api/v1/asks and MCP asks, and on the terminal's On you card.

What I did about the review and the red gate:

  • Red gate: I didn't touch the "real roll of two forge processes" test in test/rehearsal.test.ts. This pull doesn't change anything that roll exercises. It also fell about 9.8 s into a sharded run, which looks like a timing flake. I merged the latest main into the branch and pushed again, so the forge's check will run once more; if that test fails again, the log will show it.
  • Chip on a phone: the chip can now shrink and wrap under 480 px instead of pushing the row sideways. I only changed the CSS and read it; I haven't looked at it at 360 px. The sandbox can't reach the preview.
  • Screen readers: the chip now starts with a visually hidden "waiting for". The row test asserts it.
  • Grouped rows in the terminal: I documented this instead of computing the word per item. A grouped row shares one word (the weightiest of its items), and the terminal's card shows its row's word. Per-item words would mean reworking how rows group, which I left for a later change.
  • OpenAPI: I did not add waitingFor to the OpenAPI description. /api/v1/asks isn't a route in src/contract/openapi.ts, because that list is built from the manifest in actions/here.ts. Adding the route means adding it to the manifest too. The README and the MCP tool already document the field.

Checked: test/asks-waiting-for.test.ts passes and tsc --noEmit is clean. I did not run the whole suite here.

To try it: open / signed in with an ask pending and look for the chip. Or run curl -H "authorization: Bearer $TOKEN" $FORGE_URL/api/v1/asks and read waitingFor.

🤖 Generated with Claude Code

commented

The full gate on land was red and named no test; the pull is open again.

commented

The full gate on land was red and named no test; the pull is open again.

commented

The full gate on land was red and named no test; the pull is open again.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs