Skip to content

Add changelog page - #679

Open
dawn-ducky wants to merge 17 commits into
mainfrom
add-changelog-page
Open

dawn-ducky wants to merge 17 commits into
mainfrom
add-changelog-page

Conversation

@dawn-ducky

@dawn-ducky dawn-ducky commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

Status

READY

Description

Adds /changelog/, a searchable, filterable feed of what shipped to Code Push, the CLI, and the API. It's a StarlightPage next to roadmap.astro, linked from the sidebar right below it.

Entries sit on a timeline. Each has a type badge (New/Fixed/Changed/Deprecated), an area tag, its date, and the CLI release that shipped it, when there is one. It expands in place to show detail bullets, an optional command, a link to the relevant doc page, a link to the GitHub release notes, and a copyable permalink (/changelog/#entry-id). Opening the page with a matching #entry-id expands and scrolls to that entry. Search and the area chips filter the list client-side. The month headings appear under "On this page".

Seeded with ten real changes from CLI 1.6.120 to 1.6.123, checked against RELEASE_NOTES.md and the CLI source. Write future entries from RELEASE_NOTES.md, not the GitHub release bodies, which are auto-generated and leave things out.

Adding an entry: copy src/content/changelog/_template.md to a new file in that folder. The file name becomes the permalink. Fill in the frontmatter, then write a summary paragraph, a bullet list, and an optional sh code block. The template explains each field. The build checks every entry and fails with a file:line message if something is wrong, including a docLink to a page or heading that doesn't exist. version is required for CLI and Flutter entries and optional otherwise, since Console, API, and server-side changes don't ship in a CLI release.

Also served as:

  • /changelog.md, the Markdown version for agents, also listed under Optional in llms.txt. Accept: text/markdown on /changelog/ negotiates to it.
  • /changelog.xml, an RSS 2.0 feed, linked from the page and advertised in its <head>.

Design source: https://claude.ai/design/p/8d6abb36-5f0f-4da2-86d9-636e825acb58 ("Docs Changelog.dc.html", option 3a).

Test plan

  • npm run build (astro check && astro build) passes: 0 errors, 0 warnings, all internal links valid
  • cspell passes on the changed files; changelog.xml validates with xmllint
  • Local preview, light and dark: expand/collapse, title click, text selection, find-in-page into a collapsed entry, search, area chips, empty state, permalink hash, "On this page" month links, RSS link

A searchable, faceted feed of what shipped to Code Push, the CLI,
and the API, with expandable entries carrying detail, a command, and
a doc link. Seeded with one example entry; add to the ENTRIES array
in src/pages/changelog.astro as things ship.

Design: https://claude.ai/design/p/8d6abb36-5f0f-4da2-86d9-636e825acb58

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Area was a free string derived from whichever entries existed; fix it
to the five actual areas (Code Push, CLI, Console, API, Flutter) so
the filter chips are stable regardless of what's in ENTRIES.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@dawn-ducky
dawn-ducky requested review from easymac and wrpeck and removed request for AbhishekDoshi26 September 18, 2026 16:27
The toolbar opts out of Starlight's markdown sibling spacing, which was pushing every chip after "All" down by 1rem.

The expand toggle keeps its button on the badge row, but a stretched ::after covers the whole header so the title and summary toggle the entry too. Links inside the header sit above the overlay. The "+" text glyph is replaced with an SVG so it centers in a larger bubble, and the vertical stroke hides when the entry is open.
@easymac

easymac commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

I think this looks great. I made a couple tiny adjustments:
image

  • Vertically centered the filter chips
  • Vertically centered the + icon for expanding an entry, and made it a little bigger
  • Made it so you can click anywhere in the title to expand the summary

The last change isn't precious, just an idea :)

- The copy button called preventDefault, so the "link still works as a
  fallback" comment was false: a failed clipboard write did nothing.
  Let the link navigate, and show a brief "copied" state on success.
- Open the targeted entry on hashchange too, not just on first load, so
  a permalink followed from the same page expands its entry.
- Search the version, detail bullets, and command, not only the title
  and summary.
- Put the command's pre and code on one line so the template's
  indentation does not render as a leading space.
@AbhishekDoshi26

Copy link
Copy Markdown
Member

Reviewed this. The page structure, the filtering, and the sidebar wiring all look good, and the build is clean (0 errors, 0 warnings). I found a few small issues and pushed the fixes as a55b990:

  1. The copy-link fallback never worked. The .cl-copy handler called ev.preventDefault() before writing to the clipboard. So when the clipboard write failed (permissions, insecure context), nothing happened, even though the comment says "the link itself still works as a fallback". The click also gave no sign that it had copied anything. Now the link navigates normally, so the permalink always ends up in the address bar, and a successful copy briefly shows ✓ with the aria-label "Link copied".
  2. Permalinks only opened on first load. The auto-expand ran once, in init(). Following a #entry-id link from the page itself (or pasting one into the same tab) only fires hashchange, so the entry stayed collapsed. The same logic now runs on hashchange too.
  3. Search skipped most of an entry. data-search held only the title, summary, area, and type. Searching a version number or a flag that appears only in the details returned nothing. It now also covers the version, the bullets, and the command.
  4. The command had a stray leading space. <pre> preserves whitespace, so the template's indentation before <code> rendered as a leading space ahead of $. They're on one line now.

How I checked: ran npm run build and cspell. In a local preview I confirmed that a hash change expands the entry, that version and bullet searches match, that the empty state still appears, and that a real click on copy writes the full URL, shows ✓, and reverts after 1.5s.

Head.astro gives every page a <link rel="alternate" type="text/markdown">
pointing at <path>.md, but [...slug].md.ts only builds those for content
collection pages. The changelog is a standalone .astro page, so its link
pointed at a 404 and Accept: text/markdown on /changelog/ fell back to HTML.

- Move the entries, areas, and month grouping to src/data/changelog.ts so
  the page and the Markdown route read the same data.
- Add src/pages/changelog.md.ts, which renders /changelog.md from it. The
  existing middleware then negotiates /changelog/ to it with no changes.
- List /changelog.md under Optional in llms.txt.
@AbhishekDoshi26

Copy link
Copy Markdown
Member

One more fix, pushed as 3cf311f: the changelog wasn't reachable as Markdown for agents.

Head.astro gives every page a <link rel="alternate" type="text/markdown" href="<path>.md">, but [...slug].md.ts only builds .md files for content collection pages. changelog.astro is a standalone page, so the page advertised /changelog.md, which would 404, and a request for /changelog/ with Accept: text/markdown quietly got HTML instead.

  • Moved ENTRIES, AREAS, the entry type, and the month grouping into src/data/changelog.ts, so the page and the Markdown route read the same list. You still add entries in one place, just in that file now.
  • Added src/pages/changelog.md.ts, which renders /changelog.md: frontmatter, month headings, and for each entry the type, area, version, date, permalink, bullets, command, and doc link. The existing middleware now negotiates /changelog/ to it with no changes.
  • Listed /changelog.md under Optional in llms.txt.

How I checked: npm run build is clean (0 errors, 0 warnings), and Prettier and cspell pass on the changed files. Using wrangler pages dev with the real middleware:

  • Accept: text/markdown on /changelog/ returns 200 text/markdown with Vary: Accept and CORS.
  • A browser Accept header still gets HTML.
  • text/markdown;q=0.5, text/html still gets HTML.
  • /changelog.md returns 200.

New used the theme accent, which is gray in Nova, so it looked like the
area badge beside it. New is now green and Fixed moves to blue, the usual
changelog convention.

Light-mode text also darkens to reach 4.5:1 on the tinted pill at this
size: New #166534 (6.2:1), Fixed #1d4ed8 (5.6:1), Changed #7e22ce (5.7:1,
was 4.4:1), and Deprecated #92400e (6.3:1, was 2.8:1). Dark mode already
passed and keeps its shades, with Fixed at #93c5fd (8.7:1).
@AbhishekDoshi26

