Problem
The reload loop (bootstrap.rs) and supervisor config flow (supervisor.rs) track state implicitly through mutable locals and control flow. This makes them:
- Hard to reason about (5 mutable vars in a 300-line tokio::select loop)
- Not individually testable without standing up the full runtime
- Misaligned with the TLA+ spec which uses explicit states
The test module already contains the correct state machine model (SupervisorState enum + transition()) — but it only exists in tests, not production code.
Proposed Solution
Lift implicit state into explicit, pure state machines:
Phase 1: ValidatedConfig wrapper type
Parse-don't-validate pattern — eliminates triple config validation across the pipeline.
Phase 2: Supervisor ConfigFlowMachine
Lift the test-only state machine to production. handle_remote_config() becomes a thin effect executor driven by a pure transition() function.
States: Idle → Reading → Validating → Writing → Signaling → Done/Failed
Phase 3: ReloadCoordinator state machine
Extract the reload loop state into:
States: Starting → Running ⇄ Draining → Validating → Building → Running | ShuttingDown
The 300-line tokio::select! loop becomes a ~100-line async driver calling coordinator.transition(event) and executing returned effects.
Phase 4+5: Cleanup
- Replace blocking
std::fs I/O in async OpAMP handler with tokio::fs
- Extract diagnostics server setup from inside the reload loop
Benefits
- State transitions individually testable (no full runtime needed)
- Code structure mirrors TLA+ spec (same states, same transitions)
- Proptest/Kani can verify state machine properties directly
- Easier for contributors to understand "what states can this be in?"
PR Strategy
- PR A: ValidatedConfig (small, mechanical)
- PR B: Supervisor ConfigFlowMachine (medium, lifts test model)
- PR C: ReloadCoordinator (large, restructures bootstrap.rs)
- PR D: Cleanup (small)
Relates to #2744
Problem
The reload loop (
bootstrap.rs) and supervisor config flow (supervisor.rs) track state implicitly through mutable locals and control flow. This makes them:The test module already contains the correct state machine model (
SupervisorStateenum +transition()) — but it only exists in tests, not production code.Proposed Solution
Lift implicit state into explicit, pure state machines:
Phase 1:
ValidatedConfigwrapper typeParse-don't-validate pattern — eliminates triple config validation across the pipeline.
Phase 2: Supervisor
ConfigFlowMachineLift the test-only state machine to production.
handle_remote_config()becomes a thin effect executor driven by a puretransition()function.States:
Idle → Reading → Validating → Writing → Signaling → Done/FailedPhase 3:
ReloadCoordinatorstate machineExtract the reload loop state into:
States:
Starting → Running ⇄ Draining → Validating → Building → Running | ShuttingDownThe 300-line
tokio::select!loop becomes a ~100-line async driver callingcoordinator.transition(event)and executing returned effects.Phase 4+5: Cleanup
std::fsI/O in async OpAMP handler withtokio::fsBenefits
PR Strategy
Relates to #2744