Home
Release Notes
Weekly release notes for my side projects, written by a bot every Sunday from the week's commits and pull requests.
2026-W43 ·
2026-W42
2026-W43 (Oct 19 to Oct 25, 2026)
5 active days | 2 repos | 45 PRs merged | 9 commits
Week in a sentence: Data now replicates continuously to blob storage and restores from it on every start, with the old file share retired.
brandonchastain/brandonchastain.com
Improvements
- Release notes group each project's work by category and skip anything an earlier week already reported.
brandonchastain/rss-reader
New features
- The Feeds page is a hub of cards: My feeds with a count, Popular feeds, Subscribe, Import / Export and Tags, each opening its own page.
- A feed that fails three times in a row shows a "not updating" badge, with the reason and the last attempt in its row.
Improvements
- Each post is stored once per feed, not once per subscriber, and unsaved posts older than 180 days are deleted nightly.
Performance
- Scheduled refreshes now pace their fetches. At 5 a second, p95 under 50 req/s fell from 513 ms to 30 ms, at the cost of a 5,000-feed cycle taking 999 s instead of 80 s.
- Search answers from the full-text index: a rare word returns in 17 to 20 ms, down from 109 to 216 ms, at the cost of no longer matching words that start mid-word, such as "flare" in "cloudflare".
Reliability
- Deploys no longer return 5xx on /api/user: the CI probe saw none over 61 samples on the deploy that followed the handover fix.
- A failed restore at startup restarts the app and retries, so an empty replica never replaces your database.
Fixes
- Sign-in now survives closing the browser, so a return visit no longer starts at the login button.
Raw activity
brandonchastain/brandonchastain.com
- PR #5 Release notes: group by category and stop repeating earlier weeks
8979310 Release notes: group by category and stop repeating earlier weeks
4c5c668 Release notes: say why the model returned no text, and raise the output cap
8f636ce Release notes: report the impact, and give reliability its own category
f59cdc4 Release notes: a measurement decides how a bullet reads, not whether it ships
13dc102 Release notes: pin the thinking budget so the summary fits in the cap
2557d42 Release notes: adaptive thinking and low effort, not a thinking budget
d251644 Release notes: fix the category order to the one the notes actually read in
brandonchastain/rss-reader
- PR #196 chore(durability): remove the Azure Files share path (spec step 5)
- PR #195 feat(auth): keep the session key ring in blob instead of the share
- PR #194 feat(feeds): make /feeds a hub of cards with a subpage per choice
- PR #193 feat(feeds): tabbed Feeds page with titles, Subscribe/Unsubscribe and tag removal
- PR #192 fix(feeds): always show Popular feeds as a plain top list
- PR #191 feat(feeds): popular feeds section and starter feeds for new users
- PR #190 feat(frontend): offer a reload when a newer build is deployed
- PR #189 chore(auth): retire the Static Web Apps gateway header path
- PR #188 feat(admin): accurate trends, drill-down tables and admin deletes
- PR #187 docs: measured handover numbers, actimeo finding, replica chain report
- PR #186 fix(deploy): drop unsupported mountOptions so #185 can deploy
- PR #185 fix(durability): fresh replica path, chain report, actimeo (supersedes #183)
- PR #184 fix(durability): handover follower retry, probe hold, hourly snapshots, gate-aware checks
- PR #179 feat(durability): rollout step 3, cooperative handover and restore from the Litestream replica (flag on)
- PR #180 fix(deploy): probe the writer lock with an open so a release is seen within one poll
- PR #181 obs(durability): make the writer's shutdown sequence visible in prod logs
- PR #178 fix(durability): make LitestreamSupervisor.DisposeAsync idempotent
- PR #177 fix(durability): Litestream 0.5.17 and replication back on
- PR #175 fix(durability): Litestream 0.5.17 and replication back on; remove the restore-drill workflow
- PR #176 infra(durability): turn blob replication off pending the full-size upload diagnosis
- PR #174 docs: note the two config changes that halve blob replication cost
- PR #173 chore(durability): clear analyzer warnings in the new code; label the Azurite test key
- PR #171 perf(refresh): pace scheduled fetches with a per-second budget
- PR #172 feat(durability): Litestream replication to blob beside the share (rollout steps 1 and 2)
- PR #169 test(load): fixed-rate capacity scenarios and a capacity report at the live size
- PR #168 perf(search): answer from the full-text index; widen only the page that is returned
- PR #167 fix(feeds): keep backoff across restarts; name the real failure; repair two bad bytes
- PR #166 perf(timeline): walk the newest-first index instead of sorting every post; refresh load tests
- PR #165 test(e2e): browser tests of the real stack in CI; surface a refused feed address
- PR #164 chore(config): one-line docs per option, drop dead settings, fix docs
- PR #163 ci: post-deploy sign-in smoke check; a failed sign-in returns to the frontend
- PR #162 chore: retire the Static Web Apps Functions proxy; fix the local-run stack
- PR #161 feat(feeds): show when a feed has stopped updating, and why
- PR #160 test(admin): make the CaptureNow test independent of clock resolution
- PR #159 fix(admin): lay the trends chart out on a real time axis
- PR #158 chore(config): drop the unused ServerHostName setting
- PR #157 feat(admin): add a 1h trends range; ranges are named keys
- PR #156 feat(admin): "Refresh now" button that takes a stats snapshot immediately
- PR #155 feat(admin): switch the trends chart between 1d, 7d, 30d and 1y
- PR #154 fix(auth): let the providers' sign-in callback POST through the CSRF guard
- PR #153 fix(auth): personal Microsoft accounts only, CSRF guard, rate limits
- PR #152 feat(db): store posts once with per-user state, migrating in place
- PR #151 test(api): add HTTP contract tests for the API as it behaves today
- PR #150 fix(auth): request only openid + email from Microsoft and Google
da0a33b chore(ship): validate the backend on the API domain, not the SWA proxy (#148)
3fb8847 fix(auth): keep people signed in between visits (#149)
- Deployed to production (14x)
2026-W42 (Oct 12 to Oct 18, 2026)
4 active days | 2 repos | 32 PRs merged | 7 commits
Week in a sentence: The site gained a weekly Release Notes page that now rebuilds on every deploy, while rss-reader moved sign-in into its API, hardened deploys and cost, and fixed a run of timeline and read-state bugs.
brandonchastain/brandonchastain.com
- Added a weekly Release Notes page at
/release-notes/ (renamed from /shipped/), linked from the home page. A Sunday-evening bot summarizes the week's commits, merged PRs and releases across my repos and commits the result to master so the site deploys. The first week (2026-W42) is seeded from a real run, and the fallback summary is kept short with the raw list in a collapsible block.
- Every site deploy now regenerates the page from the committed week files, so it can't go stale. Week ids come from the window midpoint, so the Monday 02:00 UTC run files under the week it covers.
- The bot skips repos its token can't read instead of crashing, and it rebases before pushing so overlapping runs no longer fail with "fetch first".
brandonchastain/rss-reader
- Moved login off Static Web Apps Easy Auth and into the API, with Google, Microsoft and GitHub providers behind
/auth/*. The cutover on 2026-10-17 made Microsoft login go through the API, and the Functions proxy is retired. Existing accounts are linked by a hash of the Microsoft-reported email, the admin checks work after the migration, and the account picker always appears.
- Deploys no longer lose user writes. The new revision hands the database over from the old one before it starts, which closes a window of up to 15 minutes of lost writes on every deploy.
- Kept one replica warm to fix a 45.6s cold start that ended in a 500, and cut idle-time work (backups, scheduler, probes) to bring the bill back down.
- Timeline and read state fixes: the cached timeline reconciles with the server on every open, the list no longer jumps under the reader while paging, the "new posts" toast works on first load and stays off Search and per-feed pages, read posts stay visible until the next fetch, and a post stays read after Back from an outbound link. Manual refresh now fetches every stale feed.
- Added self-hosting, architecture and knobs docs for the API, with 20 production deployments this week.
Raw activity
brandonchastain/brandonchastain.com
- PR #4 Rebuild release notes page before every deploy
- PR #3 Release notes workflow: rebase before push
- PR #2 Release notes bot: skip unreadable repos
- PR #1 Add weekly Release Notes page (/release-notes/)
ce14e37 Add the weekly shipped log: bot in tools/shipped-log, page at /shipped/
6976373 Shipped log: keep the fallback summary short, raw list only in the collapsible block
eff915d Rename the page to Release Notes at /release-notes/
ebe5c62 Rename the workflow files to release-notes*.yml
d6ef435 Release notes bot: skip a repo the token cannot read instead of crashing
7e4e766 Release notes workflow: rebase onto master before pushing
50113b9 Rebuild the release notes page before every site deploy; label weeks by window midpoint
brandonchastain/rss-reader
- PR #147 fix(timeline): render after the first load so the new-posts poll actually runs
- PR #146 fix(read-state): keep a post Read after Back from an outbound link
- PR #145 fix(feed): never show the "new posts" toast on the per-feed page
- PR #144 fix(unread): keep read posts visible until the next server fetch
- PR #143 fix(search): never show the "new posts" toast on the search page
- PR #142 feat: manual refresh fetches every stale feed; deflake the handover tests
- PR #140 test: rename the test project to RssReaderTests
- PR #139 fix(durability): hand the DB over between revisions on deploy (#136)
- PR #137 fix(auth): always show the provider's account picker
- PR #127 docs: self-hosting, architecture and deploy pages for API login
- PR #135 cutover: the site logs in through the API
- PR #132 docs: explain ghcr.io 'denied' from a stale scopeless credential
- PR #133 feat(auth): link pre-migration rows by a hash of the Microsoft-reported email
- PR #131 diag(auth): log the claim types of an SWA principal that carries no object id
- PR #129 fix: dev auth flag and admin check across the login migration
- PR #130 skills: launch Docker Desktop through the shell in run-locally
- PR #126 infra: login provider secrets, session keys and the cutover switch
- PR #125 feat(frontend): log in through the API instead of Static Web Apps Easy Auth
- PR #128 perf: cut the warm replica's idle-time work (backup, scheduler, probes)
- PR #121 docs: label the hardcoded knob tables as such
- PR #124 fix: bind the API hostname with an explicit managed certificate
- PR #122 infra: give the API its own hostname, api.rss.brandonchastain.com
- PR #123 feat(api): cookie login with Google, Microsoft and GitHub behind /auth/*
- PR #120 docs: knobs catalogue, self-hosting guide, and one consistent durability story
- PR #119 fix: reconcile the cached timeline with the server on every open
- PR #118 perf: keep one replica warm and take image restore, FTS count and quick_check off the cold-start path
- PR #117 fix: replace Virtualize with a measured window so the timeline never shifts under the reader
- PR #116 fix: hold the reader's row still while the virtualized timeline re-windows
- Deployed to production (20x)