AbhishekDoshi26 commented Sep 19, 2026 •

Copy link
Copy Markdown
Member

Pushed 3d897b3 to fix the type badge colors.

New looked like the area badge. It used --sl-color-accent, and the Nova theme's accent is gray, so the NEW pill had almost the same gray text and fill as the CODE PUSH pill next to it. Each type now has its own color: New is green, and Fixed moves from green to blue so the two don't clash. That matches the usual changelog convention.

Light-mode contrast. These are about 11px bold labels, so they need 4.5:1. Measured against the tinted pill on a white page:

Type Before After
New gray, same as the area badge #166534, 6.2:1
Fixed #16a34a, 2.9:1 #1d4ed8, 5.6:1
Changed #9333ea, 4.4:1 #7e22ce, 5.7:1
Deprecated #d97706, 2.8:1 #92400e, 6.3:1

Dark mode already passed. New uses #4ade80 (8.4:1) and Fixed uses #93c5fd (8.7:1); Changed and Deprecated keep their existing shades.

How I checked: npm run build is clean (0 errors, 0 warnings). In a local preview I added the other three badge types to the page and confirmed the computed colors and the look in both light and dark themes.

@AbhishekDoshi26 AbhishekDoshi26 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second pass on this, covering the code and the design in a local preview (dark and light).

