# Rollback policy simulation This C++17 standard-library example accompanies [chapter 07](../../../docs/07-rollback-and-recovery.md), [ADR-020](../../../adr/ADR-020-define-rollback-eligibility-and-retention.md), [ADR-021](../../../adr/ADR-021-preserve-data-compatibility-during-trial.md), and [ADR-022](../../../adr/ADR-022-bound-recovery-and-block-failed-system-releases.md). It models recovery decisions after B fails, including data compatibility, bounded attempts, and a persistent failed-release block. Build with CMake 3.20 or later and a C++17 compiler from the repository root. No third-party libraries are needed: ```sh cmake -S examples/simulations/rollback-policy -B /tmp/ota-rollback-build -DCMAKE_BUILD_TYPE=Debug cmake --build /tmp/ota-rollback-build /tmp/ota-rollback-build/rollback-simulate all /tmp/ota-rollback-build/rollback-simulate backup-restore ctest --test-dir /tmp/ota-rollback-build --output-on-failure ``` No argument also runs all scenarios. `--help` lists their names. Invalid arguments return a nonzero status. ## Scenarios | Scenario | Expected result | |---|---| | `success` | Compatible data; A passes checks; recovery succeeds. | | `incompatible-data` | A cannot read schema 2; no approved restore; stop without changing data or booting A. | | `backup-restore` | Approved schema-1 backup replaces schema-2 data; A passes; two live record IDs are lost. | | `restart-during-recovery` | Reset before A completes checks; another boot consumes the remaining attempt and passes. | | `recovery-failure` | A explicitly fails local checks; enter separate recovery immediately. | | `blocked-release` | After recovery and reset, rediscovering system-2 leaves it blocked. | | `attempts-exhausted` | Two A boots fail to reach completed checks; no third boot is allowed. | | `window-closed` | Retained A is outside the promised rollback window; do not select it. | | `target-unavailable` | Supplied target eligibility fails; do not select A. | The backup scenarios explore an alternative to ADR-021's compatible shared-data trial policy. They are not permission for incompatible writes during that reference design's trial. A real early-boot failure would need a recovery environment able to restore data before A uses it. ## State and Ownership `Storage` represents saved boot-control and supervisor records plus data. It survives reconstruction of `Coordinator`; nothing is persisted to real files. The normal path is: ```text Idle -> Assess -> [RestoreData] -> SelectPrevious -> CheckPrevious -> Recovered | | | | +-----------+----------------+-----------------+--> SeparateRecovery ``` `start()` saves the failure reason, exact release block, and recovery intent before taking action. Calling it again is rejected. Resume the saved phase instead. During recovery, automatic offers are excluded. `can_offer()` checks only that exclusion and the local failed-release block; it does not implement signature, hardware, or full admission policy. The modeled boot-control transition saves an attempt before handoff to A. Creating another coordinator does not consume or refresh attempts. `after_reset()` represents an actual device reset: an A boot that had not completed checks must go through another accounted handoff. After the illustrative budget of two boots is exhausted, the result is separate recovery. An explicit failed check stops sooner. Data consists of a schema number and unique record IDs. A accepts schema 1. Backup validity and restore permission are supplied inputs; the model counts live IDs missing from the restored copy. A completed restore is not repeated on restart. Terminal recovery does not restore the backup over later records. `running` records the last modeled handoff. At separate recovery it is diagnostic history, not evidence that a system is healthy or that a rescue environment started. Pending results and blocks are retained; no network transport or block-removal API is implemented. ## Checks and Limits [tests.cpp](tests.cpp) checks all scenario outcomes, reset boundaries before and after restore and boot, data-loss accounting, block retention, exclusion of competing offers, finite attempt consumption, check-before-success ordering, invalid or unauthorized backups, and changes in eligibility before an action. The checks use exceptions and remain enabled in Release builds. Each transition is assumed to complete durably. Data replacement and its phase change form one assumed operation here. The example does not test a crash inside a restore or between separate real boot-control and journal writes. Real implementations need their own reconciliation rules, atomic data selection or restartable restore procedure, and platform failure injection. The model supplies eligibility and health outcomes. It does not validate actual artifacts, implement signatures or security anti-rollback, interpret a real schema, run a watchdog, measure deadlines, invoke a package manager, or enter a rescue system. A closed window and an unavailable target are policy inputs rather than a retention implementation. There are no concurrent writers. The block covers one failed update on one device. The [trial boot simulation](../ab-trial-boot/readme.md) covers boot mechanics; the [interrupted installation model](../interrupted-installation/readme.md) covers preparation and activation. The three programs are independent, not an integrated updater. ## Sources and Diagrams - [simulation.hpp](simulation.hpp) and [simulation.cpp](simulation.cpp): saved state, policy transitions, and scenarios. - [main.cpp](main.cpp): scenario runner. - [tests.cpp](tests.cpp) and [CMakeLists.txt](CMakeLists.txt): invariants and CTest integration. - Rollback policy: [PlantUML](../../../diagrams/plantuml/rollback-policy.puml), [PNG](../../../diagrams/rendered/rollback-policy.png). - Recovery sequence: [PlantUML](../../../diagrams/plantuml/rollback-recovery-sequence.puml), [PNG](../../../diagrams/rendered/rollback-recovery-sequence.png). - Rollback window: [PlantUML](../../../diagrams/plantuml/rollback-window.puml), [PNG](../../../diagrams/rendered/rollback-window.png). Format C++ sources with the repository's root `.clang-format`. Diagrams include editable PlantUML sources and PNG previews.