mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 14:40:52 +00:00
Wave-D reconcile report at .planning/phase-D-reconcile-report.md; deferred items seeded to .planning/v1419-backlog.md; strategic v1.5 items appended to .planning/v15-backlog.md from the v1.4.18 Product-Lead review. STATE.md marks Wave D done. Prettier sweep also touched the planning markdown table widths; no content change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.8 KiB
7.8 KiB
Phase B2 — AI provider settings UX cleanup (Pulldown-driven, v1.4.16)
Completed 2026-05-10 ~01:15 CEST on agent/b2-ai-provider-ux worktree.
Previous v1.4.15 phase-B2 report (Withings + moodLog sync robustness) superseded — that work shipped under tag v1.4.15 already and lives in
docs/audit/v1415-summary.md.
What landed
Four atomic TDD-first commits on agent/b2-ai-provider-ux, ready to
fast-forward into origin/main:
| # | Commit | What it ships |
|---|---|---|
| 1 | feat(api): PUT /api/insights/provider-chain persists user fallback chain |
New PUT writes the chain to User.aiProviderChain. Server-side priority is recomputed from insertion order so the UI's visual contract ("first row = priority 1") cannot drift from what gets persisted. Unknown provider types and duplicates 422; an empty chain is rejected outright. parseProviderChain() still falls back to the default chain when the persisted JSON is malformed, so a stale-tab resubmit cannot poison generation. 5 unit tests pin the contract. |
| 2 | feat(settings): AI provider section with single dropdown driving form below |
The big one. Single Pulldown (ai-active-provider-select) drives a switch-rendered config card below: Codex (connect/disconnect/status + last-insight + CODEX_MODEL note), OpenAI (API key + model select + collapsed Base URL override), Anthropic (API key + model), Local (Base URL + key + model), Admin OpenAI (read-only). Fallback chain card with up/down arrow reorder + per-row enable Switch + remove + add + reset-to-defaults. URL-synced via ?provider=… so deep links work and the SSR test drives each branch deterministically. |
| 3 | test(insights): integration coverage for PUT /api/insights/provider-chain |
Two scenarios pinned end-to-end against the postgres testcontainer: saving a valid reordered chain persists the JSON column with priority normalised; saving an empty chain rejects with 422 + leaves the column untouched. |
| 4 | test(e2e): AI provider dropdown switches the rendered config form |
Playwright spec confirms the dropdown switches every config form (Codex / OpenAI / Anthropic / Local) and the fallback chain card surfaces every row with the right data-chain-row markers. Mocks every backend endpoint the section reads so no real keys are needed in CI. |
Acceptance criteria mapping
- #1 New section component layout —
<AiSection>is the single card;<ActiveProviderSelect>is the Pulldown;<ProviderConfigCard>switch-renders one of five forms;<FallbackChainCard>is the chain manager with arrow controls (no new dependency —dnd-kitis not inpackage.json). - #2 Codex form —
<CodexProviderForm>shows connect / disconnect / status badge / last-insight / CODEX_MODEL slug note, reusing the unchanged device-code flow + OAuth callback handler. - #3 OpenAI form —
<OpenAIProviderForm>has masked API-key input, model dropdown (gpt-4o,gpt-4o-mini,gpt-4-turbo,Custom slug…), and a collapsed Base-URL override (advanced). - #4 Fallback chain UI — arrow up/down reorders, per-row Switch enables/disables, X removes, "+ Add Provider" picks from configured-but-not-in-chain providers, "Reset to defaults" with confirm dialog, "Save chain order" calls the new PUT.
- #5 i18n keys — EN + DE keys land under
settings.ai.activeProvider*,settings.ai.providerSelect.*,settings.ai.providerConfigTitle,settings.ai.providerChain.{title, description, moveUp, moveDown, removeFromChain, addProvider, saveOrder, saved, saveFailed, resetDefaults, resetConfirm*},settings.ai.openai.{modelSelect, modelOptionCustom, modelCustomLabel, baseUrl*, showAdvanced, hideAdvanced, apiKey, apiKeyPlaceholder},settings.ai.codex.{statusConnected, statusDisconnected, statusExpired, connectButton, disconnectButton, modelSlugLabel, modelSlugBody, lastInsight},settings.ai.adminOpenai.{title, body, notConfigured},settings.ai.{testProvider, testSuccess, testFailedShort}. The i18n parity guard test (src/lib/__tests__/i18n*.test.ts) is green. - #6 Tests — 5 new PUT route tests + 8 new component SSR tests
- 2 integration tests + 1 Playwright spec (covers form-switch
contract + chain row markers). The existing
<AiSection>smoke test insections.test.tsxstill passes (mock now exposesuseSearchParams).
- 2 integration tests + 1 Playwright spec (covers form-switch
contract + chain row markers). The existing
Verification
pnpm test— 1316 / 1316 unit tests pass (was 1299 → +17 net).pnpm test:integration— 55 / 55 integration tests pass (was 53 → +2 for the new PUT integration tests).pnpm typecheck— 0 errors.pnpm lint— 12 pre-existing warnings / 0 errors. Thereact-hooks/set-state-in-effectlint required a defensive pattern: the dropdown re-seeds on chain-data arrival via a render-timeseededFormarker rather than auseEffectsetter.
Notes for B5c / future phases
- The new ai-section.tsx no longer imports
<ProviderChainSummary>(the read-only summary panel B5b shipped). Its functionality is fully absorbed by<FallbackChainCard>. No external references remain — verified viagrep -r "ProviderChainSummary". - The chain PUT endpoint deduplicates and 422s on unknown provider
types, so when B5c adds a new provider tag it must extend
PROVIDER_CHAIN_TYPESin bothprovider-chain.ts(server) and the client-sidePROVIDER_TYPESarray inai-section.tsx. - The
aiProviderlegacy column is updated in lock-step with the chain so the v1.4.x single-resultresolveProvider()(still used byweight-status.ts,mood-status.ts, etc.) sees the same selection. When B5c migrates those last consumers off the legacy resolver, the OPENAI / ANTHROPIC / LOCAL save-mutation can drop theaiProviderwrite and rely on the chain alone. - E2E spec uses
data-chain-row+data-testidmarkers so the assertions are locale-independent. Reuse the same convention when B5c adds the per-recommendation explainability card.
Worktree
Branch agent/b2-ai-provider-ux (4 commits ahead of origin/main
at gate 8352c6d). Push + fast-forward to main is the next step.