One blocker before merge: the seeded entry describes a feature that doesn't exist. See the inline comment on src/data/changelog.ts. That one needs you, since it's about what we actually shipped.

Everything else is small. I'm pushing a commit right after this review that fixes the comments marked (fixing):

  • Accessible name of the entry toggle
  • Title and summary text can't be selected
  • Result count not announced
  • Find-in-page can't reach collapsed details
  • Month grouping depends on array order
  • Double border on the command block
  • Detail panel has no fill in light mode
  • Commands and flags render as plain prose
  • type="search" and white-space on the command

The comments marked (suggestion) are design ideas I left for you to decide on. Also, the PR description still says to add entries in src/pages/changelog.astro. Since 3cf311f they live in src/data/changelog.ts.

Comment thread src/data/changelog.ts Outdated
Comment thread src/data/changelog.ts
Comment thread src/pages/changelog.astro Outdated
Comment thread src/pages/changelog.astro Outdated
Comment thread src/pages/changelog.astro Outdated
Comment thread src/pages/changelog.astro
Comment thread src/pages/changelog.astro Outdated
Comment thread src/pages/changelog.astro Outdated
Comment thread src/pages/changelog.astro Outdated
Comment thread src/pages/changelog.astro Outdated
- Name each entry toggle by its title, and announce the result count.
- Toggle from the header with a click handler instead of an overlay, so
  the title and summary text can be selected.
- Use hidden="until-found" so find-in-page reaches collapsed details.
- Sort entries by date instead of relying on array order.
- Render backticked text in summaries and bullets as inline code.
- Remove the inline-code border inside the command block, give the
  detail panel a fill in light mode, and keep newlines in commands.
The seeded entry described a --rollout flag and CLI 1.7.2, neither of
which exist. Replace it with six changes from CLI 1.6.120 to 1.6.123,
each checked against the release notes and CLI source.

- List the month headings under "On this page".
- Show each entry's date, and label the version as the CLI release,
  with a link to its release notes.
- Add an RSS feed at /changelog.xml, linked from the page and its head.
@AbhishekDoshi26

Copy link
Copy Markdown
Member

