# Harbor state recovery Harbor keeps the existing data paths and volumes. `state.json` now uses `schemaVersion: 1`; subscription cache, generated sing-box config and HWID keep their existing filenames. ## Atomic writes Persistent files are written to a unique temporary file in the same directory, flushed with `fsync`, closed and atomically renamed over the target. A failure before rename leaves the previous target untouched and removes the temporary file. ## Migration On startup, a legacy `state.json` without `schemaVersion` is normalized and migrated to v1. Before replacement Harbor saves the original beside it: ```text state.json.backup-v0-2026-07-11T12-00-00-000Z ``` The v1 migration preserves existing fields, adds normalized revision, selection and server fields, and does not rename the volume. Older Harbor builds ignore the additional `schemaVersion` field, but the backup is the safest rollback source. ## Corrupt JSON If `state.json` cannot be parsed, Harbor renames the exact damaged bytes to: ```text state.json.corrupt-2026-07-11T12-00-00-000Z ``` It then creates a valid empty v1 state and reports `storage-recovery` through `snapshot.operation`. A corrupt subscription cache is preserved with the same suffix and reported in control logs. Recovery should be performed while Harbor is stopped: 1. Copy the whole data directory before changing anything. 2. Inspect a backup with `jq . `. 3. Restore only a valid JSON backup to the original filename. 4. Start Harbor and verify `GET /api/state` before applying or importing anything. Generated config rollback also uses the atomic writer. No automatic recovery tries to guess missing subscription credentials or repair semantically invalid sing-box configuration.