Lane 9 page 4c: AI models, AI usage & speed, Discord, Email, Instance health (#735) #881

Merged
claude-bot merged 6 commits from build/lane9-4c-pages into main 2026-09-27 11:47:50 +00:00
Collaborator

Part of #735 (lane 9). Stacked on #873 (4b). It merges with that stack as part of the train, and its diff against 4b is only this page.

What it builds

Legacy BotSettings had 49 fields on one tab. This PR splits it into sections, each at its own address, and adds two new pages.

  • AI models (/admin/ai)

    • the capability panel;
    • the transcriber and summariser forms, with Test running on the typed values (D147); "No key was sent" is a note, not a refusal;
    • the summary and wiki mode choices (API-012/013, ADMIN-8);
    • "who uses their own".
  • AI usage & speed (/admin/usage)

    • AdminHardwareProfile and AdminAiUsage ported into the kit;
    • the preflight's own basis for the transcription speed (D148's plainer words).
  • Discord (/admin/discord)

    • the bot's address;
    • its key, behind the confirm dialog;
    • the identity check from GET /admin/settings/bot/identity.

    There is no token field (D139).

  • Email (/admin/email)

    • the SMTP form;
    • an inline test that shows {sent, error} rather than queuing.
  • Instance health (/admin/health), its first screen

    • #859's AI queue verdict (free / busy / stuck) and which secrets this server can read;
    • a 10 s poll.
  • #872 item 2: Users, Campaigns and Audit get a min-width/nowrap date column at 390 px. All three tables were render-checked.

BotSettings, AiCapabilityPanel and NotificationSettings stay in legacy pages/Admin.jsx for now. It is unrouted but still has tests, and 4d deletes the whole file in one sweep.

Departures and follow-ups

#879 holds three follow-ups this page surfaced:

  1. The bot's disabled reason. The identity endpoint drops the bot's reason, so "Discord refused the token" can't yet be told apart from "no token".
  2. Campaigns' own keys in secrets health. They aren't in audit_encrypted_settings yet.
  3. The kit's .kv at phone width. It needs a stacking rule; there are local workarounds in AdminAi/AdminUsage until then.

#872 item 1 (the "kept until" date) is still separate.

Checks

  • The frontend suite, plus new tests for each page (AdminAi, AdminUsage, AdminDiscord, AdminEmail, AdminHealth).
  • eslint.
  • A render check with realistic fixture data at desktop and 390 px.
  • A changelog.d/ fragment.

🤖 Generated with Claude Code