Pushed 10ce731. It addresses the rest of my review:

  • Blocker: replaced the example entry with six real changes from CLI 1.6.120 to 1.6.123: --flutter-version=fvm/system, the patch-load fix, Flutter 3.47.4 support, the shorebird apps and shorebird channels commands, and shorebird patches rollback/rollforward. I checked each one against the release notes and the CLI source, and each links to an existing doc page.
  • On this page: the month headings now have ids and are passed as headings, so they show up there.
  • Date and version: each entry shows its date, and the version is labeled CLI 1.6.x, with a release-notes link in the expanded footer.
  • RSS: added /changelog.xml, linked from the page intro and from <head>, with a Content-Type rule in public/_headers.
  • PR description: updated to point at src/data/changelog.ts.

Build is clean (0 errors, 0 warnings, all links valid), and cspell and xmllint pass.

- Put each entry's date and CLI version in a left column, joined by a
  line with a dot in the change type's color. At narrow widths the date
  moves above the badges and the line stays on the left.
- Show live counts on the area chips, dim chips with no matches for the
  current search, and hide areas that have no entries yet.
- Mark the active chip with aria-pressed and a solid fill.
- Replace the permalink text and glyph with a "Copy link" button, and
  shorten the release notes link.
- Keep the chips on one scrolling row on phones.
@AbhishekDoshi26

Copy link
Copy Markdown
Member

Pushed d73ec70, which redesigns the list as a timeline:

  • Layout: each entry's date and CLI version sit in a left column, joined by a line with a dot in the change type's color. The title and summary use the full width. At phone width it becomes one column, with the date above the badges.
  • Chips: they show live counts that follow the search, and a chip with no matches dims. Areas with no entries (Console and API, for now) are hidden until an entry uses them. The active chip has a solid fill and aria-pressed.
  • Footer: the doc link, a shorter "Release notes ↗" link, and a "Copy link" button that says "Copied" on success. It replaces the mono permalink text and the ⧉ glyph.
  • Chip row on phones: the chips stay on one row that scrolls sideways instead of wrapping.

How I checked: npm run build is clean (0 errors, 0 warnings, all links valid) and cspell passes. In a local preview I checked desktop in light and dark, and phone width through a 390px frame. I measured no gaps in the timeline line, the date, dot, and badge row aligned within 1px, and no horizontal scroll at 390px. I also confirmed that the chip counts update while searching and that the live region stays quiet on load.

Each entry is now a Markdown file in src/content/changelog/, named for
its permalink: frontmatter for the metadata, then a summary paragraph,
a bullet list, and an optional sh code block. Copy _template.md to add
one; it documents every field.

The build fails with a message naming the file and line when:
- a field is missing or malformed (date not YYYY-MM-DD, a "v" on the
  version, an unknown area or type);
- a CLI or Flutter entry has no version (Console, API, and server-side
  Code Push entries may omit it);
- docLink points at a page that doesn't exist, or at a missing heading;
- the body has anything besides the summary, bullets, and code block.

The page, /changelog.md, and /changelog.xml render the same as before.
@AbhishekDoshi26

Copy link
Copy Markdown
Member

Pushed 6748c86, which moves each entry into its own Markdown file in src/content/changelog/. To add one, copy _template.md and fill it in. Authors write plain Markdown instead of TypeScript strings with escaped quotes.

The build now fails, with a message naming the file and line, when:

  • a field is malformed: the date isn't YYYY-MM-DD, the version has a "v", or the area or type is unknown
  • a CLI or Flutter entry has no version (it's optional for Console, API, and server-side Code Push changes, which don't ship in a CLI release)
  • docLink points at a page that doesn't exist, or at a heading that isn't on that page
  • the body has anything besides a summary paragraph, a bullet list, and one optional sh block

How I checked:

  • npm run build is clean, and cspell and Prettier pass.
  • /changelog.md, /changelog.xml, and the page's rendered text and attributes are byte-identical to the previous commit.
  • I built 14 test entries: a copy of the template and a Console entry with no version both build, and every broken case fails with the right message and line number.

- Append the changelog to llms-full.txt after the build, since
  starlight-llms-txt only covers docs collection pages.
- List /changelog.md in ai-catalog.json, agent.json, and
  agent-instructions.txt, and tell agents to compare an entry's CLI
  release with `shorebird --version` before suggesting a new flag.
