--- phase: 01-draft-state-ownership plan: 02 type: execute wave: 2 depends_on: [01-01] files_modified: - tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx - tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.css - tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx autonomous: true requirements: [WORK-02, CONF-02] must_haves: truths: - User can tell which values are draft edits versus live or saved values while editing. - User can explicitly discard changes back to the last saved baseline. - Closing the drawer hides the draft without discarding it, and reopening restores it. artifacts: - path: tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx provides: controlled draft editor with explicit live-vs-draft presentation and discard flow - path: tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.css provides: draft-state visual treatment matching the approved UI contract - path: tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx provides: coverage for visible draft and discard semantics key_links: - from: tauri-app/src/features/runtime/useRuntimeManager.ts to: tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx via: controlled props for draft values and draft actions pattern: draft|discard|openDraft|closeDraft - from: tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx to: tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.css via: classes for draft badges, helper rows, sticky header, and discard confirmation pattern: draft|live-now|discard --- Refactor the settings drawer into a controlled draft editor that visibly distinguishes draft values from live values and exposes explicit discard behavior. Purpose: satisfy the user-facing trust requirements once manager-owned draft state exists. Output: a drawer that renders `Draft settings`, `Live now`, `Save changes`, `Discard changes`, and in-session draft preservation per the approved UI contract. @$HOME/.config/opencode/get-shit-done/workflows/execute-plan.md @$HOME/.config/opencode/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/01-hf-model-discovery/01-CONTEXT.md @.planning/phases/01-hf-model-discovery/01-RESEARCH.md @.planning/phases/01-hf-model-discovery/01-UI-SPEC.md @.planning/phases/01-hf-model-discovery/01-01-SUMMARY.md @tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx @tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.css @tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx From `tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx`: ```tsx interface Props { open: boolean; snapshot: RuntimeSnapshot; busy: boolean; onClose: () => void; onSave: (patch: Partial) => Promise; onStart: () => Promise; onStop: () => Promise; } ``` From `01-UI-SPEC.md`: ```text - Sticky header title: Draft settings - Visible live reference label: Live now - Footer actions: Save changes, Discard changes - Confirmation row: Keep editing, Revert to saved ``` Task 1: Convert the drawer to a controlled draft/live presentation tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx, tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.css - tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx - tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.css - .planning/phases/01-hf-model-discovery/01-UI-SPEC.md - .planning/phases/01-hf-model-discovery/01-CONTEXT.md - .planning/phases/01-hf-model-discovery/01-01-SUMMARY.md - Test 1: changed fields show visible draft treatment plus a live/saved reference row, not color-only state (WORK-02). - Test 2: the drawer header and footer use `Draft settings`, `Live now`, `Save changes`, and `Discard changes` copy from the UI contract. - Test 3: close hides the draft without resetting it; discard is the explicit full-form reset path (D-04, D-05, D-06). Refactor `RuntimeSettingsDrawer.tsx` to consume manager-owned draft props from Plan 01 instead of repopulating local form state from `snapshot` in a blanket effect. Replace the current header copy (`Runtime workspace`, `One control plane for startup, models, and API routing`) with the Phase 1 contract: sticky `Draft settings` title, a compact dirty-state summary, and `Live now` reference content. For every dirty editable field, render the draft control with a draft accent treatment plus a helper row showing the current saved/live value beneath it. Replace footer labels with `Save changes` and `Discard changes`. Implement the inline discard confirmation row exactly with `Keep editing` and destructive `Revert to saved`; `Discard changes` opens the confirmation row and only `Revert to saved` actually resets the full draft to baseline. Backdrop click and close button must call the manager's hide-draft action, not discard. - `tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx` no longer has a `useEffect` that fully rehydrates all form fields from `snapshot.config` on every snapshot change. - The file contains the strings `Draft settings`, `Live now`, `Save changes`, `Discard changes`, `Keep editing`, and `Revert to saved`. - `tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.css` contains styles for visible draft-state and live-reference treatment rather than only neutral field styling. npm test -- RuntimeSurface The drawer becomes a controlled, explicit draft editor that makes unsaved edits and saved/live references obvious and never discards draft state on close. Task 2: Add drawer-level tests for draft visibility and explicit discard semantics tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx - tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx - tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx - .planning/phases/01-hf-model-discovery/01-UI-SPEC.md - Test 1: editing a field marks it as draft and shows the saved/live reference below the control. - Test 2: clicking close or backdrop preserves the unsaved draft for reopen in the same session. - Test 3: `Discard changes` does not reset immediately; `Revert to saved` performs the reset while `Keep editing` cancels it. Add or update `RuntimeSurface.test.tsx` so it exercises the controlled drawer through the runtime manager harness. Assert concrete UI strings and behaviors: a dirty field shows the `Draft` signal and the `Live now` or saved reference row; close/backdrop preserves the edited value on reopen; `Discard changes` reveals the confirmation row; `Keep editing` leaves the draft untouched; `Revert to saved` restores the last saved baseline for the full form. Keep the tests in the existing jsdom harness instead of introducing a new test framework. - `tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx` contains assertions for `Draft settings`, `Discard changes`, `Keep editing`, and `Revert to saved`. - The tests verify close/reopen preservation and full-form discard reset behavior. npm test -- RuntimeSurface Automated tests prove the drawer exposes clear draft state and that discard behavior is explicit, reversible at the confirmation step, and never triggered by simple close. - `npm test -- RuntimeSurface` - `npm run build` - The drawer clearly distinguishes draft versus live/saved values while editing. - Users must explicitly confirm a full-form discard; close merely hides the draft. - The approved Phase 1 copy and layout contract is reflected in the drawer implementation. After completion, create `.planning/phases/01-hf-model-discovery/01-02-SUMMARY.md`