# Internal: Command Restore ## Purpose Define the implemented `narratio restore` command contract: committed remote-state discovery, deterministic planning, safe file installation, conflict policy, and restore reporting. ## Inputs and outputs Inputs: - CLI flags: `--config`, `--session`, `--session-id`, `--dry-run`, `--force`, `--include-audio`. - Resolved/validated `pipeline.yml` and `session.yml`. - Configured remote object store. - Remote committed current-state markers (`current/run_id.txt`, `current/manifest.json`). Outputs: - Dry-run summary to stdout (plan + counts). - Non-dry-run completion summary to stdout. - Local durable session files restored under canonical session root. - Non-dry-run restore report at `reports/restore-latest.json`. ## Boundaries Owns: - Restore command flag parsing and command wiring. - Remote current-state discovery and identity validation. - Restore plan construction and conflict classification. - Restore execution for planned downloads. - Restore report model and persistence. Does not own: - Stage execution orchestration (`run`, `resume`, `run-stage`). - Archive publish behavior (owned by archive stage). - Storage transport implementation details (owned by storage adapters). ## Config fields used - Config/session discovery and templating fields consumed by all commands. - `pipeline.workspace.root` (local restore target root). - `pipeline.storage.*` (remote backend + archive identity derivation). - `pipeline.storage.s3.*` identity components used by archive prefix helpers. - `session.session_id` - `session.campaign` ## External adapters used - `storage.ObjectStore` for `Exists`, `List`, `Download`. - `artifacts.Store` (`LocalStore`) for layout and session lock management. - `manifest.LocalStore` for manifest decode/validation and identity checks. ## State and manifest behavior - Restore is not a pipeline run and does not create a run manifest. - Restore uses committed remote current state only: - `current/run_id.txt` must exist and be non-empty. - `current/manifest.json` must decode and match requested session/campaign. - Non-dry-run writes restore files to canonical session paths. - Manifest install behavior: - validated before replacement. - installed last among download actions. - existing local manifest is preserved if restored manifest validation/install fails. - Non-dry-run report persists summary/action status metadata in `reports/restore-latest.json`. ## Skip and resume behavior - Restore does not participate in stage skip/resume decisions. - Restore provides durable local state so subsequent stage commands can resume or rerun based on restored manifest state. - Dry-run is read-only and returns plan output only. ## Failure behavior - Fails when storage backend is unavailable or archive identity cannot be resolved. - Fails when remote current pointer/manifest is missing or invalid. - Fails when remote manifest identity mismatches requested campaign/session. - Fails on local conflicts unless `--force` is set. - Fails fast on session lock acquisition conflict for non-dry-run execution. - On execution failure, previously installed files remain; no rollback is performed. ## Tests to inspect before changing - `internal/app/restore_test.go` - `internal/app/restore_discovery_test.go` - `internal/app/restore_plan_test.go` - `internal/app/restore_execution_test.go` - `internal/app/restore_workflow_test.go` - `internal/artifacts/archive_identity_test.go` ## Architectural invariants - Restore relies on centralized archive identity/key helpers (`internal/artifacts`) rather than ad hoc key building. - `current/run_id.txt` is the remote commit marker; restore must not infer committed state from incidental files. - Local path mapping is traversal-safe and constrained to session root. - Restore scope is deterministic and path-classified: - include `manifest.json`, `transcripts/**`, `artifacts/**` - include `audio/**` only with `--include-audio` - exclude `runs/**`, `logs/**`, `reports/**`, `config/**`, `inputs/**` - Command remains standalone; no implicit `run --restore` behavior.