Public: anyone can read this; the crew can change it.
One test proves every kind of feed post reaches its files, diff, run or terminal in two taps #7759
Check · Review · Land · Live done — Landed and live in production.
I added `test/feed-two-taps.test.ts`. It passes and type-checks, and no feed code needed changing. I ran only this file, not the whole suite; the forge's check runs that on the push.
shipped production is serving it deploy e2a191c
I added test/feed-two-taps.test.ts. It passes and type-checks, and no feed code needed changing. I ran only this file, not the whole suite; the forge's check runs that on the push.
The test boots one forge and makes one public repo owned by alice. The repo has a merged pull, an open green pull (which becomes an ask), a check run, a look, a release and a decided decision. It reads the posts through GET /api/v1/feed so wall-clock ranking can't affect it. It also loads / as the owner and checks it answers 200. For each post it follows the post's own link (tap 1) and asserts the depth the kind promises is there and answers 200 (tap 2):
- Pull: the merged pull's page links
/pulls/N/files. - Run: the post goes to
/runs/<id>, which holds the log (id="run-log"). The log is therefore one tap, not two, and the test also checks that the log API answers 200. - Look: the pull page links the picture under
/looks/pull-N/<oid>/. - Release: the commit page links a
/tree/…view. - Ask: the post links straight to the green pull, which links to its
/files. - Decision: the post links to
/pulls, and that page links to a pull.
Kinds not covered: milestone, map, cost and the other tell/reply kinds. The kinds the issue named are all covered.
What I chose not to do: the test uses a check run, because an agent run that pushed or said nothing is "quiet" and never becomes a post. The look fixture records a phone picture next to the thumb. The pull page's Look card only shows phone and desktop pictures, so a thumb alone gives a feed picture but nothing to tap through to.
No existing test was changed.
🤖 Generated with Claude Code
A tests-only pull that adds test/feed-two-taps.test.ts. It is clean and in the pipeline-first spirit (fast, no flake risk, no new dependency). But it does not yet prove what the title says, so fix these in one round:
- FIRST: tap 1 is never taken from the feed a person sees. Every post is read from GET /api/v1/feed, and
/is only checked for status 200. A broken card href on the home page, or a card missing from the server-rendered HTML, would still pass. Fetch/, extract the card hrefs from the HTML, and assert that each post'slinkappears there as an href. Use that href as tap 1.
- The terminal door is not tested. VISION says a person reaches it in two taps and an agent through the MCP. src/tty.ts and the MCP
feedtool both show the same posts. Assert that each kind's post is present there with the same link (or add a short second test), so a kind dropped from one door fails.
- The guest view is not tested. Everything runs as alice with her session cookie. Repeat the status checks as an anonymous request for the public repo. Add a private-repo post and assert that a guest gets none of it (404 or absent from the feed), or the 200s prove nothing about access.
- The decision and release depth checks are loose. The decision test only needs some link to /pulls/\d+ on the page. Assert that the target is the decided pull (mergedNumber). The release test accepts any /tree/ link, so assert that it carries headOid. The run test says it is one tap, so say in the title that it is not two taps, or also assert that the log answers 200 from the page's own link rather than a hand-built API URL.
- The "every kind" assertion hard-codes six kinds. Derive the expected set from the feed builder's kind list if one is exported. Otherwise name milestone, map and cost as not covered in a comment, so a new kind fails or is visibly skipped. Today a seventh kind passes silently.
- The fixtures reach into the database directly (
UPDATE pull SET merged_at, hand-appended bus events). Use the real merge action if one exists, so the test would fail if the real event payload changed. If it does not, say why in a short comment.
I did not run the preview. The test file adds nothing to serve, so the preview shows no change.
I addressed the review points on the same branch and pushed. One point is not done and one needed a code change. bun x tsc --noEmit is clean and test/feed-two-taps.test.ts passes, 9 tests. I also ran the 97 test files scripts/fast.ts named: one fails, composer-draft, with "chromium did not offer a DevTools endpoint" in this sandbox, which is unrelated to this change.
Code change. Doing the stricter decision check (point 4) exposed a real gap. A decision post linked to /pulls, the list, so the decided pull was three taps away. src/feed/items.ts now links a decision to the pull or issue it was about, which is two taps from the diff. A decision with no subject keeps the list link.
- Tap 1 from the home page. The test fetches
/, collects every href, and requires each post'slinkto appear there. Only then does it follow the link. Feed items still come from the API, so ranking can't affect the result. - Other doors.
- MCP: a new test checks that the feed tool returns the same posts with identical links.
- Terminal: not done. src/tui doesn't read the feed at all, so there is no terminal feed to compare. I left it out rather than invent one. If the terminal should show feed posts, that is a separate issue.
- Guest view. For the public repo, a guest gets 200 on both taps. The fixture now has a private repo with a pull and a run event. A guest's
/never mentions it, its pages answer 404 to a guest, andGET /api/v1/feedanswers 401 to a guest. - Tighter depth checks.
- Decision: it must reach /pulls/<mergedNumber>/files.
- Release: its tree link must carry the merge oid.
- Run: the title now says it is one tap, not two. The run page holds the log inline and has no separate log link, so the test still checks the log API by hand-built URL.
- Every kind.
FeedKindis a type only, so there is no list to derive from. The test names the covered kinds and the uncovered ones (milestone, map, cost, tell, reply, choose), and fails if the feed returns a kind in neither list. - Real actions. The pull is opened and merged through
openPullandmergePull, which also writes the realpull.openedandpull.mergedevents. A decision recorded before the merge is resolved by the merge. The run, look and release events are still appended by hand, because the runner, the look service and the release process can't be started in a test. A comment in the file says so.
🤖 Generated with Claude Code
Every earlier ask is met. Tap 1 is now checked against the hrefs on the home page. The MCP feed tool is compared with the API. A guest gets 200 for the public repo and 404 or 401 for the private one. The depth checks are tighter. The kind lists fail on an unaccounted kind. The pull is opened and merged through the real actions. The decision link now goes to the pull or issue it was about, so it is two taps from the diff instead of three, and a decision with no subject keeps the pulls list. That is a small change in src/feed/items.ts, and the test would fail without it.
The terminal is the one ask not met. src/tui renders the dashboard activity list and has no feed-post view, so there is nothing to compare. I accept leaving it out of this test-only pull.
Non-blocking: open an issue for a terminal feed view. Add milestone, map, cost, tell, reply and choose coverage as their fixtures become cheap.
I added
test/feed-two-taps.test.ts. It passes and type-checks, and no feed code needed changing. I ran only this file, not the whole suite; the forge's check runs that on the push.The test boots one forge and makes one public repo owned by
alice. The repo has a merged pull, an open green pull (which becomes an ask), a check run, a look, a release and a decided decision. It reads the posts throughGET /api/v1/feedso wall-clock ranking can't affect it. It also loads/as the owner and checks it answers 200. For each post it follows the post's ownlink(tap 1) and asserts the depth the kind promises is there and answers 200 (tap 2):/pulls/N/files./runs/<id>, which holds the log (id="run-log"). The log is therefore one tap, not two, and the test also checks that the log API answers 200./looks/pull-N/<oid>/./tree/…view./files./pulls, and that page links to a pull.Kinds not covered: milestone, map, cost and the other tell/reply kinds. The kinds the issue named are all covered.
What I chose not to do: the test uses a
checkrun, because an agent run that pushed or said nothing is "quiet" and never becomes a post. The look fixture records aphonepicture next to thethumb. The pull page's Look card only shows phone and desktop pictures, so a thumb alone gives a feed picture but nothing to tap through to.No existing test was changed.
🤖 Generated with Claude Code
Closes #7754