- Say the same at the top of /changelog.md, and stop repeating the
  description there, matching the other Markdown twins.
@AbhishekDoshi26

Copy link
Copy Markdown
Member

Pushed b44cb67, which makes the changelog discoverable to agents. Before this, agents could only reach it through llms.txt, the .md alternate link, and Accept: text/markdown:

  • llms-full.txt: it now ends with the changelog. starlight-llms-txt only covers docs collection pages, so a build hook appends /changelog.md in the plugin's page format. The hook runs after the unlisted-page strip, which counts pages from the end of the file.
  • .well-known: ai-catalog.json has a changelog entry with representative queries, agent.json lists it under endpoints, and agent-instructions.txt tells agents to compare an entry's CLI release with shorebird --version before suggesting a recently added flag, and to suggest shorebird upgrade if the user is behind.
  • /changelog.md: it opens with the same version hint, and no longer repeats the description from its frontmatter, matching the other Markdown twins.

How I checked: the build is clean (0 errors, 0 warnings, all links valid). The build log shows the strip hook running before the append. llms-full.txt has 66 pages, with the changelog last. Both JSON files parse, and changelog.xml still validates.

@AbhishekDoshi26 AbhishekDoshi26 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fresh-eyes pass over the whole PR. The structure holds up. I also confirmed that astro dev picks up entry edits, and recovers from a broken entry once it's fixed, without a restart, so the getEntries() cache isn't a problem.

I found five small issues, all about things an author can write that pass the build but render wrong, plus two edge cases. I'm pushing fixes for all five right after this review.

Comment thread src/data/changelog-schema.ts Outdated
Comment thread src/data/changelog.ts
Comment thread src/data/changelog.ts Outdated
Comment thread src/pages/changelog.astro Outdated
Comment thread src/pages/changelog.xml.ts Outdated
- Fail the build on an unclosed backtick, a Markdown link, bold text, or
  a bare <placeholder> in a summary or bullet, and on any Markdown in a
  title. The page renders only backticks, so these showed up as raw
  syntax on the page but rendered (or vanished) in /changelog.md.
- Require docLink.href to start with "/" or "https://"; a relative href
  passed the check but resolved against /changelog/ on the page.
- Order same-day entries by file name instead of collection order.
- When a permalink or month link targets something a filter is hiding,
  clear the filters so the link goes somewhere.
- Build RSS links from `site` in astro.config.mjs.
@AbhishekDoshi26

Copy link
Copy Markdown
Member

Pushed 55bec5e, which fixes all five items from my review above:

  • Text that renders differently: the build now fails on an unclosed backtick, a Markdown link, bold text, or a bare <placeholder> in a summary or bullet, and on any Markdown in a title. Each error points at the file and line and says what to do instead. The template documents the rule.
  • Relative docLink.href: it must now start with / or https://.
  • Same-day order: entries from the same day are sorted by file name. The template says so.
  • Hidden hash targets: a permalink or month link whose target a filter is hiding now clears the filters, then opens and scrolls to it.
  • RSS links: built from site in astro.config.mjs.

How I checked:

  • The build is clean (0 errors, 0 warnings, all links valid), and cspell and Prettier pass.
  • /changelog.md, /changelog.xml, and llms-full.txt are byte-identical to the previous commit. The page HTML is identical apart from its script.
  • I built six new broken test entries (relative href, unclosed backtick, link, bold, bare placeholder, backticks in the title), and each fails with the right message and line. A copy of the template still builds.
  • In a browser, I searched rollback and then followed the September link, and set the Flutter filter and then followed a permalink to a CLI entry. Both cleared the filters and landed on the target.

@AbhishekDoshi26 AbhishekDoshi26 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more independent review pass. I reproduced or confirmed each finding below before posting.

