Public: anyone can read this; the crew can change it.
Watch a milestone: its progress in the feed, and one push to the phone when it lands #821
Check · Review · Land · Live done — Landed and live in production.
Closes #732
shipped production is serving it for issue #732 — its issue is already done deploy 5431a5f
Final description (the pull body above was the early placeholder). Closes #732. Stacked on #737, which is stacked on #708: the diff against main is this pull's own once those land. Carries migration 56 (milestone_watch), appended at the end (it was 54 on the first commit; main has since landed 54 and 55).
What a person sees
- On a milestone, one button: Watch. Pressed, it reads Watching; pressing it again stops. It is there for a person who is signed in, and it is each person's own.
- In the feed, one item for each milestone they watch, and only when there is something new:
“Release one” is 2 of 7 done: 2 merged since you last looked (…). The item is renamed as the milestone moves, so it is one item however many pulls merge, and a dismissal holds only until the next one does. When it lands the item says so; when it was dropped or split it says it will not land as written. - On the phone, one line when it lands, with a link to the milestone. Landed means its issue closed as done, or the last open issue beneath it closed. Progress never pages; a dropped or split milestone does not page.
How it is built
core/watches.ts: one row per person and issue, andwatchedBy(db, viewer, now), the ONE reader of what a watch says. It reads the plan (core/milestones.ts) as that person, so nothing is stored about progress and nothing is said for a repository they can no longer read.feed/items.ts: amilestonecandidate fromwatchedBy. "Since you last looked" is since they last opened the item from the feed (the feed's ownopenedinteraction), or since they began to watch.crew/notify.ts:landedLinesbeside the asks and the new-account lines. Same once-per-id rule, same hourly bound, same baseline after a restart. A line may now carry its own link.actions/watches.ts: who may. A watch is the person's own state, like a dismissal or a mute: no event is appended and nobody else is told.- Page
POST /:owner/:name/milestones/:number/watch; APIPUTandDELETE /api/v1/repos/:owner/:name/milestones/:number/watch(a write token) andwatchingon the milestone's read; MCP toolwatchandwatchingonmilestones.
Who may
A person, for themselves, in a repository they can read. An agent does not watch. A read token reads watching and cannot change it. A repository that cannot be seen, and an issue that is no milestone, give the one not-found answer.
What it adds and what it removes
It adds one button to the milestone page and one kind of feed card. No other screen did this job, so nothing is removed. The watched card has no "Mute app" button: muting an app does not mute what the person chose to watch, and the way to stop is the Watch button, one tap from the card.
Tests
test/watches.test.ts (in GATE), refusals first: nobody, an agent, a read token, a hidden repository, an issue that is no milestone and a post from another origin watch nothing. Then: the button is each person's own and the read says which; the feed says nothing until the milestone moves, then one item that follows it; opening it quiets it until the next merge; landing pages once, with the link, and progress never; dropped says so and does not page; a person who lost access hears and sees nothing while a person who kept it does.
With #769 (limb actions)
Both pulls put a row of actions under the milestone's head. They are independent; whichever lands second merges the two rows into one (Watch first, then the admin's actions). I own both and will do that merge.
🤖 Generated with Claude Code
At 50dca9a: main merged (69b28c7, the whole milestone stack included). The migration is now 65, appended last. What the merge touched beyond conflicts resolved both ways: the milestone page shows one row of actions, Watch first and then the admin's limb actions (limbActions takes the lead element); the feed's kind list gains milestone beside main's tell, reply and look; the watched card keeps no "Mute app" button; issue.closed joins the feed's live events; the MCP tools list is milestones, watch, limb, returns, spend in that order.
🤖 Generated with Claude Code
Closes #732
In progress (steward build team). Stacked on #737 (milestones) and #708, so the diff against
mainincludes them until they land. Carries migration 54 (milestone_watch), appended at the end.So far: the Watch button on a milestone, one feed item per watched milestone that follows it, one push when it lands, the API and MCP paths, and the tests (refusals first). Looks and docs follow on this branch.
🤖 Generated with Claude Code