1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//! PROMPT.md permission lifecycle tracking.
//!
//! This state tracks the permission protection lifecycle for PROMPT.md:
//! - Locked at pipeline start (best-effort read-only)
//! - Restored on all graceful termination paths (success and failure)
//!
//! # Cleanup Guarantees
//!
//! Multiple safety layers ensure PROMPT.md is restored to writable state:
//!
//! 1. **Reducer-driven (normal path)**: `Effect::RestorePromptPermissions` during
//! Finalizing phase or on interrupt (Ctrl+C or programmatic). Note: On interrupt,
//! restoration is attempted unconditionally regardless of `restore_needed` state,
//! since prior crashed runs may have left PROMPT.md read-only.
//!
//! 2. **RAII guard (panic/early return)**: `AgentPhaseGuard::drop()` restores
//! permissions even when the reducer event loop doesn't complete.
//!
//! 3. **Startup cleanup (SIGKILL/crash)**: On next Ralph run, startup code
//! restores PROMPT.md permissions from prior crashed runs.
//!
//! Note: SIGKILL and power loss cannot be intercepted; recovery happens on
//! next startup.
use ;
/// Tracks PROMPT.md permission lifecycle for reducer-driven protection.
///
/// # State Transitions
///
/// 1. **Startup**: `locked=false, restore_needed=false, restored=false`
/// 2. **After `LockPromptPermissions` effect**: `locked=true, restore_needed=true`
/// 3. **After `RestorePromptPermissions` effect**: `locked=false, restore_needed=false, restored=true`
///
/// # Resume Safety
///
/// All fields are checkpointed. On resume:
/// - If locked but not restored, orchestration will derive `RestorePromptPermissions`
/// - If already restored, no further action needed
///
/// This state is serialized in `PipelineCheckpoint.prompt_permissions` to ensure
/// pending restores are honored after resume.