Save Validation and Recovery
Relevant source files
The following files were used as context for generating this wiki page:The Save Validation and Recovery system is a comprehensive suite of modules designed to ensure the integrity, reliability, and resilience of game save data. It provides a multi-layered defense against data corruption, save/load failures, and file system errors. The system is built around several key managers that handle data validation, error handling, metadata management, and file operations.
This system automatically validates game state before saving, repairs corrupted data on load, manages file integrity via checksums, and implements robust error handling with retry logic and fallback recovery strategies. This ensures a stable and trustworthy persistence layer for the player's progress.
Architecture Overview
The system is composed of several interconnected modules, primarily orchestrated by the AutoSaveManager. Each module has a distinct responsibility, working together to handle the full lifecycle of save and load operations.
The following diagram illustrates the high-level interaction between the main components of the save system.
Key Components
| Component | File | Description |
|---|---|---|
AutoSaveManager | src/auto-save-manager.js | Orchestrates the entire save/load process, managing periodic saves, backups, and coordinating other managers. |
DataValidator | src/data-validator.js | Validates game state against a predefined schema and attempts to repair data. |
SaveErrorHandler | src/save-error-handler.js | Manages errors during save operations, implementing retries, backoff delays, and recovery strategies. |
SaveMetadataManager | src/save-metadata-manager.js | Manages a metadata.json file, tracking save files, checksums, and statistics for integrity checks. |
FileSystemManager | src/filesystem-manager.js | Handles all low-level file I/O, including atomic writes, reads, and disk space validation. |
SaveStateManager | src/renderer/save-manager.js | Acts as the bridge in the renderer process, communicating with the main process via IPC. |
saveManagerUI | app/js/save-manager-ui.js | Manages the Save Manager modal in the UI, allowing users to interact with their saves. |
Sources: src/auto-save-manager.js:10, src/data-validator.js:7, src/save-error-handler.js:8, src/save-metadata-manager.js:7, src/filesystem-manager.js:8, src/renderer/save-manager.js:5, app/js/save-manager-ui.js:5
Data Validation
Sources: src/data-validator.js, src/auto-save-manager.js
Data validation is the first line of defense against corruption. Before any save operation, the AutoSaveManager calls DataValidator.validateGameState() to check the game data.
Schema-Based Validation
Validation is performed against a strict gameStateSchema defined within DataValidator. This schema specifies the expected data types, required fields, and constraints (e.g., min, max) for each part of the game state.
Sources: src/data-validator.js:11-96
A high-level overview of the schema:
| Field | Type | Required | Description |
|---|---|---|---|
version | string | No | The save file version. |
player | object | Yes | Contains player data like money, exp, level. |
script | object | Yes | Contains script progression data. |
server | object | Yes | Contains owned servers. |
battery | object | No | Contains battery state. |
achievements | object | No | List of owned achievements. |
Sources: src/data-validator.js:12-95
Validation and Repair Flow
The validateGameState method performs a recursive validation and repair process. If it finds discrepancies, it attempts to fix them automatically based on default values and constraints defined in the schema.
This diagram shows the flow of the validateGameState function.
Sources: src/data-validator.js:103-151
Key repair actions include:
- Setting missing required fields to their default values.
- Converting data to the correct type (e.g., a number stored as a string).
- Clamping numerical values to their
minandmaxconstraints. - Truncating strings that exceed
maxLength. - Removing duplicate entries from arrays marked as
unique.
Sources: src/data-validator.js:296-488
Loading and Repair
During a load operation, AutoSaveManager also uses DataValidator to ensure the integrity of the loaded data. If validation fails, it calls repairCorruptedData to attempt a more thorough repair before applying the state. If successful, the repaired data is saved back to a new file to prevent future issues.
Sources: src/auto-save-manager.js:501-530, src/data-validator.js:574-635
Save File Integrity
Sources: src/save-metadata-manager.js, src/filesystem-manager.js
To protect against file-level corruption (e.g., incomplete writes), the system uses checksums managed by SaveMetadataManager. This manager maintains a metadata.json file in the save directory.
Metadata and Checksums
For every save file created, SaveMetadataManager.registerSaveFile calculates a SHA-256 checksum of the file's content and stores it in metadata.json along with other metadata like size and timestamps.
// src/save-metadata-manager.js:141-143
calculateChecksum(data) {
return crypto.createHash('sha256').update(data).digest('hex');
}
Sources: src/save-metadata-manager.js:141-143, 370-372
When a file is read, FileSystemManager can request validation from SaveMetadataManager. The validateSaveFileIntegrity function re-calculates the file's current checksum and compares it to the stored one.
Integrity Validation Flow
The following sequence diagram shows how a save file's integrity is verified.
Sources: src/save-metadata-manager.js:148-185
If a checksum mismatch occurs, it indicates the file may be corrupted. The AutoSaveManager's loading logic will then attempt to load the next available save file. If the metadata.json file itself is corrupted (e.g., invalid JSON), it is automatically backed up and reset to a default state.
Sources: src/save-metadata-manager.js:70-72, src/auto-save-manager.js:532-540
Error Handling and Recovery
Sources: src/save-error-handler.js, src/auto-save-manager.js
When a save operation fails, AutoSaveManager delegates the error to SaveErrorHandler, which implements a sophisticated recovery process.
Error Handling Flow
The handleSaveError function is the entry point for all save-related errors. It classifies the error, attempts retries with exponential backoff, and can enter a "degraded mode" if failures persist.
This diagram outlines the error handling logic.
Sources: src/save-error-handler.js:55-80
Recovery Strategies
SaveErrorHandler employs several strategies during the retry attempts, selected based on the error type and retry count.
| Strategy | Description | Trigger |
|---|---|---|
retry_with_backoff | A simple retry after a delay. | Default strategy. |
cleanup_old_files | Triggers backup cleanup to free disk space. | disk_space error. |
use_backup_location | Tries to save to an emergency/ subdirectory. | permission error or as a fallback. |
compress_data | Attempts to save a compressed version of the game state. | disk_space error on retry, or as a fallback. |
fallback_to_localstorage | (Not implemented in main process) Emergency fallback. | As a fallback. |
emergency_memory_save | (Not implemented in main process) Last resort in-memory save. | As a fallback. |
Sources: src/save-error-handler.js:41-47, 281-303
Degraded Mode
If save operations fail consecutively (degradedModeThreshold, default 5), the system enters a "degraded mode". In this state, features like auto-saving may be disabled to prevent further errors and protect existing data. The system will exit degraded mode once a save operation succeeds.
Sources: src/save-error-handler.js:19, 172-192, 197-214
Backup and Restoration
Sources: src/auto-save-manager.js
The AutoSaveManager is responsible for creating and managing backups, which serve as a crucial part of the recovery process.
Backup Creation and Cleanup
- Timestamped Backups: After a successful periodic save, a timestamped backup is created.
- Manual Backups: The user can create manual backups via the UI.
- Cleanup: An automatic process runs daily to clean up old backups based on a retention policy (
backupRetentionDays, default 30) and a total disk usage limit (maxDiskUsage, default 100MB).
Sources: src/auto-save-manager.js:20-23, 245-275, 280-353
Game State Loading and Restoration
The loadGameState function in AutoSaveManager provides a robust process for loading the most recent, valid save file.
The loading process follows a clear priority:
- Find the most recent, non-backup save file.
- Attempt to load and validate it.
- If validation reveals issues, attempt to repair the data.
- If loading or repair fails, move to the next most recent save file.
- If all regular saves fail, attempt to recover from the most recent backup files.
This sequence diagram illustrates the loadGameState logic.
Sources: src/auto-save-manager.js:472-588
Conclusion
The Save Validation and Recovery system in Skid-Inc is a robust, multi-faceted framework designed to maximize data integrity and provide a seamless user experience even in the face of errors. Through a combination of proactive validation, schema-based repair, checksum verification, and reactive error handling with multiple recovery strategies, the system ensures that player progress is protected. The clear separation of concerns among the different managers (DataValidator, SaveErrorHandler, SaveMetadataManager, FileSystemManager, and AutoSaveManager) creates a maintainable and resilient architecture for data persistence.