feat: consolidate Workflow options into WorkflowOption#77
Merged
Conversation
Brainstorming output and openspec change proposing to:
- collapse Workflow's nine top-level configuration fields into a single
Workflow.Option WorkflowOption (scalar pointers, slice prepend)
- replace MutatorReceiver / InterceptorReceiver with a single
WorkflowOptionReceiver { InheritOption(parent WorkflowOption) }
- rename IsolateInterceptors to Option.DontInherit (whole-Option opt-out)
- deprecate flow.SubWorkflow (remove next major); recommend embedding
flow.Workflow directly
- propagate parent Option to sub-workflows in a single Do() prologue pass;
use snapshot/restore to prevent multi-Do() accumulation
Spec deltas update workflow-options, composite-steps, mutators, and
step-interceptor capabilities.
- composite-steps: add MUST-NOT scenario for unguarded Add() inside Do(), enumerating the failure modes and the three required patterns (construction-time / inline-fresh-Workflow / sync.Once); add the multi-Do() embedded scenario and the inline-with-explicit-InheritOption scenario - workflow-options: add Reset requirement spelling out the contract (rewinds per-step status only, never modifies steps or Option; optional from Option-isolation standpoint thanks to Do() snapshot) - tasks.md: add 9.5 (Reset godoc rewrite), 9.6 (Workflow godoc patterns), 9.7 (Add() godoc warning); add Section 11 Future Work for static analyser to catch unguarded Do-time Add (out of scope here, no runtime panic because retry releases x.isRunning between attempts)
Collapses the nine top-level configuration fields on Workflow
(MaxConcurrency, DontPanic, SkipAsError, Clock, DefaultOption, Mutators,
StepInterceptors, AttemptInterceptors, IsolateInterceptors) into a single
named field Workflow.Option of type WorkflowOption. Scalar fields are
now pointer-typed so unset / explicit-zero are distinguishable, enabling
positive parent → child inheritance (e.g. setting DontPanic on the
parent now flows into sub-workflows that left it nil).
A single WorkflowOptionReceiver { InheritOption(parent) (restore func()) }
interface replaces the previous MutatorReceiver and InterceptorReceiver,
with the parent's Do() prologue calling InheritOption once per root
sub-workflow. The returned restore func is deferred by the parent so
child Option mutations do not accumulate across runs, removing the need
for inheritedStep / inheritedAttempt side fields and special-cased
reset() behavior.
Breaking changes:
- &Workflow{Field: ...} literals must move under Option: WorkflowOption{...}
- MutatorReceiver, InterceptorReceiver, Workflow.PrependMutators,
Workflow.PrependInterceptors, findInterceptorReceiver, and
IsolateInterceptors are removed.
- DefaultOption renamed to Option.StepDefaults; IsolateInterceptors
renamed to Option.DontInherit (semantics widened to whole Option).
Deprecations (remove next major):
- flow.SubWorkflow (delegates InheritOption during the deprecation window).
- flow.StepBuilder (type-level deprecation alongside the already-deprecated
BuildStep method and user hook).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Workflow(MaxConcurrency,DontPanic,SkipAsError,Clock,DefaultOption,Mutators,StepInterceptors,AttemptInterceptors,IsolateInterceptors) into a single named fieldWorkflow.Option WorkflowOption. Scalar fields are now pointer-typed so unset / explicit-zero are distinguishable.MutatorReceiver+InterceptorReceiverwith a singleWorkflowOptionReceiver { InheritOption(parent) (restore func()) }. The parent'sDo()prologue callsInheritOptiononce per root sub-workflow and defers the returnedrestoreso child Option mutations do not accumulate across runs (replaces theinheritedStep/inheritedAttemptside fields and special-casedreset()rule).Option.DontPanic(or any other scalar) on the parent now flows into sub-workflows that left it nil. Opt out withOption.DontInherit = true.flow.SubWorkflowandflow.StepBuilder(withBuildStep) — both removed in the next major version. SubWorkflow keeps a delegatingInheritOptionfor the deprecation window.Breaking changes
&Workflow{Field: ...}literals must move underOption: WorkflowOption{...}; scalars wrap as pointers.MutatorReceiver,InterceptorReceiver,Workflow.PrependMutators,Workflow.PrependInterceptors,findInterceptorReceiver,IsolateInterceptors.DefaultOption→Option.StepDefaults;IsolateInterceptors→Option.DontInherit(semantics widened from interceptors-only to whole-Option).Option.DontInherit = trueon the child to keep the previous non-propagating behavior, or restate the desired non-default explicitly.Test plan
🤖 Generated with Claude Code