Part of #735 (lane 9). **Stacked on #873 (4b).** It merges with that stack as part of the train, and its diff against 4b is only this page. ## What it builds Legacy `BotSettings` had 49 fields on one tab. This PR splits it into sections, each at its own address, and adds two new pages. - **AI models** (`/admin/ai`) - the capability panel; - the transcriber and summariser forms, with **Test** running on the typed values (D147); "No key was sent" is a note, not a refusal; - the summary and wiki mode choices (API-012/013, ADMIN-8); - "who uses their own". - **AI usage & speed** (`/admin/usage`) - `AdminHardwareProfile` and `AdminAiUsage` ported into the kit; - the preflight's own basis for the transcription speed (D148's plainer words). - **Discord** (`/admin/discord`) - the bot's address; - its key, behind the confirm dialog; - the identity check from `GET /admin/settings/bot/identity`. There is **no token field** (D139). - **Email** (`/admin/email`) - the SMTP form; - an inline test that shows `{sent, error}` rather than queuing. - **Instance health** (`/admin/health`), its first screen - #859's AI queue verdict (`free` / `busy` / `stuck`) and which secrets this server can read; - a 10 s poll. - **#872 item 2:** Users, Campaigns and Audit get a `min-width`/`nowrap` date column at 390 px. All three tables were render-checked. `BotSettings`, `AiCapabilityPanel` and `NotificationSettings` stay in legacy `pages/Admin.jsx` for now. It is unrouted but still has tests, and 4d deletes the whole file in one sweep. ## Departures and follow-ups **#879** holds three follow-ups this page surfaced: 1. **The bot's disabled reason.** The identity endpoint drops the bot's reason, so "Discord refused the token" can't yet be told apart from "no token". 2. **Campaigns' own keys in secrets health.** They aren't in `audit_encrypted_settings` yet. 3. **The kit's `.kv` at phone width.** It needs a stacking rule; there are local workarounds in `AdminAi`/`AdminUsage` until then. #872 item 1 (the "kept until" date) is still separate. ## Checks - The frontend suite, plus new tests for each page (`AdminAi`, `AdminUsage`, `AdminDiscord`, `AdminEmail`, `AdminHealth`). - eslint. - A render check with realistic fixture data at desktop and 390 px. - A `changelog.d/` fragment. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
.atbl's date columns (Joined, Last here, Started, When) had no white-space
rule of their own, so the auto table layout shrank them to fit a phone
viewport before the table overflowed, wrapping the date mid-word. #872 item 2.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Splits the legacy 49-field BotSettings tab into three addressed sections
(AI models, AI usage & speed, Discord), ports AdminHardwareProfile and
AdminAiUsage into the kit at /admin/usage, rebuilds Email with an inline
test on typed values (A10/D147), and gives Instance health its first
screen with a 10s poll (API-010/API-011, #859's verdict).

- AdminAi.jsx: the capability panel, the transcriber and summariser forms
  with Test on typed values, the summary/wiki mode choices (API-012/013,
  ADMIN-8), and "who uses their own" from the admin campaigns list.
- AdminUsage.jsx: the preflight and usage report, ported from
  components/AdminHardwareProfile.jsx and AdminAiUsage.jsx.
- AdminDiscord.jsx: the bot's address, its key (with the confirm dialog),
  and IS-394's identity check — no token field (D139).
- AdminEmail.jsx: the SMTP form with an inline test answering {sent, error}
  rather than queuing.
- AdminHealth.jsx: the AI queue's free/busy/stuck verdict and which secrets
  this server can read.
- adminSections.js/App.jsx: /admin/usage and /admin/health routed and
  marked built.
- api/users.js, api/sessions.js: testLlm, testWhisper and sendTestEmail take
  an optional typed body; fetchAiQueue and the summarisation-mode endpoints
  added.

BotSettings, AiCapabilityPanel and NotificationSettings stay in the legacy
pages/Admin.jsx: its own default-exported page (unrouted, but still tested
by Admin.test.jsx) still renders them, and that whole file is 4d's to
delete in one sweep.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Render-checked all five page 4c sections at 2560/1440/1024/390 in light
and dark (a throwaway, uncommitted harness with fixture data, the same
approach 4b used). It found three real bugs, all fixed here:

- .verdict (the Test row's and Discord's answer line) was `display: flex`,
  which lays each text fragment out as its own flex item instead of
  wrapping them as a sentence — "Signed in as QuestBoard#0420 · in 2
  servers" fractured into disconnected lines at 390px. It is
  `inline-block` now, which wraps like prose.
- AdminAi's and AdminUsage's `<dl className="kv">` blocks squeezed the
  value column to a sliver at 390px once a label ran long enough
  ("A 3½-hour session, five voices"), wrapping technical strings like
  "local_whisper · large-v3" one character per line. Both are stacked
  paragraphs now.
- Instance health's stuck line read "Nothing has finished in 4 minutes
  ago" (both "in" and "ago"); it says "in 4 minutes" now, matching the
  drawing.

Also caught that the render harness itself needed `.app`'s
`container-type` to make `@container app (max-width: 640px)` fire at all
— without it every phone-only rule in the kit (including the leafbar)
silently never triggered, which would have hidden the .kv and .verdict
bugs above rather than showing them.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The Transcribing line dropped result.asr.basis entirely when the
capability-panel rewrite moved away from <dl className="kv">, so nothing on
the page carried D148's accepted wording ("measured from the last
recordings") — the drawing's "a 30-second clip" would have gone unreplaced
by anything rather than by the plainer words the owner accepted.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
claude-bot changed target branch from build/lane9-4b-pages to main 2026-09-27 09:36:59 +00:00
Merge main into build/lane9-4c-pages
All checks were successful
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 55s
CI / Bot tests and audit (pull_request) Successful in 2m2s
CI / Backend lint (ruff) (pull_request) Successful in 32s
CI / Feedback site tests (pull_request) Successful in 48s
CI / Bot/backend version sync (pull_request) Successful in 27s
CI / Docker image build (pull_request) Successful in 5m10s
CI / Does this change touch the recording path? (pull_request) Successful in 23s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Has been skipped
CI / Frontend tests, audit, and build (pull_request) Successful in 21m59s
CI / Backend migration, tests, and audit (pull_request) Successful in 45m50s
CI / End-to-end journeys (desktop, phone, keyboard-only) (pull_request) Successful in 41m15s
9084eed14d
Sign in to join this conversation.
No description provided.