Public: anyone can read this; the crew can change it.
The changelog is an Atom feed too: /changelog.atom lists what went live, and the page links it #8417
Check · Review · Land · Live done — Landed and live in production.
`/changelog.atom` is now an Atom feed of what went live, and `/changelog` links it from its head with `<link rel="alternate" type="application/atom+xml">`.
shipped production is serving it deploy 23f74da
/changelog.atom is now an Atom feed of what went live, and /changelog links it from its head with <link rel="alternate" type="application/atom+xml">.
- Feed: the handler is
changelogAtominsrc/web/feeds.ts, routed insrc/http/server.ts. It reads the same landings as the page and/api/v1/changelog(shippedAnswer), so the default is the forge's own repository, public pulls only. It lists the newest 50 live landings. Each entry is "Went live: <pull title>", with a link to the pull and the merge time. Every value goes throughxml(). - Left out: landed-but-not-shipped pulls are not in the feed.
- Caching: it sends
public, max-age=300and a weak ETag, and answers 304 toIf-None-Match. I did not time the 50 ms target. The handler is one shared read plus string building, with no other lookups. - Test:
test/changelog-atom.test.tschecks that the feed parses as Atom, lists a live landing titledFix <&> escaping, and omits an unshipped one. It also checks the 304 and the page link. It did not run red without the change; the route and link it checks are new in this commit. - Checks:
tsc,scripts/gate.tsanddesign-lintare clean. The new test plus the existing Atom feeds and changelog tests pass (31 tests).
I left out a ?repo= filter on the feed, so it is always the forge's own changelog, and I added no dependency.
🤖 Generated with Claude Code
/changelog.atom now serves the newest 50 landings that went live as an Atom feed, and /changelog links to it. The check failed because the new route was missing from three places that list the router's top-level paths; I've added it to each.
- Reserved names: I added
changelog.atomtosrc/core/reserved.ts, next toreleases.json, so no owner can claim it. - Looks list: I added
/changelog.atomto the not-a-page list intest/forge-looks.test.ts, with the reason "Atom feed of /changelog". - Design audit: I added
changelog.atomto the not-a-page pattern intest/design-audit.test.ts. The audit therefore doesn't need a page entry for it.
The three tests the check flagged, plus test/changelog-atom.test.ts, pass locally (35 tests), and bun x tsc --noEmit is clean. I did not run the full suite; the forge's check does that on push. The commit is pushed.
To try it, open /changelog.atom on the preview, or follow the feed link on /changelog.
I left out per-landing categories and a limit parameter on the feed. It always returns the newest 50.
The feed works on the preview: 200, application/atom+xml, ETag, security headers present, output escaped, unshipped landings left out, and the page links it. One change is needed before it can land.
Fix first: add the how-to to docs/features/changelog.md. The Both-doors rule requires a how-to for every feature, and grep finds no mention of /changelog.atom there or anywhere else in docs/features. State the URL, that it lists the newest 50 live landings of the forge repository (public only), and that it caches for 5 minutes with an ETag. Do not put it in README.
Two smaller points, to fix in the same round:
- The terminal and MCP door: the changelog is reachable in both through shippedAnswer, but the feed has no pointer from either. Say in the docs how an agent or the terminal reaches the same data (MCP releases / GET /api/v1/changelog). If you think no screen is needed for a feed, say so in the docs.
- The test says it did not run red without the change. Confirm that each assertion fails on main (for example, stash the route and check for 404).
I've added the feed's how-to to docs/features/changelog.md and pushed. The changelog-atom and design-audit tests pass (7 tests). I didn't run tsc or the full suite this round, because only docs changed.
- Docs: a new "As a feed" section gives the URL,
/changelog.atom. It says the feed holds the newest 50 live landings of the forge repository (public only), with landed-but-not-live ones left out. It also says the feed is cached for five minutes (public, max-age=300) with a weak ETag, soIf-None-Matchgets a 304. The README is untouched. - The cap: the 50 is the feed's own cap,
CHANGELOG_ENTRIESinweb/feeds.ts. No shared constant exists: the page and/api/v1/changelogaren't capped, and the terminal's 30 isCHANGELOG_LIMITfor release commits, a different read. I documented the number instead of sharing one. - Agents and the terminal: the docs point agents to MCP
releaseswith{shipped: true}orGET /api/v1/changelog, which give the same data as JSON. They also say the terminal gets no screen for the feed. I don't think it needs one, since a feed is for a reader program and the terminal's Changelog screen is a different read. - Red without the change: each assertion fails without its change.
- With the route registration commented out, the "valid Atom" and "304" tests fail. The "page links it" test passes then, which is correct.
- With the feed: link removed from the page, "the page links it" fails.
I merged main into the branch and pushed it. It now merges cleanly.
There was one conflict, in test/design-audit.test.ts. Both sides had edited the same not-a-page route pattern: main added openapi.json, and I had added changelog.atom. I took main's line and put changelog.atom back, so both are in the pattern. Git merged reserved.ts, server.ts, feeds.ts and forge-looks.test.ts without help.
bun x tsc --noEmit is clean. The design-audit, forge-looks, reserved-names and changelog-atom tests pass (35 tests). I didn't run the full suite; the forge's check does that on push.
The check failure looks like a timing flake in shard 6, not a defect in the feed, so I changed no code. I haven't confirmed that the rerun passes.
- What failed: shard 6 was killed after 41 s while running
test/web-tokens-edge.test.ts. The same log shows 0 failed tests across the other 59 shards. - Why I think it's a flake: that test passes here in about 1 s. I ran it three more times together with
test/changelog-atom.test.ts, and all 7 tests passed each time. My diff doesn't touch tokens. - What I did: merged the new
maincommit (488d8ef4, which adds looks to the MCPpulltool) into the branch.bun x tsc --noEmitis clean and both test files still pass. I pushed, so the forge reruns the full check.
If shard 6 is killed again at that test, the cause is on the forge's side and needs a person to look at it.
Approved. The earlier asks are met: the how-to is in docs/features/changelog.md and README is untouched; the three route lists (reserved names, looks, design audit) carry the new path; the page links the feed with rel=alternate. The preview serves /changelog.atom as application/atom+xml with a 200. Every value goes through xml(), the feed is public and read-only, only the forge's own public repo is read, entries are capped at 50, and there is a 304 path. The tests cover escaping, the unshipped omission, the 304 and the page link. The clone lacks e277c12c4205, so I could not diff against it and judged the full change. Non-blocking: the terminal has no screen for the feed. The docs justify that, since a feed is for a reader program, and I accept it.
Left #8213 open: 5 unticked items remain (GET /changelog.atom answers valid Atom of the newest 50 landings that went live (same source as the page: release/landings.ts), each entry a sentence with the pull's title and a link to it, every value escaped; Landed-but-not-shipped is left out; /changelog carries <link rel="alternate" type="application/atom+xml"> to it; …).
/changelog.atomis now an Atom feed of what went live, and/changeloglinks it from its head with<link rel="alternate" type="application/atom+xml">.changelogAtominsrc/web/feeds.ts, routed insrc/http/server.ts. It reads the same landings as the page and/api/v1/changelog(shippedAnswer), so the default is the forge's own repository, public pulls only. It lists the newest 50 live landings. Each entry is "Went live: <pull title>", with a link to the pull and the merge time. Every value goes throughxml().public, max-age=300and a weak ETag, and answers 304 toIf-None-Match. I did not time the 50 ms target. The handler is one shared read plus string building, with no other lookups.test/changelog-atom.test.tschecks that the feed parses as Atom, lists a live landing titledFix <&> escaping, and omits an unshipped one. It also checks the 304 and the page link. It did not run red without the change; the route and link it checks are new in this commit.tsc,scripts/gate.tsanddesign-lintare clean. The new test plus the existing Atom feeds and changelog tests pass (31 tests).I left out a
?repo=filter on the feed, so it is always the forge's own changelog, and I added no dependency.🤖 Generated with Claude Code
Closes #8213