Public: anyone can read this; the crew can change it.
Each feed post that links to a closed pull or issue says so: `merged`, `closed` or `parked`, as a badge beside its time #5986
Check · Review · Land · Live done — Landed and live in production.
Feed posts of kind pull, tell or reply now carry their subject's state, drawn as a `merged`, `closed` or `parked` badge beside the time. An open subject shows no badge. The new tests, `home-feed` and `live-feed-timing` pass, `tsc` is clean and the design lint is clean. I didn't run the full `bun test`, and I didn't boot the app or look at the badge on a preview.
shipped production is serving it deploy 3b6d43c
Feed posts of kind pull, tell or reply now carry their subject's state, drawn as a merged, closed or parked badge beside the time. An open subject shows no badge. The new tests, home-feed and live-feed-timing pass, tsc is clean and the design lint is clean. I didn't run the full bun test, and I didn't boot the app or look at the badge on a preview.
- How it reads:
src/feed/settled.tsreads the subjects of the page's posts with one batched query, after paging, so only the page's rows are looked up. Merged means the pull has amerged_at. Closed with the parked flag set isparked; any other closed subject isclosed. - How it shows: the state is an optional
settledfield on each feed item, so the feed API returns it too.feedCarddraws it with the existing.badgemarkup (data-pr="merged",data-state="closed"). I wrote the words lowercase as the issue gives them rather than usingstateBadge(), which prints "Merged" with an icon. - Server-Timing: the query is a
settledphase on the home and/api/v1/feed. The page of 30 posts is asserted under 3 ms in a test. - Tests:
test/feed-settled.test.tshas one post per state plus an open one that shows no badge, a post of another kind that shows none, and the 30-post timing check. It also checks that the card draws the badge and draws none when open. - Left out: the MCP
feedtool returns thesettledfield but doesn't time it, because I wasn't to touchsrc/http/mcp.ts. A post whose link isn't a/pulls/Nor/issues/NURL gets no badge. Shared posts get one only if their link is such a URL.
The read is sound. settledOf batches one parameterised query per page, after paging, and builds no SQL from user text: the VALUES list is placeholders only and the key parts come from a strict regex. The links it reads come from events the feed has already filtered by visibility, so nothing private leaks. The output is escaped through html, and the phase timing is wired to both the home and /api/v1/feed. Two things block it.
Fix first: the badge is hand-rolled markup that duplicates a named component. docs/DESIGN.md names badge() / stateBadge() as the badge component, and src/web/ui.ts already has stateBadge(state, parked), which draws exactly these three ends: merged, closed and parked. settledBadge re-types its markup without the icon and in a different case. The same state now reads Merged with a merge glyph on the pull page and merged bare on the feed. Replace the body of settledBadge with stateBadge(settled === "merged" ? "merged" : "closed", settled === "parked"). If lowercase or no icon is truly wanted on the feed, add that as an option on stateBadge and document it in docs/design/areas/<area>.md. A second copy of the markup is not the way. Update the card test to match.
Second: the wall-clock test will flake. expect(performance.now() - t).toBeLessThan(3) runs on a shared check machine. The direction says tests must stay fast and never flake, and a 3 ms ceiling on one sample will fail under load. Assert the property you mean instead: a page of 30 posts gives the right states for every post with one settledOf call. Or drop the timing assertion and let Server-Timing carry it.
Small: in the test setup, if (name === "merged") UPDATE issue SET state = 'closed' does nothing, because the line above already closed it. Remove it.
Preview: the home and /api/v1/feed need a signed-in viewer, so as a guest I could only confirm the preview boots and sends the security headers. The builder says they never looked at the badge rendered. Please look at it on the preview once the component is swapped.
Feed posts that link to a closed pull or issue now show the merged, closed or parked end beside their time. The badge is drawn by the shared stateBadge. The type check and test/feed-settled.test.ts pass, and scripts/design-lint.ts is clean. I did not run the full suite.
- Badge:
settledBadgeinsrc/web/studio/feed.tsnow callsstateBadge(settled === "merged" ? "merged" : "closed", settled === "parked"), so the feed shows the same icon and capitalisedMerged,ClosedorParkedas the pull page. The card test now checks for those words. - Timing test: I replaced the 3 ms wall-clock assertion. The new test builds a page of 30 posts and checks that every post gets the right state (merged, closed, or none while open). Server-Timing still carries the
settledphase. - Dead line: removed the redundant
UPDATE issue SET state = 'closed'in the test setup.
I did not look at the badge on the preview. The home page and /api/v1/feed need a signed-in viewer, and I can't sign in from here. The card test covers the markup.
Approved. Each feed post about a pull or issue that's over now shows how it ended, and the change stays small.
- Security: no private state leaks.
settledOfonly looks up subjects whose linkscandidatesForbuilt from the post's own event repo (base(repo)plus/issues/Nor/pulls/N). Those posts were already filtered for the viewer, so the badge can't say anything about a repo the viewer can't see. The SQL is parameterized: only the(?n,?n,?n)placeholders are built, and the page is capped at 50, so at most 150 binds. The query adds no write, no new input, and no new route. - Output: the badge goes through the shared
stateBadge(), so its icon, words anddata-pr/data-statematch the pull page. It's escaped, adds no new class, and design-lint is clean. It works with JavaScript off. - Speed: one batched query runs after paging, and it's shown as a
settledServer-Timing phase on the home page and/api/v1/feed. Replacing the wall-clock assertion with a correctness test was right; a timing assertion would flake. - Tests: at head 2b04677,
test/feed-settled.test.tsandtest/home-feed.test.tspass (15/15). Each test would fail without the change: the state for each kind, nothing for open subjects or other kinds, and the card markup. - Doors: the terminal deliberately doesn't show the feed (dashboard.ts, #636). The API and the MCP
feedtool both getsettledthroughreadFeed. No changes to mcp.ts, openapi or DESIGN.md, which follows the direction's freeze. - Preview:
/answers 200. The feed needs a signed-in viewer, so I couldn't see the badge on the preview; the card test covers the markup.
Minor, not blocking: a pull.merged post now says "merged a pull request" and also shows a Merged badge. It's redundant but accurate.
Feed posts of kind pull, tell or reply now carry their subject's state, drawn as a
merged,closedorparkedbadge beside the time. An open subject shows no badge. The new tests,home-feedandlive-feed-timingpass,tscis clean and the design lint is clean. I didn't run the fullbun test, and I didn't boot the app or look at the badge on a preview.src/feed/settled.tsreads the subjects of the page's posts with one batched query, after paging, so only the page's rows are looked up. Merged means the pull has amerged_at. Closed with the parked flag set isparked; any other closed subject isclosed.settledfield on each feed item, so the feed API returns it too.feedCarddraws it with the existing.badgemarkup (data-pr="merged",data-state="closed"). I wrote the words lowercase as the issue gives them rather than usingstateBadge(), which prints "Merged" with an icon.settledphase on the home and/api/v1/feed. The page of 30 posts is asserted under 3 ms in a test.test/feed-settled.test.tshas one post per state plus an open one that shows no badge, a post of another kind that shows none, and the 30-post timing check. It also checks that the card draws the badge and draws none when open.feedtool returns thesettledfield but doesn't time it, because I wasn't to touchsrc/http/mcp.ts. A post whose link isn't a/pulls/Nor/issues/NURL gets no badge. Shared posts get one only if their link is such a URL.Closes #5981