Lane 9 PR 6: Admin follow-ups (#879) and the demo seed (#735) #889

Merged
claude-bot merged 6 commits from build/lane9-6-seed into main 2026-09-27 21:22:38 +00:00
Collaborator

Part of #735 (lane 9). Closes #879. Stacked on #886 (4d).

#879

  1. The bot's disabled reason. GET /admin/settings/bot/identity passes the bot's own reason through. It's optional, so an older bot sends none.
    • Discord now says "Discord refused the token…" separately from "No Discord token set…".
    • The bot already reported the reason, so the bot doesn't change. This is an admin route, not /api/bot/*.
  2. Campaigns' own keys in secrets health. The encrypted-settings audit now tries to decrypt campaign_ai_settings' LLM and ASR keys.
    • It records only whether each key reads, never the value.
    • Instance health shows "Campaigns' own keys (N)" and folds them into the "cannot be read" banner. So does the dashboard flag.
    • The startup log line gains the two counts.
  3. Done in 4d.
  4. Test backfill.
    • AdminRecording.test.jsx gets retention parity, including every field saved in one submit.
    • AdminAi.test.jsx gets gap-severity ordering, the guessed-provider note, the transcriber round-trip through Save, and the wiki pipeline's mode change and error state.

The demo seed (§6, D145)

Admin's pages now have realistic content to show:

  • An archived campaign, The Salt Crown. It has:
    • transcripts over 12 months old;
    • its own "keep for good" retention;
    • a failed latest recording;
    • a pack disabled after a content notice.
  • A one-shot in the bin, Brinewatch.
  • Their GM, an invented Rook Tallis, last seen about 7 months ago.
  • Other additions:
    • a co-GM on the Tuesday Tide;
    • a never-signed-in account that joined this week;
    • 9 audit events;
    • 4 content notices, none targeting an instance pack;
    • 2 more AI usage rows, one failed and one at a hosted rate.

A real bug the seed's test caught: content_notices has no foreign key to a campaign, by design, so delete_demo's cascade missed them and a second --reset failed. The seed now deletes its own notice ids explicitly.

Both new campaigns are deliberately shallow: 6 and 1 sessions, with no wiki or shelf. They exist for Admin's pages, and the README says so.

Checks

  • Backend: 125 passed across test_demo_seed, test_secrets_at_rest, test_admin and the body-reader allowlist.
  • ruff: clean.
  • vitest: 197 files, 2626 passed. eslint: 0 errors.
  • No render check. The changes are text branches and one list row, and exact-text tests cover them. The next render pass on a running stack should include AdminDiscord and AdminHealth.

🤖 Generated with Claude Code

Part of #735 (lane 9). Closes #879. **Stacked on #886 (4d).** ## #879 1. **The bot's disabled reason.** `GET /admin/settings/bot/identity` passes the bot's own `reason` through. It's optional, so an older bot sends none. - Discord now says "Discord refused the token…" separately from "No Discord token set…". - The bot already reported the reason, so the bot doesn't change. This is an admin route, not `/api/bot/*`. 2. **Campaigns' own keys in secrets health.** The encrypted-settings audit now tries to decrypt `campaign_ai_settings`' LLM and ASR keys. - It records only whether each key reads, **never the value**. - Instance health shows "Campaigns' own keys (N)" and folds them into the "cannot be read" banner. So does the dashboard flag. - The startup log line gains the two counts. 3. **Done in 4d.** 4. **Test backfill.** - `AdminRecording.test.jsx` gets retention parity, including every field saved in one submit. - `AdminAi.test.jsx` gets gap-severity ordering, the guessed-provider note, the transcriber round-trip through Save, and the wiki pipeline's mode change and error state. ## The demo seed (§6, D145) Admin's pages now have realistic content to show: - **An archived campaign,** The Salt Crown. It has: - transcripts over 12 months old; - its own "keep for good" retention; - a failed latest recording; - a pack disabled after a content notice. - **A one-shot in the bin,** Brinewatch. - **Their GM,** an invented Rook Tallis, last seen about 7 months ago. - **Other additions:** - a co-GM on the Tuesday Tide; - a never-signed-in account that joined this week; - 9 audit events; - 4 content notices, none targeting an instance pack; - 2 more AI usage rows, one failed and one at a hosted rate. **A real bug the seed's test caught:** `content_notices` has no foreign key to a campaign, by design, so `delete_demo`'s cascade missed them and a second `--reset` failed. The seed now deletes its own notice ids explicitly. Both new campaigns are deliberately shallow: 6 and 1 sessions, with no wiki or shelf. They exist for Admin's pages, and the README says so. ## Checks - **Backend:** 125 passed across `test_demo_seed`, `test_secrets_at_rest`, `test_admin` and the body-reader allowlist. - **ruff:** clean. - **vitest:** 197 files, 2626 passed. **eslint:** 0 errors. - **No render check.** The changes are text branches and one list row, and exact-text tests cover them. The next render pass on a running stack should include AdminDiscord and AdminHealth. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
GET /admin/settings/bot/identity now passes through the bot's own reason
("no token"/"token refused") for a disabled Discord connection, additive on
an already-additive field the bot has reported since IS-394. AdminDiscord
says "Discord refused the token" separately from "No Discord token set",
as drawn (ADMIN-14), rather than one generic message.

audit_encrypted_settings now also counts campaign_ai_settings' own
llm_api_key/asr_api_key columns and how many this host's SECRET_KEY can no
longer read, so Instance health's "Campaigns' own keys (N)" line is real
instead of always absent. Feeds the existing any_secret_unreadable
dashboard flag too.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Extends the demo seed with two thin campaigns purely so Admin's own pages
have more than one live example to show (D145): The Salt Crown (archived,
owned by a stale invented owner who has not signed in in seven months) and
Brinewatch (a one-shot, binned). Between them: a co-GM on the Tuesday Tide,
a failed recording, three transcripts old enough for a stricter retention
cap to name (kept "for good" as the campaign's own override), a second
content pack disabled after a rightsholder notice, four content notices
(none about an instance pack), and nine more audit-log events. Nobody
plays either table — no wiki, shelf, quests or discussions — see
demo/README.md for why the scope stops there.

content_notices has no foreign key to a campaign, so delete_demo now
deletes the seed's own notices by id explicitly; everything else still
cascades from the campaign rows.

Also backfills #879 item 4's test coverage that the legacy Admin page's
deletion (#735) didn't carry over: AdminAi's gap-severity ordering, the
guessed-provider note, the ASR round-trip through save, and the wiki
pipeline's mode change and error states; AdminRecording's retention
parity (defaults and caps, both sides, loaded and saved together).

Backend: targeted modules (125 passed) + ruff clean. Frontend: full
vitest suite (2626 passed, 1 pre-existing skip) + eslint 0 errors.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
claude-bot changed target branch from build/lane9-4d-pages to main 2026-09-27 20:26:22 +00:00
Merge main into build/lane9-6-seed
All checks were successful
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 55s
CI / Backend lint (ruff) (pull_request) Successful in 28s
CI / Feedback site tests (pull_request) Successful in 40s
CI / Bot tests and audit (pull_request) Successful in 1m42s
CI / Bot/backend version sync (pull_request) Successful in 28s
CI / Does this change touch the recording path? (pull_request) Successful in 19s
CI / Docker image build (pull_request) Successful in 4m58s
CI / Backend migration, tests, and audit (pull_request) Successful in 17m49s
CI / Frontend tests, audit, and build (pull_request) Successful in 22m0s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Successful in 34m37s
CI / End-to-end journeys (desktop, phone, keyboard-only) (pull_request) Successful in 41m34s
578a853783
Sign in to join this conversation.
No description provided.