mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-06 02:48:25 +00:00
Adversarial review surfaced that both RunArchived and RunUnarchived apply arms were naive — any out-of-spec event in the log (concurrent double archive, tampered import, replayed retry) would permanently corrupt the projection: - RunArchived unconditionally captured current status into prior_status. A second RunArchived would set prior_status=Some(Archived). Unarchive would then emit restored_status=Archived, the apply arm would set status=Archived and clear prior_status, and the run would be unrecoverable. - RunUnarchived trusted restored_status unconditionally. An imported event with restored_status=Running produced a projection reporting status=Running with no RunRunning event in the log — breaking is_active/is_terminal invariants. Both arms now require a sensible pre-state before mutating: - RunArchived only transitions from Succeeded|Failed|Dead. - RunUnarchived only runs from Archived with a terminal restored_status. Adds three regression tests: - double_archive_preserves_prior_status - run_unarchived_with_non_terminal_restored_status_is_ignored - run_archived_on_non_terminal_projection_is_ignored The operations layer (archive/unarchive in fabro-workflow) still validates at emit time; the projection guards are a defensive second line for replay, imports, and any future code path that double-writes. |
||
|---|---|---|
| .. | ||
| src | ||
| Cargo.toml | ||