chore(release): v4.1.0 — Data Durability & Recovery #482

Merged
claude-bot merged 1 commit from chore/release-v4.1.0 into main 2026-09-01 18:10:28 +00:00
Contributor

Closes out the v4.1.0 milestone — 22 issues, 0 open.

APP_VERSION and BOT_EXPECTED_APP_VERSION both 4.0.14.1.0. make check-versions passes.

BOT_CONTRACT_VERSION stays at 1 — verified, not assumed

Three commits touched /api/bot/* since v4.0.1, so I read the diff rather than trusting the shape of the changes:

  • #399 added guild_id and notification_channel_id to a bot response. Optional on both sides by design — the bot declares them str | None = None with a comment saying explicitly that an older backend omitting them must still parse, in which case recovery declines rather than guessing.
  • #405 and #408 added deleted_at IS NULL filters to the guild lookup and the /ask lore context. Response shapes unchanged; both narrow which rows come back, to outcomes an older bot already handles — the guild lookup's 404 is a documented case it denies on.

So a self-hoster can upgrade the backend and bot images independently. The changelog preamble says so, since that is exactly what people read it for.

Migrations

Two, both additive — nullable columns and partial indexes, no data rewritten:

revision what
e3f4a5b6c7d9 wiki entry soft delete (#408)
f4a5b6c7d8ea campaign soft delete (#405)

Both verified up → down → up against a real Postgres. f4a5b6c7d8ea is head.

Release-notes extraction checked

release.yml extracts the version's section from CHANGELOG.md, and an empty release body is the documented failure mode. I ran the workflow's own regex against this file: 24,765 characters extracted for 4.1.0, correct boundaries, no bleed into the 4.0.1 section.

That also required fixing a pre-existing missing blank line before the ## [4.0.1] header. It would probably have extracted anyway, but I would rather not have this release's notes depend on "probably".

What is in it

The milestone's own framing — nothing a GM has made can be destroyed by a single click, a crashed worker, or a background job they never saw run. Headline items: campaign and wiki soft delete with a 30-day trash and a 7-day floor, off-host backups, audio reaching deletion only through a trash, per-speaker recording that streams to disk, crash recovery for interrupted recordings, and the retention sweep no longer eroding anything restorable.

Two operator-visible changes are called out in the changelog preamble: deleted things now occupy disk for 30 days, and there is a new optional RESTART_POLICY in .env.

After this merges

Tag v4.1.0 on main and push, which fires release.yml. Deploy to dev and validate before prod — not deploying anything as part of this PR.

🤖 Generated with Claude Code

Closes out the **v4.1.0 milestone — 22 issues, 0 open.** `APP_VERSION` and `BOT_EXPECTED_APP_VERSION` both `4.0.1` → `4.1.0`. `make check-versions` passes. ## `BOT_CONTRACT_VERSION` stays at 1 — verified, not assumed Three commits touched `/api/bot/*` since v4.0.1, so I read the diff rather than trusting the shape of the changes: - **#399** added `guild_id` and `notification_channel_id` to a bot response. Optional on *both* sides by design — the bot declares them `str | None = None` with a comment saying explicitly that an older backend omitting them must still parse, in which case recovery declines rather than guessing. - **#405** and **#408** added `deleted_at IS NULL` filters to the guild lookup and the `/ask` lore context. Response shapes unchanged; both narrow which rows come back, to outcomes an older bot already handles — the guild lookup's 404 is a documented case it denies on. So a self-hoster can upgrade the backend and bot images independently. The changelog preamble says so, since that is exactly what people read it for. ## Migrations Two, both additive — nullable columns and partial indexes, no data rewritten: | revision | what | |---|---| | `e3f4a5b6c7d9` | wiki entry soft delete (#408) | | `f4a5b6c7d8ea` | campaign soft delete (#405) | Both verified up → down → up against a real Postgres. `f4a5b6c7d8ea` is head. ## Release-notes extraction checked `release.yml` extracts the version's section from `CHANGELOG.md`, and an empty release body is the documented failure mode. I ran the workflow's own regex against this file: **24,765 characters** extracted for `4.1.0`, correct boundaries, no bleed into the `4.0.1` section. That also required fixing a pre-existing missing blank line before the `## [4.0.1]` header. It would probably have extracted anyway, but I would rather not have this release's notes depend on "probably". ## What is in it The milestone's own framing — nothing a GM has made can be destroyed by a single click, a crashed worker, or a background job they never saw run. Headline items: campaign and wiki soft delete with a 30-day trash and a 7-day floor, off-host backups, audio reaching deletion only through a trash, per-speaker recording that streams to disk, crash recovery for interrupted recordings, and the retention sweep no longer eroding anything restorable. Two operator-visible changes are called out in the changelog preamble: deleted things now occupy disk for 30 days, and there is a new optional `RESTART_POLICY` in `.env`. ## After this merges Tag `v4.1.0` on `main` and push, which fires `release.yml`. Deploy to dev and validate before prod — not deploying anything as part of this PR. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
chore(release): v4.1.0 — Data Durability & Recovery
All checks were successful
CI / Backend lint (ruff) (pull_request) Successful in 36s
CI / Bot/backend version sync (pull_request) Successful in 28s
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 1m10s
CI / Docker image build (pull_request) Successful in 46s
CI / Frontend tests, audit, and build (pull_request) Successful in 1m42s
CI / Bot tests and audit (pull_request) Successful in 1m48s
CI / Backend migration, tests, and audit (pull_request) Successful in 8m43s
8f0fef07d7
Closes out the v4.1.0 milestone: 22 issues, everything the milestone set out to
do. Nothing a GM has made can now be destroyed by a single click, a crashed
worker, or a background job they never saw run.

APP_VERSION and BOT_EXPECTED_APP_VERSION both 4.0.1 -> 4.1.0.

BOT_CONTRACT_VERSION stays at 1, verified against the diff rather than assumed.
Three commits touched the /api/bot/* surface since v4.0.1:

- #399 added `guild_id` and `notification_channel_id` to a bot response. Both
  are optional on both sides *by design* — the bot declares them
  `str | None = None` explicitly so an older backend that omits them still
  parses, and recovery declines rather than guessing.
- #405 and #408 added `deleted_at IS NULL` filters to the guild lookup and the
  /ask lore context. Response shapes unchanged; both narrow which rows are
  returned, to outcomes an older bot already handles correctly (the guild
  lookup's 404 is a documented case it denies on).

So a self-hoster can upgrade the two images independently, and the changelog
says so.

Two migrations ship: e3f4a5b6c7d9 (wiki entry soft delete) and f4a5b6c7d8ea
(campaign soft delete). Both additive — nullable columns and partial indexes,
no data rewritten — and both verified up -> down -> up against a real Postgres.

Also fixes a pre-existing missing blank line before the ## [4.0.1] header, so
the release-notes extraction has a clean section boundary. Simulated the
workflow's own regex against this file: 24,765 chars extracted for 4.1.0, no
bleed into the 4.0.1 section.

`make check-versions` passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
claude-bot changed title from chore(release): v4.1.0 — Data Durability &amp; Recovery to chore(release): v4.1.0 — Data Durability & Recovery 2026-09-01 17:14:28 +00:00
Sign in to join this conversation.
No description provided.