Files
ForgeLM/.planning/phases/01-hf-model-discovery/01-02-PLAN.md
T

155 lines
8.4 KiB
Markdown

---
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
---
<objective>
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.
</objective>
<execution_context>
@$HOME/.config/opencode/get-shit-done/workflows/execute-plan.md
@$HOME/.config/opencode/get-shit-done/templates/summary.md
</execution_context>
<context>
@.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
<interfaces>
From `tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx`:
```tsx
interface Props {
open: boolean;
snapshot: RuntimeSnapshot;
busy: boolean;
onClose: () => void;
onSave: (patch: Partial<RuntimeConfig>) => Promise<RuntimeSnapshot>;
onStart: () => Promise<unknown>;
onStop: () => Promise<unknown>;
}
```
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
```
</interfaces>
</context>
<tasks>
<task type="auto" tdd="true">
<name>Task 1: Convert the drawer to a controlled draft/live presentation</name>
<files>tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx, tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.css</files>
<read_first>
- 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
</read_first>
<behavior>
- 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).
</behavior>
<action>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.</action>
<acceptance_criteria>
- `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.
</acceptance_criteria>
<verify>
<automated>npm test -- RuntimeSurface</automated>
</verify>
<done>The drawer becomes a controlled, explicit draft editor that makes unsaved edits and saved/live references obvious and never discards draft state on close.</done>
</task>
<task type="auto" tdd="true">
<name>Task 2: Add drawer-level tests for draft visibility and explicit discard semantics</name>
<files>tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx</files>
<read_first>
- 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
</read_first>
<behavior>
- 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.
</behavior>
<action>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.</action>
<acceptance_criteria>
- `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.
</acceptance_criteria>
<verify>
<automated>npm test -- RuntimeSurface</automated>
</verify>
<done>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.</done>
</task>
</tasks>
<verification>
- `npm test -- RuntimeSurface`
- `npm run build`
</verification>
<success_criteria>
- 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.
</success_criteria>
<output>
After completion, create `.planning/phases/01-hf-model-discovery/01-02-SUMMARY.md`
</output>