Initial ForgeLM import
This commit is contained in:
commit
a392b9dc60
4296 files changed
+1212675
No files matched your search
@@ -0,0 +1,159 @@
|
||||
---
|
||||
phase: 02-lifecycle-command-safety
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- tauri-app/src-tauri/src/runtime/mod.rs
|
||||
- tauri-app/src-tauri/src/runtime/state.rs
|
||||
- tauri-app/src-tauri/src/runtime/types.rs
|
||||
autonomous: true
|
||||
requirements: [CTRL-01, CTRL-03]
|
||||
must_haves:
|
||||
truths:
|
||||
- The runtime backend distinguishes active lifecycle operations from idle snapshots so overlapping start and stop requests do not silently race.
|
||||
- The runtime backend returns explicit conflict or completion metadata that frontend consumers can turn into trustworthy lifecycle feedback.
|
||||
- Restart-impacting save rules remain aligned with the actual backend fields that require a local runtime restart.
|
||||
artifacts:
|
||||
- path: tauri-app/src-tauri/src/runtime/mod.rs
|
||||
provides: lifecycle command guards, structured command results, and start/stop flow behavior
|
||||
- path: tauri-app/src-tauri/src/runtime/state.rs
|
||||
provides: authoritative runtime snapshot state and process-refresh rules for in-flight lifecycle actions
|
||||
- path: tauri-app/src-tauri/src/runtime/types.rs
|
||||
provides: serialized lifecycle metadata that the frontend can consume without guessing command outcomes
|
||||
key_links:
|
||||
- from: tauri-app/src-tauri/src/runtime/mod.rs
|
||||
to: tauri-app/src-tauri/src/runtime/types.rs
|
||||
via: serialized lifecycle command fields added to the runtime snapshot
|
||||
pattern: RuntimeSnapshot|RuntimeStatus|last_error
|
||||
- from: tauri-app/src-tauri/src/runtime/mod.rs
|
||||
to: tauri-app/src-tauri/src/runtime/state.rs
|
||||
via: shared guard rules for starting, stopping, and process refresh transitions
|
||||
pattern: start|stop|refresh_process_state
|
||||
---
|
||||
|
||||
<objective>
|
||||
Create the backend lifecycle contract that Phase 2 can build on before frontend state and UI changes begin.
|
||||
|
||||
Purpose: make start, stop, and conflicting lifecycle requests deterministic at the Tauri runtime boundary instead of relying on a single frontend `busy` boolean.
|
||||
Output: runtime snapshot metadata and guard behavior that explicitly describe in-flight operations, blocked conflicts, and lifecycle completion outcomes.
|
||||
</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
|
||||
@tauri-app/src-tauri/src/runtime/mod.rs
|
||||
@tauri-app/src-tauri/src/runtime/state.rs
|
||||
@tauri-app/src-tauri/src/runtime/types.rs
|
||||
|
||||
<interfaces>
|
||||
From `tauri-app/src-tauri/src/runtime/types.rs`:
|
||||
|
||||
```rust
|
||||
pub enum RuntimeStatus {
|
||||
Stopped,
|
||||
Starting,
|
||||
Ready,
|
||||
Degraded,
|
||||
Stopping,
|
||||
Error,
|
||||
}
|
||||
|
||||
pub struct RuntimeSnapshot {
|
||||
pub status: RuntimeStatus,
|
||||
pub ready: bool,
|
||||
pub process_running: bool,
|
||||
pub resolved_url: String,
|
||||
pub binary_path: Option<String>,
|
||||
pub last_error: Option<RuntimeErrorInfo>,
|
||||
pub config: RuntimeConfig,
|
||||
}
|
||||
```
|
||||
|
||||
From `tauri-app/src-tauri/src/runtime/mod.rs`:
|
||||
|
||||
```rust
|
||||
pub fn save_runtime_config_command(...) -> Result<RuntimeSnapshot, String>;
|
||||
pub fn start_runtime(...) -> Result<RuntimeSnapshot, String>;
|
||||
pub fn stop_runtime(...) -> Result<RuntimeSnapshot, String>;
|
||||
```
|
||||
</interfaces>
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 1: Add explicit lifecycle command metadata to the runtime snapshot</name>
|
||||
<files>tauri-app/src-tauri/src/runtime/types.rs, tauri-app/src-tauri/src/runtime/state.rs</files>
|
||||
<read_first>
|
||||
- tauri-app/src-tauri/src/runtime/types.rs
|
||||
- tauri-app/src-tauri/src/runtime/state.rs
|
||||
- tauri-app/src/features/runtime/types.ts
|
||||
- .planning/phases/02-lifecycle-command-safety/02-RESEARCH.md
|
||||
</read_first>
|
||||
<behavior>
|
||||
- Test 1: the serialized runtime snapshot exposes the currently active lifecycle action and the last completed lifecycle result.
|
||||
- Test 2: snapshots still report existing status, readiness, process_running, and error fields without breaking current callers.
|
||||
</behavior>
|
||||
<action>Extend `tauri-app/src-tauri/src/runtime/types.rs` and `tauri-app/src-tauri/src/runtime/state.rs` with concrete lifecycle metadata. Add a serialized enum or string union for the active command with the values `idle`, `save`, `start`, `stop`, and `save_and_start`. Add a serialized result payload or equivalent snapshot fields that record the last command name, a terminal outcome of `succeeded`, `blocked`, or `failed`, and a human-readable message. Keep the existing `RuntimeSnapshot`, `RuntimeStatus`, and `RuntimeErrorInfo` fields intact; add new fields instead of replacing old ones so brownfield frontend callers continue compiling.</action>
|
||||
<acceptance_criteria>
|
||||
- `tauri-app/src-tauri/src/runtime/types.rs` defines serialized lifecycle command metadata alongside `RuntimeSnapshot`.
|
||||
- `tauri-app/src-tauri/src/runtime/state.rs` stores enough lifecycle metadata to build snapshots with active-command and last-result information.
|
||||
- Existing snapshot fields `status`, `ready`, `process_running`, `resolved_url`, `binary_path`, `last_error`, and `config` remain present in `RuntimeSnapshot`.
|
||||
</acceptance_criteria>
|
||||
<verify>
|
||||
<automated>cargo test -p tauri-app runtime::</automated>
|
||||
</verify>
|
||||
<done>The runtime snapshot becomes an explicit transport for lifecycle state instead of forcing the frontend to infer command outcomes from generic status changes.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 2: Guard conflicting lifecycle commands and preserve restart-impacting save rules</name>
|
||||
<files>tauri-app/src-tauri/src/runtime/mod.rs, tauri-app/src-tauri/src/runtime/state.rs</files>
|
||||
<read_first>
|
||||
- tauri-app/src-tauri/src/runtime/mod.rs
|
||||
- tauri-app/src-tauri/src/runtime/state.rs
|
||||
- tauri-app/src-tauri/src/runtime/process.rs
|
||||
- .planning/phases/02-lifecycle-command-safety/02-RESEARCH.md
|
||||
</read_first>
|
||||
<behavior>
|
||||
- Test 1: a second `start_runtime` request while a start or stop command is active returns a blocked lifecycle result instead of mutating process state.
|
||||
- Test 2: `stop_runtime` while no local process is running returns a blocked or no-op lifecycle result with a stable message.
|
||||
- Test 3: saving a running local config that changes `connection_mode`, `model_path`, `addr`, `gpu_layers`, or `ctx_size` still returns `restart_required` guidance.
|
||||
</behavior>
|
||||
<action>Refactor `tauri-app/src-tauri/src/runtime/mod.rs` to centralize lifecycle command guards before mutating process state. Add explicit conflict handling for these cases: `start_runtime` while `status` is `Starting` or `Stopping`, `start_runtime` while a managed child already exists, `stop_runtime` while `status` is `Starting` or `Stopping`, and `stop_runtime` when no managed child exists. For each blocked case, populate the new lifecycle result metadata with `blocked` and a concrete message such as `Local API start already in progress.`, `Stop the local API before starting it again.`, or `Local API is already stopped.`. Preserve the existing restart-impacting save guard for `connection_mode`, `model_path`, `addr`, `gpu_layers`, and `ctx_size`, and route it through the same structured lifecycle result metadata so the frontend receives one consistent contract.</action>
|
||||
<acceptance_criteria>
|
||||
- `tauri-app/src-tauri/src/runtime/mod.rs` contains explicit guard branches for duplicate or conflicting start/stop requests.
|
||||
- Blocked lifecycle cases return concrete user-facing messages containing `already in progress`, `already running`, or `already stopped`.
|
||||
- The restart-impacting field list in `requires_runtime_restart` remains limited to `connection_mode`, `model_path`, `addr`, `gpu_layers`, and `ctx_size` unless tests are updated to prove a different list.
|
||||
</acceptance_criteria>
|
||||
<verify>
|
||||
<automated>cargo test -p tauri-app runtime::</automated>
|
||||
</verify>
|
||||
<done>The backend becomes the authoritative source for lifecycle conflict prevention and restart-required guidance.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `cargo test -p tauri-app runtime::`
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Start and stop requests have explicit blocked-state outcomes instead of silent no-ops.
|
||||
- Runtime snapshots expose active and completed lifecycle command information.
|
||||
- Restart-required saves still map to the existing backend-impact field list.
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/02-lifecycle-command-safety/02-01-SUMMARY.md`
|
||||
</output>
|
||||
@@ -0,0 +1,106 @@
|
||||
---
|
||||
phase: 02-lifecycle-command-safety
|
||||
plan: 01
|
||||
subsystem: runtime
|
||||
tags: [tauri, rust, lifecycle, runtime, desktop]
|
||||
requires:
|
||||
- phase: 01-draft-state-ownership
|
||||
provides: runtime draft/live separation that lifecycle metadata now extends without clobbering edits
|
||||
provides:
|
||||
- explicit runtime snapshot lifecycle command metadata
|
||||
- backend guards for conflicting local runtime start and stop requests
|
||||
- restart-required save guidance aligned to backend-owned runtime fields
|
||||
affects: [phase-02-02, phase-02-03, runtime-workspace]
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns: [snapshot lifecycle transport, centralized runtime command guards]
|
||||
key-files:
|
||||
created: []
|
||||
modified:
|
||||
- tauri-app/src-tauri/src/runtime/types.rs
|
||||
- tauri-app/src-tauri/src/runtime/state.rs
|
||||
- tauri-app/src-tauri/src/runtime/mod.rs
|
||||
key-decisions:
|
||||
- "Expose active and last lifecycle command data on RuntimeSnapshot so frontend polling can render trustworthy lifecycle feedback without inferring from status alone."
|
||||
- "Centralize duplicate start/stop blocking in runtime state helpers so save, start, and stop flows share the same command-result contract."
|
||||
- "Keep restart-required save enforcement limited to connection_mode, model_path, addr, gpu_layers, and ctx_size to stay aligned with the existing backend runtime boundary."
|
||||
patterns-established:
|
||||
- "RuntimeSnapshot includes active_command plus last_command_result for stable in-flight and terminal lifecycle messaging."
|
||||
- "Lifecycle commands update terminal outcomes through helper functions instead of ad-hoc last_error-only handling."
|
||||
requirements-completed: [CTRL-01, CTRL-03]
|
||||
duration: 6min
|
||||
completed: 2026-03-29
|
||||
---
|
||||
|
||||
# Phase 2 Plan 01: Lifecycle Command Safety Summary
|
||||
|
||||
**Runtime snapshot lifecycle metadata and guarded local start/stop/save outcomes at the Tauri runtime boundary**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 6 min
|
||||
- **Started:** 2026-03-29T03:45:48Z
|
||||
- **Completed:** 2026-03-29T03:51:43Z
|
||||
- **Tasks:** 2
|
||||
- **Files modified:** 3
|
||||
|
||||
## Accomplishments
|
||||
- Added serialized lifecycle command metadata to `RuntimeSnapshot` so backend snapshots now report both the active command and the last completed command result.
|
||||
- Centralized lifecycle result helpers and guard rules in runtime state so duplicate start/stop requests return stable blocked messages instead of silent no-ops.
|
||||
- Routed restart-required saves and lifecycle success/failure paths through one command-result contract while preserving the existing backend restart-impact field list.
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: Add explicit lifecycle command metadata to the runtime snapshot** - `217e265` (test)
|
||||
2. **Task 1: Add explicit lifecycle command metadata to the runtime snapshot** - `cf73eb2` (feat)
|
||||
3. **Task 2: Guard conflicting lifecycle commands and preserve restart-impacting save rules** - `581b81b` (test)
|
||||
4. **Task 2: Guard conflicting lifecycle commands and preserve restart-impacting save rules** - `67651bf` (feat)
|
||||
|
||||
## Files Created/Modified
|
||||
- `tauri-app/src-tauri/src/runtime/types.rs` - defines lifecycle command and result payloads on runtime snapshots.
|
||||
- `tauri-app/src-tauri/src/runtime/state.rs` - stores lifecycle metadata, shared guard helpers, and regression tests for blocked command behavior.
|
||||
- `tauri-app/src-tauri/src/runtime/mod.rs` - applies guard helpers to save/start/stop commands and records consistent lifecycle outcomes.
|
||||
|
||||
## Decisions Made
|
||||
- Used snapshot-level lifecycle transport instead of separate command-specific responses so existing polling consumers can adopt the new contract incrementally.
|
||||
- Kept blocked lifecycle feedback in `last_command_result` while reserving `last_error` for actual runtime failures such as restart-required, spawn, health, and stop failures.
|
||||
- Preserved the restart-required field list exactly as planned and covered non-restart fields with regression tests.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 1 - Bug] Cleared latched active commands when config persistence fails**
|
||||
- **Found during:** Task 2 (Guard conflicting lifecycle commands and preserve restart-impacting save rules)
|
||||
- **Issue:** Beginning a save or save-and-start command before persisting config could leave `active_command` stuck if `save_runtime_config` returned an error.
|
||||
- **Fix:** Added failure handling that records a failed lifecycle result, stores `save_failed`, and exits without leaving the runtime in an in-flight command state.
|
||||
- **Files modified:** `tauri-app/src-tauri/src/runtime/mod.rs`
|
||||
- **Verification:** `cargo test --manifest-path "tauri-app/src-tauri/Cargo.toml" runtime::` and `cargo check --manifest-path "tauri-app/src-tauri/Cargo.toml"`
|
||||
- **Committed in:** `67651bf` (part of task commit)
|
||||
|
||||
---
|
||||
|
||||
**Total deviations:** 1 auto-fixed (1 bug)
|
||||
**Impact on plan:** The auto-fix kept the new lifecycle contract trustworthy under save failures without expanding scope beyond the planned backend boundary.
|
||||
|
||||
## Issues Encountered
|
||||
- The plan's verification command used `cargo test -p tauri-app runtime::`, but the Tauri crate is named `forgelm-chat`; verification succeeded via `cargo test --manifest-path "tauri-app/src-tauri/Cargo.toml" runtime::`.
|
||||
|
||||
## User Setup Required
|
||||
|
||||
None - no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
- Frontend lifecycle manager work can now read `active_command` and `last_command_result` directly from runtime snapshots.
|
||||
- Restart/apply UI work can rely on the backend restart-required contract staying limited to `connection_mode`, `model_path`, `addr`, `gpu_layers`, and `ctx_size`.
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- Summary file exists at `.planning/phases/02-lifecycle-command-safety/02-01-SUMMARY.md`.
|
||||
- Verified commit hashes `217e265`, `cf73eb2`, `581b81b`, and `67651bf` are present in git history.
|
||||
|
||||
---
|
||||
*Phase: 02-lifecycle-command-safety*
|
||||
*Completed: 2026-03-29*
|
||||
@@ -0,0 +1,173 @@
|
||||
---
|
||||
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>
|
||||
@@ -0,0 +1,92 @@
|
||||
---
|
||||
phase: 02-lifecycle-command-safety
|
||||
plan: 02
|
||||
subsystem: ui
|
||||
tags: [react, typescript, runtime, lifecycle, tauri]
|
||||
requires:
|
||||
- phase: 02-lifecycle-command-safety
|
||||
provides: backend lifecycle snapshot metadata and conflict guards from plan 02-01
|
||||
provides:
|
||||
- frontend lifecycle command and result types
|
||||
- manager-owned lifecycle progress and apply-impact state
|
||||
- RuntimeSurface regression coverage for lifecycle manager semantics
|
||||
affects: [phase-02-03, runtime-status-card, runtime-settings-drawer]
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns: [manager-owned lifecycle state, apply-impact classification from saved-versus-draft config]
|
||||
key-files:
|
||||
created: []
|
||||
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
|
||||
key-decisions:
|
||||
- "Mirror backend lifecycle metadata directly into the frontend RuntimeSnapshot so polling and command responses share one contract."
|
||||
- "Derive applyImpact from saved baseline versus draft config using the backend restart-required field list instead of UI-only heuristics."
|
||||
- "Expose activeLifecycleCommand, lastLifecycleResult, and lifecycleBusy from the manager so status-card and drawer copy can consume explicit state in plan 02-03."
|
||||
patterns-established:
|
||||
- "Runtime manager normalizes lifecycle metadata on every snapshot before reconciling draft-safe state."
|
||||
- "Blocked duplicate lifecycle requests become manager-visible lifecycle results before UI surfaces render them."
|
||||
requirements-completed: [CTRL-01, CTRL-02, CTRL-03]
|
||||
duration: 14min
|
||||
completed: 2026-03-29
|
||||
---
|
||||
|
||||
# Phase 2 Plan 02: Lifecycle Command Safety Summary
|
||||
|
||||
**Frontend runtime state now tracks explicit lifecycle commands, completion messages, and restart/apply impact on top of the Phase 1 draft model**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 14 min
|
||||
- **Started:** 2026-03-29T03:56:04Z
|
||||
- **Completed:** 2026-03-29T04:10:22Z
|
||||
- **Tasks:** 2
|
||||
- **Files modified:** 5
|
||||
|
||||
## Accomplishments
|
||||
- Added frontend lifecycle command, result, and apply-impact types plus fallback snapshot support in the runtime API layer.
|
||||
- Refactored the runtime manager to expose `activeLifecycleCommand`, `lastLifecycleResult`, `lifecycleBusy`, and `applyImpact` while keeping dirty-draft polling safety intact.
|
||||
- Expanded `RuntimeSurface` tests to cover lifecycle metadata mirroring, apply-impact classification, start/stop progress, and restart-required manager state.
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: Mirror backend lifecycle metadata and define frontend apply-impact contracts** - `a72c902` (test)
|
||||
2. **Task 1: Mirror backend lifecycle metadata and define frontend apply-impact contracts** - `2cb6cad` (feat)
|
||||
3. **Task 2: Replace generic busy handling with action-specific manager state** - `1d45342` (test)
|
||||
4. **Task 2: Replace generic busy handling with action-specific manager state** - `1bcd4be` (feat)
|
||||
|
||||
## Files Created/Modified
|
||||
- `tauri-app/src/features/runtime/types.ts` - mirrors backend lifecycle fields and apply-impact unions in the frontend contract.
|
||||
- `tauri-app/src/features/runtime/api.ts` - preserves lifecycle result metadata in local fallback snapshots.
|
||||
- `tauri-app/src/features/runtime/runtime-utils.ts` - classifies apply impact from the backend restart-required field list and provides lifecycle result defaults.
|
||||
- `tauri-app/src/features/runtime/useRuntimeManager.ts` - owns explicit lifecycle progress and completion state alongside the existing draft/live split.
|
||||
- `tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx` - covers manager lifecycle semantics through the React runtime feature harness.
|
||||
|
||||
## Decisions Made
|
||||
- Normalized snapshots inside the manager so older fallback payloads and fresh backend payloads both produce defined lifecycle fields.
|
||||
- Kept `busy` available for brownfield consumers while adding explicit lifecycle state that plan 02-03 can render directly.
|
||||
- Used the backend restart-required field list (`connection_mode`, `model_path`, `addr`, `gpu_layers`, `ctx_size`) as the only source of truth for `restart_required` apply impact.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
None - plan executed as written.
|
||||
|
||||
## Issues Encountered
|
||||
- None.
|
||||
|
||||
## User Setup Required
|
||||
|
||||
None - no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
- `RuntimeStatusCard` and `RuntimeSettingsDrawer` can now render explicit lifecycle progress and apply guidance from manager props instead of inferring from `busy`.
|
||||
- Phase 2 UI work can show restart-required and save-before-apply messaging without re-implementing backend guard logic.
|
||||
|
||||
---
|
||||
*Phase: 02-lifecycle-command-safety*
|
||||
*Completed: 2026-03-29*
|
||||
@@ -0,0 +1,163 @@
|
||||
---
|
||||
phase: 02-lifecycle-command-safety
|
||||
plan: 03
|
||||
type: execute
|
||||
wave: 3
|
||||
depends_on: [02-02]
|
||||
files_modified:
|
||||
- tauri-app/src/features/runtime/components/RuntimeStatusCard.tsx
|
||||
- tauri-app/src/features/runtime/components/RuntimeStatusCard.css
|
||||
- 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: [CTRL-01, CTRL-02, CTRL-03]
|
||||
must_haves:
|
||||
truths:
|
||||
- The runtime workspace tells the user exactly which lifecycle action is happening, what completed, and whether a saved draft is live now or waiting for restart/apply.
|
||||
- Status-card and drawer controls disable or relabel themselves consistently while a conflicting lifecycle action is in progress.
|
||||
- Restart-required and save-before-apply guidance is visible before the user commits a high-impact action.
|
||||
artifacts:
|
||||
- path: tauri-app/src/features/runtime/components/RuntimeStatusCard.tsx
|
||||
provides: authoritative status-card action labels, blocked states, and completion messaging for runtime lifecycle actions
|
||||
- path: tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx
|
||||
provides: explicit apply-semantics guidance and lifecycle CTA copy inside the draft editor
|
||||
- path: tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx
|
||||
provides: integrated UI regression coverage for lifecycle commands and apply feedback
|
||||
key_links:
|
||||
- from: tauri-app/src/features/runtime/useRuntimeManager.ts
|
||||
to: tauri-app/src/features/runtime/components/RuntimeStatusCard.tsx
|
||||
via: active lifecycle command, lifecycle result, and action guards passed as props
|
||||
pattern: start|stop|retry|result
|
||||
- from: tauri-app/src/features/runtime/useRuntimeManager.ts
|
||||
to: tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx
|
||||
via: applyImpact and lifecycle status passed into drawer CTA and helper copy
|
||||
pattern: restart_required|save_before_apply|lifecycleBusy
|
||||
---
|
||||
|
||||
<objective>
|
||||
Finish Phase 2 by making lifecycle command safety visible and trustworthy in the runtime workspace.
|
||||
|
||||
Purpose: expose the backend and manager semantics from plans 02-01 and 02-02 through the status card and settings drawer without regressing Phase 1 draft UX.
|
||||
Output: clear CTA labels, restart/apply guidance, blocked-state rules, and end-to-end UI regressions for lifecycle safety.
|
||||
</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
|
||||
@.planning/phases/02-lifecycle-command-safety/02-02-SUMMARY.md
|
||||
@tauri-app/src/features/runtime/components/RuntimeStatusCard.tsx
|
||||
@tauri-app/src/features/runtime/components/RuntimeStatusCard.css
|
||||
@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/RuntimeStatusCard.tsx`:
|
||||
|
||||
```tsx
|
||||
interface Props {
|
||||
snapshot: RuntimeSnapshot;
|
||||
loading: boolean;
|
||||
busy: boolean;
|
||||
onOpenSettings: () => void;
|
||||
onStart: () => void;
|
||||
onStop: () => void;
|
||||
}
|
||||
```
|
||||
|
||||
From `tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx`:
|
||||
|
||||
```tsx
|
||||
interface Props {
|
||||
open: boolean;
|
||||
snapshot: RuntimeSnapshot;
|
||||
busy: boolean;
|
||||
onSave: (patch: Partial<RuntimeConfig>) => Promise<RuntimeSnapshot>;
|
||||
onStart: () => Promise<unknown>;
|
||||
onStop: () => Promise<unknown>;
|
||||
}
|
||||
```
|
||||
</interfaces>
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 1: Update the runtime status card for action-specific lifecycle feedback</name>
|
||||
<files>tauri-app/src/features/runtime/components/RuntimeStatusCard.tsx, tauri-app/src/features/runtime/components/RuntimeStatusCard.css, tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx</files>
|
||||
<read_first>
|
||||
- tauri-app/src/features/runtime/components/RuntimeStatusCard.tsx
|
||||
- tauri-app/src/features/runtime/components/RuntimeStatusCard.css
|
||||
- tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx
|
||||
- tauri-app/src/features/runtime/useRuntimeManager.ts
|
||||
- .planning/phases/02-lifecycle-command-safety/02-02-SUMMARY.md
|
||||
</read_first>
|
||||
<behavior>
|
||||
- Test 1: while a start command is active, the primary status-card action reads `Starting local API...` and conflicting controls are disabled.
|
||||
- Test 2: while a stop command is active, the primary status-card action reads `Stopping local API...` and start is not re-enabled until completion.
|
||||
- Test 3: after a blocked or failed command, the status card surfaces the latest lifecycle result message with retry guidance.
|
||||
</behavior>
|
||||
<action>Refactor `tauri-app/src/features/runtime/components/RuntimeStatusCard.tsx` to consume the explicit lifecycle fields from the runtime manager instead of only `busy`. Replace the generic label `Working...` with concrete command labels `Starting local API...` and `Stopping local API...`. Add a visible result banner or note area that renders the latest lifecycle result message from manager state, including blocked/failed copy such as `Local API start already in progress.` or `Local API stopped.`. Update `RuntimeStatusCard.css` so the new note/banner styles match the existing runtime card tone system and remain readable on desktop and mobile layouts.</action>
|
||||
<acceptance_criteria>
|
||||
- `tauri-app/src/features/runtime/components/RuntimeStatusCard.tsx` no longer renders the generic text `Working...`.
|
||||
- `tauri-app/src/features/runtime/components/RuntimeStatusCard.tsx` contains the strings `Starting local API...` and `Stopping local API...`.
|
||||
- `tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx` asserts lifecycle result messages or banners on the status card.
|
||||
</acceptance_criteria>
|
||||
<verify>
|
||||
<automated>npm test -- RuntimeSurface</automated>
|
||||
</verify>
|
||||
<done>The runtime status card becomes a trustworthy summary of what lifecycle command is happening and what just completed.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 2: Make drawer CTA copy and apply guidance explicit</name>
|
||||
<files>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</files>
|
||||
<read_first>
|
||||
- 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
|
||||
- tauri-app/src/features/runtime/runtime-utils.ts
|
||||
- .planning/phases/02-lifecycle-command-safety/02-RESEARCH.md
|
||||
</read_first>
|
||||
<behavior>
|
||||
- Test 1: when a dirty local draft changes only non-restart fields, the drawer continues to offer `Save changes` and `Save and start local API` with immediate-apply helper copy.
|
||||
- Test 2: when a running local runtime has dirty restart-impact fields, the drawer shows `Restart required to apply saved changes` and disables conflicting lifecycle actions until the user saves or stops.
|
||||
- Test 3: when the user changes connection mode from remote to local, the drawer keeps the existing `Save mode before applying` safeguard and pairs it with explicit apply guidance.
|
||||
</behavior>
|
||||
<action>Update `tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx` so the footer CTA copy is driven by `applyImpact` and active lifecycle command state. Keep `Save changes` for plain saves, keep `Save mode before applying` for pending mode switches, and add explicit helper or warning copy using these exact phrases when relevant: `Applies immediately after save.`, `Restart required to apply saved changes.`, and `Stop the local API or save first before applying this change.`. When the process is already running and restart-impact fields are dirty, disable `Save and start local API` as a conflicting action and render restart guidance instead of pretending the change is live. Update `RuntimeSettingsDrawer.css` so apply-guidance rows, warning banners, and disabled CTA states are visually distinct but consistent with the existing drawer styling.</action>
|
||||
<acceptance_criteria>
|
||||
- `tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx` contains the strings `Applies immediately after save.` and `Restart required to apply saved changes.`.
|
||||
- The drawer still contains `Save mode before applying` for mode-switch safeguards.
|
||||
- `tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx` covers immediate-apply, restart-required, and conflicting-action-disabled states.
|
||||
</acceptance_criteria>
|
||||
<verify>
|
||||
<automated>npm test -- RuntimeSurface</automated>
|
||||
</verify>
|
||||
<done>The draft editor explains exactly when a change goes live, when restart is required, and why conflicting lifecycle actions are disabled.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `npm test -- RuntimeSurface`
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Status card and drawer use action-specific lifecycle copy instead of one generic busy state.
|
||||
- Restart-required and save-before-apply semantics are visible before the user commits a conflicting action.
|
||||
- End-to-end tests prove lifecycle safety across start, stop, retry/block, and apply-guidance flows.
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/02-lifecycle-command-safety/02-03-SUMMARY.md`
|
||||
</output>
|
||||
@@ -0,0 +1,108 @@
|
||||
---
|
||||
phase: 02-lifecycle-command-safety
|
||||
plan: 03
|
||||
subsystem: ui
|
||||
tags: [react, css, runtime, lifecycle, ux]
|
||||
requires:
|
||||
- phase: 02-lifecycle-command-safety
|
||||
provides: explicit manager lifecycle state and apply-impact semantics from plan 02-02
|
||||
provides:
|
||||
- status card lifecycle progress and result messaging
|
||||
- drawer apply guidance for immediate, restart-required, and save-before-apply states
|
||||
- UI regression coverage for lifecycle-safe runtime controls
|
||||
affects: [phase-03, runtime-workspace, lifecycle-ux]
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns: [action-specific CTA copy, lifecycle result banners, pre-action apply guidance]
|
||||
key-files:
|
||||
created: []
|
||||
modified:
|
||||
- tauri-app/src/features/runtime/components/RuntimeStatusCard.tsx
|
||||
- tauri-app/src/features/runtime/components/RuntimeStatusCard.css
|
||||
- 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
|
||||
- tauri-app/src/components/Sidebar.tsx
|
||||
- tauri-app/src/features/runtime/runtime-utils.test.ts
|
||||
key-decisions:
|
||||
- "Use explicit lifecycle result banners instead of overloading last_error so completed and blocked actions remain visible after polling refreshes."
|
||||
- "Render apply guidance in the drawer before the CTA row so users see whether a draft applies immediately, needs restart, or must be saved before apply."
|
||||
- "Keep status-card and drawer props backward-compatible with optional lifecycle fields while Sidebar forwards the new manager contract."
|
||||
patterns-established:
|
||||
- "Status card consumes activeLifecycleCommand plus lastLifecycleResult to show action-specific CTA labels and stable completion feedback."
|
||||
- "Drawer CTA text and disabled states derive from applyImpact and lifecycleBusy instead of one generic busy label."
|
||||
requirements-completed: [CTRL-01, CTRL-02, CTRL-03]
|
||||
duration: 13min
|
||||
completed: 2026-03-29
|
||||
---
|
||||
|
||||
# Phase 2 Plan 03: Lifecycle Command Safety Summary
|
||||
|
||||
**The runtime workspace now tells the user what lifecycle action is running, what just completed, and whether saved draft changes apply now or wait for restart**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 13 min
|
||||
- **Started:** 2026-03-29T04:04:51Z
|
||||
- **Completed:** 2026-03-29T04:17:00Z
|
||||
- **Tasks:** 2
|
||||
- **Files modified:** 7
|
||||
|
||||
## Accomplishments
|
||||
- Replaced generic status-card busy copy with action-specific lifecycle labels and result banners.
|
||||
- Added explicit drawer guidance for immediate-apply, restart-required, and save-before-apply runtime drafts.
|
||||
- Extended UI regression coverage and build wiring so the lifecycle manager contract reaches both the sidebar shell and direct test helpers.
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: Update the runtime status card for action-specific lifecycle feedback** - `8c303a9` (test)
|
||||
2. **Task 2: Make drawer CTA copy and apply guidance explicit** - `06c1a44` (feat)
|
||||
3. **Build follow-up: wire lifecycle props through build callers** - `93f7fd9` (fix)
|
||||
|
||||
## Files Created/Modified
|
||||
- `tauri-app/src/features/runtime/components/RuntimeStatusCard.tsx` - renders explicit start/stop labels, lifecycle result messages, and disabled conflicting actions.
|
||||
- `tauri-app/src/features/runtime/components/RuntimeStatusCard.css` - styles lifecycle result banners to match the existing runtime card tone system.
|
||||
- `tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx` - drives CTA labels and helper guidance from `applyImpact`, `activeLifecycleCommand`, and `lifecycleBusy`.
|
||||
- `tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.css` - styles apply-guidance rows and lifecycle outcome messaging.
|
||||
- `tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx` - covers UI lifecycle copy, result banners, and apply-guidance behavior.
|
||||
- `tauri-app/src/components/Sidebar.tsx` - forwards lifecycle manager props to the status card and drawer.
|
||||
- `tauri-app/src/features/runtime/runtime-utils.test.ts` - keeps direct snapshot helpers aligned with the expanded lifecycle snapshot shape.
|
||||
|
||||
## Decisions Made
|
||||
- Status-card completion feedback lives in a dedicated lifecycle result banner so success, blocked, and failure messages do not compete with runtime error diagnostics.
|
||||
- Drawer helper copy uses exact operator-facing phrases from the plan to keep restart and mode-switch behavior predictable.
|
||||
- Optional lifecycle props on UI components preserve compatibility for direct component renders while the live app passes explicit manager state.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 3 - Blocking] Wired expanded lifecycle props through build callers and helper tests**
|
||||
- **Found during:** Task 2 (Make drawer CTA copy and apply guidance explicit)
|
||||
- **Issue:** `npm run build` failed because `Sidebar.tsx` and `runtime-utils.test.ts` still used the older component and snapshot contracts.
|
||||
- **Fix:** Forwarded lifecycle props from `Sidebar.tsx`, made status-card lifecycle props optional for direct renders, and updated `runtime-utils.test.ts` snapshot fixtures to include lifecycle defaults.
|
||||
- **Files modified:** `tauri-app/src/components/Sidebar.tsx`, `tauri-app/src/features/runtime/components/RuntimeStatusCard.tsx`, `tauri-app/src/features/runtime/runtime-utils.test.ts`
|
||||
- **Verification:** `npm test -- RuntimeSurface` and `npm run build`
|
||||
- **Committed in:** `93f7fd9` (follow-up fix commit)
|
||||
|
||||
---
|
||||
|
||||
**Total deviations:** 1 auto-fixed (1 blocking)
|
||||
**Impact on plan:** The follow-up kept the new UI contract buildable and testable without changing the plan's scope.
|
||||
|
||||
## Issues Encountered
|
||||
- The first full frontend build surfaced stale callers that still used the pre-Phase-2 component contracts; the fix was contained to the sidebar shell and helper test fixtures.
|
||||
|
||||
## User Setup Required
|
||||
|
||||
None - no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
- Phase 2 lifecycle command safety is ready for workspace consolidation in Phase 3.
|
||||
- Phase 3 can now compose the runtime workspace around one trustworthy lifecycle/apply state model instead of duplicated control heuristics.
|
||||
|
||||
---
|
||||
*Phase: 02-lifecycle-command-safety*
|
||||
*Completed: 2026-03-29*
|
||||
@@ -0,0 +1,72 @@
|
||||
# Phase 2 Research: Lifecycle Command Safety
|
||||
|
||||
**Date:** 2026-03-29
|
||||
**Source:** Manual orchestration fallback in current session (subagent spawning unavailable in this environment)
|
||||
|
||||
## Goal to Plan For
|
||||
|
||||
Phase 2 must make runtime lifecycle actions trustworthy after Phase 1's draft ownership work. The user should be able to:
|
||||
|
||||
- start, stop, and retry the managed local runtime with clear in-progress and completion feedback (`CTRL-01`)
|
||||
- understand whether a draft change applies immediately, requires restart, or should be saved before an apply action (`CTRL-02`)
|
||||
- avoid conflicting lifecycle actions while another lifecycle action is already running (`CTRL-03`)
|
||||
|
||||
## Current Implementation Findings
|
||||
|
||||
### Frontend runtime manager
|
||||
|
||||
- `tauri-app/src/features/runtime/useRuntimeManager.ts` owns one coarse `busy` boolean for all save and lifecycle actions.
|
||||
- `startLocal()` and `stopLocal()` optimistically set `status` to `starting` or `stopping`, but there is no explicit command metadata describing which action is in flight, what completed, or what the user should do next.
|
||||
- Polling continues every 3000 ms and already preserves dirty draft values from Phase 1, so Phase 2 should build on that state model instead of bypassing it.
|
||||
|
||||
### Runtime status and settings UI
|
||||
|
||||
- `tauri-app/src/features/runtime/components/RuntimeStatusCard.tsx` exposes a single primary action with generic busy copy (`Working...`). It does not tell the user whether the current action is a start, stop, retry, or blocked transition.
|
||||
- `tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx` already has a combined `Save and start local API` / `Stop local API` CTA and blocks saves for invalid or pending draft fields.
|
||||
- The drawer already recognizes one restart-related backend signal: it exits early when a save returns `last_error.code === "restart_required"`, but there is no explicit impact preview before save and no dedicated restart/apply guidance after save.
|
||||
|
||||
### Backend runtime commands
|
||||
|
||||
- `tauri-app/src-tauri/src/runtime/mod.rs` already prevents restart-impacting config changes while the local process is running by returning `restart_required` from `save_runtime_config_command()` when `connection_mode`, `model_path`, `addr`, `gpu_layers`, or `ctx_size` change.
|
||||
- `start_runtime_inner()` returns the current snapshot if a child process already exists, but it does not record a structured "busy/conflict" result.
|
||||
- `stop_runtime()` sets status to `Stopping`, kills the child, then returns `Stopped`, but it does not distinguish repeated stop requests, remote-mode no-ops, or user-facing completion messages.
|
||||
- `tauri-app/src-tauri/src/runtime/state.rs` already revalidates health and degrades a running process when `/health` fails, which means lifecycle feedback should continue to respect `ready`, `degraded`, and `error` states rather than flattening everything into `busy`.
|
||||
|
||||
### Existing tests and patterns
|
||||
|
||||
- `tauri-app/src/features/runtime/components/RuntimeSurface.test.tsx` already covers start, stop, save-and-start, degraded polling, and draft safety. It is the best end-to-end harness for Phase 2 regressions.
|
||||
- Phase 1 plan files under `.planning/phases/01-hf-model-discovery/` define the house style for executable plans: frontmatter with `requirements` and `must_haves`, then XML tasks with mandatory `read_first` and `acceptance_criteria` blocks.
|
||||
|
||||
## Gaps to Close in Phase 2
|
||||
|
||||
1. `busy` is too generic. The UI needs action-specific state such as `start`, `stop`, `save`, `save_and_start`, and `retry` so labels and disabled states are predictable.
|
||||
2. Apply semantics are implicit. The user can trigger save or save-and-start flows, but the UI does not explicitly explain which fields require restart and when a saved change is live versus pending restart.
|
||||
3. Conflict prevention is mostly optimistic. Frontend controls disable while `busy` is true, but backend commands do not provide a strong structured guard for duplicate or conflicting lifecycle requests.
|
||||
4. Completion behavior is underspecified. The user sees status changes, but there is no stable command-result summary for success/failure/retry guidance after a lifecycle action finishes.
|
||||
|
||||
## Planning Implications
|
||||
|
||||
Phase 2 should be split into three execution plans:
|
||||
|
||||
1. **Backend lifecycle command contract** - add explicit command guard behavior and command-result semantics at the Tauri runtime boundary.
|
||||
2. **Frontend lifecycle/apply state model** - teach the runtime manager and utilities how to classify draft impact, track the active command, and preserve actionable completion feedback.
|
||||
3. **User-facing lifecycle surfaces** - update the status card, settings drawer, and regression tests so the user sees the correct action copy, restart/apply guidance, and blocked states.
|
||||
|
||||
## Concrete Decisions for the Plans
|
||||
|
||||
- Treat these fields as restart-impacting because the backend already does: `connection_mode`, `model_path`, `addr`, `gpu_layers`, `ctx_size`.
|
||||
- Keep Phase 1 draft-preservation behavior intact; Phase 2 must layer lifecycle semantics on top of the current draft/baseline/live split rather than replacing it.
|
||||
- Use `RuntimeSurface.test.tsx` for integrated lifecycle behavior and Rust runtime tests for backend guard behavior.
|
||||
- Keep brownfield compatibility: do not remove existing `startRuntime`, `stopRuntime`, `saveRuntimeConfig`, or `RuntimeSnapshot` entry points; extend them with additional metadata instead.
|
||||
|
||||
## Risks
|
||||
|
||||
- If the frontend invents apply semantics that do not match backend restart rules, the workspace will feel inconsistent.
|
||||
- If backend guards remain implicit, racey double-clicks or overlapping drawer/status-card actions can still produce confusing no-op results.
|
||||
- If completion feedback only lives in transient button labels, users will lose the reason for a blocked or completed action after the next poll.
|
||||
|
||||
## Recommended Verification Focus
|
||||
|
||||
- Rust tests around duplicate/conflicting start/stop/save requests
|
||||
- `RuntimeSurface.test.tsx` coverage for action-specific busy labels, blocked conflicting actions, restart-required guidance, and retry/error completion flows
|
||||
- Existing Phase 1 draft safety assertions still passing after lifecycle changes
|
||||
Reference in new issue
Block a user