6.0 KiB
6.0 KiB
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.tsowns one coarsebusyboolean for all save and lifecycle actions.startLocal()andstopLocal()optimistically setstatustostartingorstopping, 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.tsxexposes 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.tsxalready has a combinedSave and start local API/Stop local APICTA 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.rsalready prevents restart-impacting config changes while the local process is running by returningrestart_requiredfromsave_runtime_config_command()whenconnection_mode,model_path,addr,gpu_layers, orctx_sizechange.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 toStopping, kills the child, then returnsStopped, but it does not distinguish repeated stop requests, remote-mode no-ops, or user-facing completion messages.tauri-app/src-tauri/src/runtime/state.rsalready revalidates health and degrades a running process when/healthfails, which means lifecycle feedback should continue to respectready,degraded, anderrorstates rather than flattening everything intobusy.
Existing tests and patterns
tauri-app/src/features/runtime/components/RuntimeSurface.test.tsxalready 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 withrequirementsandmust_haves, then XML tasks with mandatoryread_firstandacceptance_criteriablocks.
Gaps to Close in Phase 2
busyis too generic. The UI needs action-specific state such asstart,stop,save,save_and_start, andretryso labels and disabled states are predictable.- 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.
- Conflict prevention is mostly optimistic. Frontend controls disable while
busyis true, but backend commands do not provide a strong structured guard for duplicate or conflicting lifecycle requests. - 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:
- Backend lifecycle command contract - add explicit command guard behavior and command-result semantics at the Tauri runtime boundary.
- 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.
- 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.tsxfor integrated lifecycle behavior and Rust runtime tests for backend guard behavior. - Keep brownfield compatibility: do not remove existing
startRuntime,stopRuntime,saveRuntimeConfig, orRuntimeSnapshotentry 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.tsxcoverage 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