# Harbor state recovery Harbor keeps the existing data paths and volumes. `state.json` now uses `schemaVersion: 4`; subscription cache, generated sing-box config and HWID keep their existing filenames. Schema v2 introduced locally managed domain routing rules. Schema v3 added rule `enabled` state. Schema v4 adds stable server IDs and migrates an unambiguous legacy `selectedTag` to `selectedServerId`. ## 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`, or any v1-v3 state, is normalized and migrated to the current schema. Existing custom rules are preserved. Server identity is derived from protocol, host and port; a unique legacy tag keeps selection, while duplicate or missing matches require a new explicit choice. Before replacement Harbor saves the original beside it: ```text state.json.backup-v0-2026-07-11T12-00-00-000Z ``` The migration preserves compatibility aliases, adds normalized revision, selection and server fields, and does not rename the volume. Subscription cache keeps the raw provider config so older builds can still use its original outbound tags. The backup remains the safest manual recovery 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 current-schema 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.