# Internal: Command Restore ## Purpose Define the implemented `narratio session restore` contract: committed remote-state discovery, deterministic plan classification, safe file install semantics, and restore reporting. ## Inputs and outputs Inputs: - CLI syntax: `narratio session restore `. - CLI flags: `--config`, `--campaign`, `--campaign-file`, `--session`, `--previous-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`). - Publish-stage behavior. - 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 + publish identity derivation). - `pipeline.storage.s3.*` identity components used by session-prefix helpers. - `pipeline.spool.root` for active audio downloads. - `pipeline.cache.root` and `pipeline.cache.s3_audio` for reusable S3 audio cache. - `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. - With `--include-audio`, restore uses the shared S3 audio cache for `audio/**` objects. Cache hits avoid object downloads; cache misses download through spool, install the work file, and populate cache. - 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`. Restore path scope: - includes: - `manifest.json` - `transcripts/**` - `artifacts/**` - `previous/**` - `audio/**` only when `--include-audio` is set - excludes: - `runs/**` - `logs/**` - `reports/**` - `config/**` - `inputs/**` - remote `current/**` pointer files as local restore targets ## 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. - Audio cache is outside the workspace and is reused across restore and prepare invocations. - Dry-run is read-only and returns plan output only. ## Failure behavior - Fails when storage backend is unavailable or publish 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 path/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/**`, `previous/**` - include `audio/**` only with `--include-audio` - exclude `runs/**`, `logs/**`, `reports/**`, `config/**`, `inputs/**` - Command remains standalone; no implicit `run --restore` behavior.