Files

8.6 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
01-draft-state-ownership 01 execute 1
tauri-app/src/features/runtime/types.ts
tauri-app/src/features/runtime/useRuntimeManager.ts
tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx
true
WORK-02
CONF-01
truths artifacts key_links
User can keep editing a runtime draft while background polling continues without draft fields being overwritten.
User can reopen the settings drawer in the same session and find the same unsaved draft.
User can save a draft and have the saved values become the new clean baseline immediately.
path provides
tauri-app/src/features/runtime/useRuntimeManager.ts separate ownership for live snapshot, saved baseline, and editable draft actions
path provides
tauri-app/src/features/runtime/types.ts runtime draft contracts shared by the manager and drawer
path provides
tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx regression coverage for polling-safe draft ownership
from to via pattern
tauri-app/src/features/runtime/useRuntimeManager.ts tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx manager props for live values, draft values, dirty state, and draft actions draft|baseline|liveSnapshot
from to via pattern
tauri-app/src/features/runtime/useRuntimeManager.ts tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx polling and save flow regression tests bootstrapRuntime|getRuntimeSnapshot|saveRuntimeConfig
Create the draft ownership foundation so the runtime feature has distinct live, baseline, and editable draft state before the drawer UI is refactored.

Purpose: eliminate the current poll-driven overwrite path at the feature-state layer instead of patching individual fields ad hoc. Output: explicit runtime draft contracts and a manager API that preserves unsaved state across refresh, close, reopen, and save.

<execution_context> @$HOME/.config/opencode/get-shit-done/workflows/execute-plan.md @$HOME/.config/opencode/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/REQUIREMENTS.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 @tauri-app/src/features/runtime/useRuntimeManager.ts @tauri-app/src/features/runtime/types.ts @tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx From `tauri-app/src/features/runtime/types.ts`:
export interface RuntimeConfig {
  connection_mode: ConnectionMode;
  start_policy: StartPolicy;
  server_url: string;
  api_key: string;
  model_path: string | null;
  models_dir: string | null;
  addr: string;
  gpu_layers: number;
  ctx_size: number;
  extra_model_paths: string[];
  selected_model_id: string | null;
  remote_presets: RemotePreset[];
  hugging_face_token: string;
}

export interface RuntimeSnapshot {
  status: RuntimeStatus;
  ready: boolean;
  process_running: boolean;
  resolved_url: string;
  binary_path: string | null;
  last_error: RuntimeErrorInfo | null;
  config: RuntimeConfig;
}

From tauri-app/src/features/runtime/useRuntimeManager.ts:

export function useRuntimeManager() {
  return {
    snapshot,
    connection,
    loading,
    busy,
    refresh,
    saveConfig,
    startLocal,
    stopLocal,
  };
}
Task 1: Define runtime draft ownership contracts tauri-app/src/features/runtime/types.ts - tauri-app/src/features/runtime/types.ts - .planning/phases/01-hf-model-discovery/01-CONTEXT.md - .planning/phases/01-hf-model-discovery/01-UI-SPEC.md - Test 1: the runtime feature can represent live values separately from editable draft values and the saved baseline. - Test 2: the draft contract exposes enough state for the drawer to show dirty, hidden, invalid, and clean states without reading raw snapshot internals. Extend `tauri-app/src/features/runtime/types.ts` with explicit draft-facing contracts for Phase 1 per D-01 through D-06 and D-09 through D-11. Add concrete exported types for manager-owned draft state, including: a live snapshot reference, a saved baseline `RuntimeConfig`, an editable draft `RuntimeConfig`, a boolean dirty flag, a boolean open/hidden state, and field-level invalid/pending metadata keyed at least for `models_dir`, `model_path`, `selected_model_id`, `server_url`, and `api_key`. Keep existing `RuntimeSnapshot` and `RuntimeConfig` intact so brownfield callers still compile; add new exports rather than replacing old ones. - `tauri-app/src/features/runtime/types.ts` exports draft-specific interfaces or types in addition to `RuntimeSnapshot` and `RuntimeConfig`. - The draft contract includes explicit baseline and draft config properties rather than relying on one mutable `snapshot.config`. - The draft contract includes field-level invalid/pending metadata needed for inline save blocking. npm test -- runtime-settings-form Runtime draft state is a first-class typed contract that downstream code can consume without inferring ownership rules from comments or snapshot mutations. Task 2: Move draft, baseline, and polling reconciliation into the runtime manager tauri-app/src/features/runtime/useRuntimeManager.ts, tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx - tauri-app/src/features/runtime/useRuntimeManager.ts - tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx - tauri-app/src/features/runtime/types.ts - .planning/phases/01-hf-model-discovery/01-CONTEXT.md - Test 1: polling updates operational live state without overwriting dirty draft values (D-02, D-09). - Test 2: closing and reopening the drawer in the same session restores the unsaved draft (D-06). - Test 3: successful save promotes the returned config into the new clean baseline while keeping the draft open (D-03). Refactor `useRuntimeManager.ts` so it owns three distinct sources of truth: `liveSnapshot` from polling/lifecycle commands, `savedBaseline` from the last committed `RuntimeConfig`, and `draftConfig` for user edits. Add explicit actions named for executor clarity: create/open draft from `savedBaseline`, close draft without discard, replace the full draft with `savedBaseline`, update a targeted draft field, and save the current draft. Polling via `getRuntimeSnapshot()` must still run every 3000 ms, but when `draftDirty` is true it may only update operational live fields (`status`, `ready`, `process_running`, `resolved_url`, `binary_path`, `last_error`, and managed-library metadata if present), not overwrite `draftConfig`. After `saveRuntimeConfig()` resolves, set both `liveSnapshot.config` and `savedBaseline` to the returned config, clear dirty state, and keep the draft available/open per D-03. Add or update `RuntimeSurface.test.tsx` coverage so these manager behaviors are enforced through the feature harness. - `tauri-app/src/features/runtime/useRuntimeManager.ts` exposes separate live and draft-facing state instead of only `snapshot`. - The polling path no longer writes the full fetched snapshot into the editable draft when the draft is dirty. - `tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx` contains regression tests for poll-safe drafts, close/reopen preservation, and save promotion. npm test -- RuntimeSurface The runtime manager becomes the source of truth for Phase 1 draft ownership, with automated coverage proving polling and save flows preserve draft safety. - `npm test -- RuntimeSurface` - `npm test -- runtime-settings-form`

<success_criteria>

  • Live runtime refresh continues while dirty draft fields remain unchanged.
  • Saving a draft promotes the saved config into the new baseline without closing the drawer.
  • Closing and reopening the drawer in the same session restores the unsaved draft. </success_criteria>
After completion, create `.planning/phases/01-hf-model-discovery/01-01-SUMMARY.md`