The main one is about content. I seeded the entries from the GitHub release bodies, but those are auto-generated and incomplete. RELEASE_NOTES.md in shorebirdtech/shorebird is the full record, and it shows that 1.6.123 also shipped Flutter 3.47.5 support and an iOS --split-debug-info fix. I'm adding what's missing for 1.6.120 through 1.6.123: every Flutter version bump, plus the dSYM fix. Future entries should be written from RELEASE_NOTES.md.

I'm pushing fixes for all of these right after this review.

Comment thread src/content/changelog/flutter-3-47-4.md
Comment thread src/content/changelog/failed-patch-checks-for-replacement.md Outdated
Comment thread src/data/changelog.ts Outdated
Comment thread src/pages/changelog.astro Outdated
Comment thread src/data/changelog.ts
Comment thread src/data/changelog.ts
Comment thread src/pages/changelog.astro
Comment thread src/pages/changelog.astro Outdated
Comment thread src/pages/changelog.astro Outdated
Content, checked against RELEASE_NOTES.md in shorebirdtech/shorebird
(the GitHub release bodies are auto-generated and incomplete):
- Add Flutter 3.47.2, 3.47.3, and 3.47.5 support, and the iOS
  --split-debug-info dSYM fix from 1.6.123.
- The 1.6.122 updater fix ships in Shorebird's Flutter 3.47.4 engine,
  not the CLI, and a failed patch falls back to the last installed
  patch, not the base release; say so.
- Describe the changelog without listing areas that have no entries.

Code:
- Keep command lines as written: strip only a "$ " prompt, never a
  $VARIABLE, and keep indentation and blank lines.
- Draw the "$ " prompt with CSS, so copying a command doesn't copy it,
  and skip it on lines continuing a backslash.
- Reject docLinks to unlisted or draft pages, validate absolute
  docs.shorebird.dev links, and accept standalone pages like /roadmap/.
- Also reject italics, HTML entities, backslash escapes, and bare URLs
  in entry text, which rendered differently on the page and in .md.
- Reject entry file names that collide with a month heading's anchor.
- Dim empty filter chips with a dashed border instead of opacity, which
  dropped their text below 4.5:1 contrast.
- Don't let a malformed URL hash stop the page script.
@AbhishekDoshi26

Copy link
Copy Markdown
Member

Pushed f953188, which fixes every item from the review above.

Content

  • Added Flutter 3.47.2, 3.47.3, and 3.47.5 support, and the iOS --split-debug-info dSYM fix. That makes 10 entries covering everything notable in 1.6.120 through 1.6.123, checked against RELEASE_NOTES.md.
  • The 1.6.122 updater entry now says the fix ships in Shorebird's Flutter 3.47.4 engine, and no longer contradicts the rollback docs.
  • The description no longer lists areas that have no entries. This also covers llms.txt and RSS.
  • Updated the PR description to say future entries should come from RELEASE_NOTES.md.

Code

  • Commands: lines are kept as written, and only a $ prompt is stripped, so $ANDROID_HOME/... survives. The prompt is drawn in CSS, so copying a command leaves it out, and continuation lines get no prompt.
  • docLink: unlisted and draft pages are rejected, absolute docs.shorebird.dev links are validated, and standalone pages like /roadmap/ are accepted.
  • Entry text: italics, HTML entities, backslash escapes, and bare URLs are now rejected too. snake_case and _template.md still pass.
  • File names: a name that matches a month heading's anchor is rejected.
  • Empty chips: they're dimmed with a dashed border instead of opacity. The labels now measure 12.85:1 in dark and 10.3:1 in light, and the prompt is 4.84:1 or better.
  • Hash links: a malformed hash no longer stops the page script.

How I checked:

  • The build is clean (0 errors, 0 warnings, all links valid), and cspell and Prettier pass. The page, .md, and RSS each list 10 entries, and the XML validates.
  • I built test entries for every new check. Each broken case fails with the right file:line message, and the valid ones (snake_case, /roadmap/, and a multi-line command with $VARIABLE) build.
  • In a browser, copying a command gives the text without $, and I measured the contrast values above.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants