A small example of representing an operational decision as explicit, ordered, observable policy.
This is not a rules engine or a framework. It is the smallest thing that shows one idea from the essay
Making Operational Decisions Explainable:
a controller's decision does not have to hide inside a ladder of nested ifs. It can be an ordered list of
named rules that reads like the policy it is, can be evaluated without the system it controls, and can
explain itself.
The decision the way it tends to grow, as control flow:
if state.InMaintenanceWindow() {
return NoAction
}
if state.BackupRunning() {
return Wait
}
if state.BackupExpired() || state.RetentionExceeded() {
if !state.IsLastBackup() {
return DeleteBackup
}
return Wait
}
if state.ScheduleReached() {
return StartBackup
}
return WaitIf the last backup is expired and a backup is scheduled, does it start a new one? You have to trace the returns to know — the expired branch returns first, so no, it waits.
The same policy as an ordered list (policy.go):
var Rules = []Rule{
Case("Do nothing during maintenance").
Matches(State.InMaintenanceWindow).
Execute(NoAction),
Case("Let a running backup finish").
Matches(State.BackupRunning).
Execute(Wait),
Case("Keep the last backup, even if it's due for cleanup").
Matches(And(State.IsLastBackup, Or(State.BackupExpired, State.RetentionExceeded))).
Execute(Wait),
Case("Delete a backup that is expired or over retention").
Matches(Or(State.BackupExpired, State.RetentionExceeded)).
Execute(DeleteBackup),
Case("Start a scheduled backup").
Matches(State.ScheduleReached).
Execute(StartBackup),
}Now the answer is in the list: "Keep the last backup" sits above "Start a scheduled backup". Priority is the order.
- Explicit. The policy is a value you can read in precedence order, not control flow you have to execute in your head.
- Testable.
DetermineNextAction(State) Actionis pure — it reads nothing and changes nothing — so the decision logic is table-testable with no cluster and no clock. Every rule and the precedence between them shows up in the rows ofstrategy_test.go: each a state and the action policy must produce. - Observable. An optional
Observeris handed each decision — the action and the rule that fired — alongside the state whose facts decided it. Most software logs the action; this logs the decision (example_test.go):
decision: DeleteBackup (rule "Delete a backup that is expired or over retention")
facts: maintenance=false running=false expired=true retention=false lastBackup=false scheduleReached=false
No Kubernetes, no framework, no config — this repository shows the representation and nothing else. It's an illustration kept deliberately simple, not production-ready code to depend on: take the idea, not the file. If your reaction is "that's surprisingly small," that's the point: the hard part was never the code. It was deciding where the complexity belongs.
MIT. See LICENSE.