Skip to content

feat: consolidate Workflow options into WorkflowOption#77

Merged
xuxife merged 7 commits into
mainfrom
xuxife/26/05/12/design-workflow-option
May 13, 2026
Merged

feat: consolidate Workflow options into WorkflowOption#77
xuxife merged 7 commits into
mainfrom
xuxife/26/05/12/design-workflow-option

Conversation

@xuxife
Copy link
Copy Markdown
Collaborator

@xuxife xuxife commented May 13, 2026

Summary

  • Collapse the nine top-level configuration fields on Workflow (MaxConcurrency, DontPanic, SkipAsError, Clock, DefaultOption, Mutators, StepInterceptors, AttemptInterceptors, IsolateInterceptors) into a single named field Workflow.Option WorkflowOption. Scalar fields are now pointer-typed so unset / explicit-zero are distinguishable.
  • Replace MutatorReceiver + InterceptorReceiver with a single WorkflowOptionReceiver { InheritOption(parent) (restore func()) }. The parent's Do() prologue calls InheritOption once per root sub-workflow and defers the returned restore so child Option mutations do not accumulate across runs (replaces the inheritedStep / inheritedAttempt side fields and special-cased reset() rule).
  • Positive parent → child propagation: setting Option.DontPanic (or any other scalar) on the parent now flows into sub-workflows that left it nil. Opt out with Option.DontInherit = true.
  • Deprecate flow.SubWorkflow and flow.StepBuilder (with BuildStep) — both removed in the next major version. SubWorkflow keeps a delegating InheritOption for the deprecation window.

Breaking changes

  • &Workflow{Field: ...} literals must move under Option: WorkflowOption{...}; scalars wrap as pointers.
  • Removed: MutatorReceiver, InterceptorReceiver, Workflow.PrependMutators, Workflow.PrependInterceptors, findInterceptorReceiver, IsolateInterceptors.
  • Renamed: DefaultOptionOption.StepDefaults; IsolateInterceptorsOption.DontInherit (semantics widened from interceptors-only to whole-Option).
  • Behavior change: scalar Option fields now propagate from parent into sub-workflows that left them nil. Set Option.DontInherit = true on the child to keep the previous non-propagating behavior, or restate the desired non-default explicitly.

Test plan

  • `go build ./...` clean
  • `go vet ./...` clean
  • `go test ./...` passes (main package + example package)
  • New `workflow_option_inherit_test.go` covers the full matrix (scalar nil/set/explicit-zero, slice prepend × all three slice fields, `DontInherit`, multi-level nesting, `Do()` snapshot/restore, scalar-inheritance `DontPanic` motivating case, zero-Workflow no-regression, SubWorkflow deprecation smoke).
  • All existing tests migrated to `Option: WorkflowOption{...}` form.
  • OpenSpec change applied to live specs and archived under `openspec/changes/archive/2026-05-12-workflow-option/`.

🤖 Generated with Claude Code

Xingfei Xu and others added 7 commits May 12, 2026 13:42
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>
Copy link
Copy Markdown

@XiangyuKuangMSFT XiangyuKuangMSFT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@xuxife xuxife added this pull request to the merge queue May 13, 2026
Merged via the queue into main with commit fca6b68 May 13, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants