Problem
Controllers whose reconcile is an ordered sequence (resolve, claim, record, apply, verify) need each step to name itself when it fails, so the owner condition can say which step stopped the pass and the steps after it never run. ocf has nothing for this, so consumers invent it.
konsole-is/camunda-operator has two shapes side by side. internal/controller/camundacluster/precheck.go runs a literal slice of functions in order, first error wins, and the failure loses the name of the step that raised it. The management cluster controller solved the same problem with a named vocabulary in internal/controller/camundamanagementcluster/step.go: a step string type with thirteen named steps, a stepError wrapper, wrap/wrapAs helpers, a stop sentinel, firstStep ordering, and a condition rule that turns the failed step into the owner condition reason. Two in-flight PRs (konsole-is/camunda-operator#317 and konsole-is/camunda-operator#321) each extended this machinery with new steps, and the machinery itself is byte-identical between them. It contains zero domain knowledge.
Deliberately out of scope: resumable phase machines that persist a phase cursor in status and advance one phase per reconcile (the backup and restore controllers). The same audit found the consumer already factored their reusable half into its own pkg/restore, and what remains (what a phase means, what survives a crash, when a claim releases) is domain specific. This issue proposes only the step naming half.
Approach
A small step package: a Step name type, an error wrapper carrying the step, Wrap(step, err) and WrapAs(step, reason, err), a Stop sentinel for ending a pass without an error, First(err) extraction, and a helper that maps a wrapped error to a condition reason such as StepFailed with the step name in the message. The consumer declares its step names and calls its functions in order; the package owns the wrapping and the condition mapping.
Verification
- The management cluster
step.go in konsole-is/camunda-operator can be deleted and its call sites ported with identical condition output.
- The camundacluster pre-check slice can adopt step names without restructuring its functions.
- A test covers: a wrapped error surfaces the first step,
Stop ends the pass without staging a failure, and a double wrap keeps the innermost step.
Context
Found while auditing konsole-is/camunda-operator for repeated hand-rolled patterns. The duplication is active: both current in-flight PRs in that repository grew this machinery independently in the same week.
Problem
Controllers whose reconcile is an ordered sequence (resolve, claim, record, apply, verify) need each step to name itself when it fails, so the owner condition can say which step stopped the pass and the steps after it never run. ocf has nothing for this, so consumers invent it.
konsole-is/camunda-operator has two shapes side by side.
internal/controller/camundacluster/precheck.goruns a literal slice of functions in order, first error wins, and the failure loses the name of the step that raised it. The management cluster controller solved the same problem with a named vocabulary ininternal/controller/camundamanagementcluster/step.go: astepstring type with thirteen named steps, astepErrorwrapper,wrap/wrapAshelpers, astopsentinel,firstStepordering, and aconditionrule that turns the failed step into the owner condition reason. Two in-flight PRs (konsole-is/camunda-operator#317 and konsole-is/camunda-operator#321) each extended this machinery with new steps, and the machinery itself is byte-identical between them. It contains zero domain knowledge.Deliberately out of scope: resumable phase machines that persist a phase cursor in status and advance one phase per reconcile (the backup and restore controllers). The same audit found the consumer already factored their reusable half into its own
pkg/restore, and what remains (what a phase means, what survives a crash, when a claim releases) is domain specific. This issue proposes only the step naming half.Approach
A small
steppackage: aStepname type, an error wrapper carrying the step,Wrap(step, err)andWrapAs(step, reason, err), aStopsentinel for ending a pass without an error,First(err)extraction, and a helper that maps a wrapped error to a condition reason such asStepFailedwith the step name in the message. The consumer declares its step names and calls its functions in order; the package owns the wrapping and the condition mapping.Verification
step.goin konsole-is/camunda-operator can be deleted and its call sites ported with identical condition output.Stopends the pass without staging a failure, and a double wrap keeps the innermost step.Context
Found while auditing konsole-is/camunda-operator for repeated hand-rolled patterns. The duplication is active: both current in-flight PRs in that repository grew this machinery independently in the same week.