Files
ForgeLM/.planning/phases/02-lifecycle-command-safety/02-02-PLAN.md
T

174 lines
8.9 KiB
Markdown

---
phase: 02-lifecycle-command-safety
plan: 02
type: execute
wave: 2
depends_on: [02-01]
files_modified:
- tauri-app/src/features/runtime/types.ts
- tauri-app/src/features/runtime/api.ts
- tauri-app/src/features/runtime/runtime-utils.ts
- tauri-app/src/features/runtime/useRuntimeManager.ts
- tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx
autonomous: true
requirements: [CTRL-01, CTRL-02, CTRL-03]
must_haves:
truths:
- The runtime manager knows which lifecycle command is active and can expose action-specific feedback instead of one generic busy state.
- The runtime feature classifies draft changes as immediate, restart-required, or save-before-apply so the UI can explain what happens next.
- Frontend command guards stay aligned with the backend lifecycle contract from plan 02-01.
artifacts:
- path: tauri-app/src/features/runtime/useRuntimeManager.ts
provides: lifecycle command state, completion feedback, and apply-impact orchestration on top of the Phase 1 draft model
- path: tauri-app/src/features/runtime/runtime-utils.ts
provides: reusable lifecycle labels, action guards, and apply-semantics helpers for runtime surfaces
- path: tauri-app/src/features/runtime/types.ts
provides: frontend types for active lifecycle commands, command results, and apply-impact values
- path: tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx
provides: integrated regression coverage for lifecycle semantics at the React feature layer
key_links:
- from: tauri-app/src/features/runtime/api.ts
to: tauri-app/src/features/runtime/types.ts
via: typed runtime snapshot fields mirrored from the Tauri backend
pattern: RuntimeSnapshot|last_error|status
- from: tauri-app/src/features/runtime/useRuntimeManager.ts
to: tauri-app/src/features/runtime/runtime-utils.ts
via: apply-impact classification and lifecycle command label helpers
pattern: start|stop|restart|required
---
<objective>
Teach the frontend runtime state layer how to represent lifecycle operations and apply semantics before any surface copy or button behavior changes.
Purpose: keep lifecycle trust rules in one manager-owned place, just as Phase 1 centralized draft ownership.
Output: typed frontend lifecycle state, reusable apply-impact helpers, and test coverage proving the manager exposes the right action-specific states.
</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/REQUIREMENTS.md
@.planning/phases/02-lifecycle-command-safety/02-RESEARCH.md
@.planning/phases/02-lifecycle-command-safety/02-01-SUMMARY.md
@tauri-app/src/features/runtime/types.ts
@tauri-app/src/features/runtime/api.ts
@tauri-app/src/features/runtime/runtime-utils.ts
@tauri-app/src/features/runtime/useRuntimeManager.ts
@tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx
<interfaces>
From `tauri-app/src/features/runtime/useRuntimeManager.ts`:
```ts
export function useRuntimeManager() {
return {
snapshot,
liveSnapshot,
savedBaseline,
draftConfig,
draftDirty,
draftOpen,
draftFields,
busy,
refresh,
saveDraft,
saveConfig,
startLocal,
stopLocal,
};
}
```
From `tauri-app/src/features/runtime/types.ts`:
```ts
export interface RuntimeSnapshot {
status: RuntimeStatus;
ready: boolean;
process_running: boolean;
resolved_url: string;
binary_path: string | null;
last_error: RuntimeErrorInfo | null;
config: RuntimeConfig;
}
```
</interfaces>
</context>
<tasks>
<task type="auto" tdd="true">
<name>Task 1: Mirror backend lifecycle metadata and define frontend apply-impact contracts</name>
<files>tauri-app/src/features/runtime/types.ts, tauri-app/src/features/runtime/api.ts, tauri-app/src/features/runtime/runtime-utils.ts</files>
<read_first>
- tauri-app/src/features/runtime/types.ts
- tauri-app/src/features/runtime/api.ts
- tauri-app/src/features/runtime/runtime-utils.ts
- tauri-app/src-tauri/src/runtime/types.rs
- .planning/phases/02-lifecycle-command-safety/02-RESEARCH.md
</read_first>
<behavior>
- Test 1: the frontend `RuntimeSnapshot` includes the backend lifecycle command fields added in plan 02-01.
- Test 2: a helper can classify a draft as `immediate`, `restart_required`, or `save_before_apply` from `savedBaseline`, `draftConfig`, and `snapshot.process_running`.
</behavior>
<action>Update `tauri-app/src/features/runtime/types.ts` to mirror the new backend lifecycle snapshot fields using concrete frontend unions for active command values `idle | save | start | stop | save_and_start`, command outcomes `succeeded | blocked | failed`, and apply-impact values `immediate | restart_required | save_before_apply`. Update `tauri-app/src/features/runtime/api.ts` to preserve these fields in the local fallback snapshot shape instead of dropping them. Add reusable helpers in `tauri-app/src/features/runtime/runtime-utils.ts` that classify draft impact using the backend restart-impact field list (`connection_mode`, `model_path`, `addr`, `gpu_layers`, `ctx_size`) and current runtime state.</action>
<acceptance_criteria>
- `tauri-app/src/features/runtime/types.ts` exports frontend lifecycle command and apply-impact types.
- `tauri-app/src/features/runtime/api.ts` fallback snapshots include the new lifecycle metadata fields.
- `tauri-app/src/features/runtime/runtime-utils.ts` contains logic that references `connection_mode`, `model_path`, `addr`, `gpu_layers`, and `ctx_size` when determining restart-required impact.
</acceptance_criteria>
<verify>
<automated>npm test -- RuntimeSurface</automated>
</verify>
<done>The frontend type layer can represent both backend lifecycle results and user-facing apply semantics without ad hoc string handling.</done>
</task>
<task type="auto" tdd="true">
<name>Task 2: Replace generic busy handling with action-specific manager state</name>
<files>tauri-app/src/features/runtime/useRuntimeManager.ts, tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx</files>
<read_first>
- tauri-app/src/features/runtime/useRuntimeManager.ts
- tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx
- tauri-app/src/features/runtime/runtime-utils.ts
- tauri-app/src/features/runtime/types.ts
- .planning/phases/02-lifecycle-command-safety/02-01-SUMMARY.md
</read_first>
<behavior>
- Test 1: starting the runtime exposes an active command of `start` and resolves to a completion result with a stable success message.
- Test 2: stopping the runtime exposes an active command of `stop` and blocks duplicate lifecycle actions while the command is active.
- Test 3: when draft changes hit restart-impact fields while the process is running, the manager exposes `restart_required` instead of pretending the save is immediately applied.
</behavior>
<action>Refactor `tauri-app/src/features/runtime/useRuntimeManager.ts` so it exposes explicit manager-owned fields for `activeLifecycleCommand`, `lastLifecycleResult`, `lifecycleBusy`, and `applyImpact` rather than relying only on `busy`. Map `saveDraft`, `saveConfig`, `startLocal`, and `stopLocal` to concrete command names `save`, `save_and_start`, `start`, and `stop`. Preserve Phase 1 draft safety: polling must still avoid overwriting dirty draft values. When a command resolves, store a result message based on the backend snapshot metadata or fallback defaults such as `Local API started.`, `Local API stopped.`, `Save completed.`, or the backend-provided blocked/failed message. Update `RuntimeSurface.test.tsx` so the feature harness asserts action-specific state instead of only the generic `busy` boolean.</action>
<acceptance_criteria>
- `tauri-app/src/features/runtime/useRuntimeManager.ts` exports `activeLifecycleCommand`, `lastLifecycleResult`, or equivalent explicit action-specific fields.
- The manager still preserves dirty draft values across polling while lifecycle state changes.
- `tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx` contains lifecycle assertions for start, stop, blocked duplicates, and restart-required saves.
</acceptance_criteria>
<verify>
<automated>npm test -- RuntimeSurface</automated>
</verify>
<done>The runtime manager becomes the single source of truth for lifecycle command progress, completion, and apply semantics.</done>
</task>
</tasks>
<verification>
- `npm test -- RuntimeSurface`
</verification>
<success_criteria>
- Frontend state exposes action-specific lifecycle progress and completion information.
- Apply-impact classification matches backend restart-required rules.
- Duplicate/conflicting lifecycle actions are blocked at the manager layer before the UI triggers them.
</success_criteria>
<output>
After completion, create `.planning/phases/02-lifecycle-command-safety/02-02-SUMMARY.md`
</output>