Uh oh!
There was an error while loading. Please reload this page.
refactor(engine): remove dead workflow lifecycle hooks (#476) - #480
Conversation
The hooks: block (on_start/on_complete/on_error) was parsed and its templates rendered, but the result was always discarded, making the feature entirely unobservable. Remove HooksConfig, WorkflowDef.hooks, the engine's _execute_hook/LifecycleHookResult and all call sites, and the Hooks section of the workflow syntax docs. A workflow declaring hooks: now fails validation with a clear error.
…le-hooks # Conflicts: # CHANGELOG.md
@microsoft-github-policy-service agree |
Jason Robert (jrob5756)
left a comment
There was a problem hiding this comment.
Two blocking issues here, both real: a mangled comment that undoes the readability this refactor was supposed to deliver, and a bundled skill that still teaches agents to write a hooks: block that now hard-fails validation. Once those are fixed this is fine to merge — the three recommended items are cleanup, not blockers.
Blocking:
src/conductor/engine/workflow.py:5343— duplicated lines and a broken sentence in theexcept BaseExceptioncomment (see inline).- No single line — the
conductorskill (SKILL.md,authoring.md,yaml-schema.md) still documentshooks:, and a workflow using it now fails to load instead of just silently no-opping like before this PR.
b2 — BLOCKING: the bundled conductor skill still teaches agents to write hooks:, which now hard-fails validation
docs/workflow-syntax.md got cleaned up, but the skill that ships with the wheel didn't. plugins/conductor/skills/conductor/skills/conductor/SKILL.md:111, references/authoring.md:51-54, and references/yaml-schema.md:133-138 all still document the removed hooks: block — and this is the file skills/registry.py loads whenever a workflow declares skills: [conductor].
This is worse than typical doc drift because of how the removal was implemented. WorkflowDef uses extra="forbid", so hooks: doesn't degrade to a no-op anymore — it aborts the load. I confirmed it: a workflow with workflow.hooks: fails conductor validate with exit code 1 and workflow.hooks: Extra inputs are not permitted. So an agent following this skill will generate a workflow that can't run at all. Before this PR, the same generated YAML at least executed.
I checked that these are genuinely the removed workflow-level feature and not the unrelated plugin hooks/ directories (plugins/manifest.py, config/validator.py, README.md:229, examples/plugins.yaml:39 are correctly untouched) — these three references are specifically workflow:-scoped hooks: keys with on_start/on_complete/on_error children.
Worth flagging as a process gap too: docs/workflow-syntax.md and these skill references are near-duplicate YAML references, and only the first got updated here. That's exactly how this slipped through, and it'll happen again on the next syntax change unless there's a check for it. A grep -rn 'hooks:' plugins/ docs/ examples/ before merge would have caught it.
Suggested fix: Delete the table row at SKILL.md:111; delete lines 51-54 of authoring.md (and the blank line that's now orphaned); delete lines 133-138 of yaml-schema.md including the # Lifecycle hooks comment, leaving one blank line between the cost: block and the # Arbitrary metadata for downstream tooling comment.
r1 — RECOMMENDED: stale "on_error hooks" prose survives in three places the sweep missed
The parallel wording got scrubbed correctly at engine/workflow.py:2109, engine/workflow.py:2136, and docs/workflow-syntax.md:1158, but three mirrors of the same sentences didn't:
src/conductor/exceptions.py:664— theSubworkflowTerminatedErrordocstring still says the attributes are carried "...so on_error hooks, debugging surfaces, and the CLI can inspect it without walking__cause__." This one's worth more attention than a normal stale comment, since it's the stated reasonterminated_output/terminated_reason/terminated_bylive on the exception at all. Point at a consumer that no longer exists and someone will eventually read this as dead code and strip real diagnostic payload off a sub-workflow failure.AGENTS.md:216— the Terminate steps bullet still says "; runson_completehook" and ", runson_errorhook." This file gets loaded into agent context on basically every task in this repo, so the stale claim has wide reach.plugins/conductor/skills/conductor/references/authoring.md:657, 658, 660— "Runs theon_completehook.", "Runs theon_errorhook.", and "...foron_errorhooks and debugging surfaces." Line 660 is the exact sentence already fixed atdocs/workflow-syntax.md:1158— just not here.
All three describe behavior that doesn't happen anymore.
Suggested fix: Match the wording already used in docs/workflow-syntax.md:1158. In exceptions.py:664: "the wrapper so debugging surfaces and the CLI can inspect it without walking __cause__." In AGENTS.md:216: drop "; runs on_complete hook" and ", runs on_error hook". In authoring.md: drop the "Runs the ... hook." sentences at 657 and 658, and on 660 change "for on_error hooks and debugging surfaces" to "for debugging surfaces".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@## main #480 +/- ##
=======================================
Coverage ? 91.77% =======================================
Files ? 146 Lines ? 23844 Branches ? 0 =======================================
Hits ? 21882 Misses ? 1962 Partials ? 0 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
- Fix garbled except BaseException comment left by the removal, restoring the microsoft#116 rationale and documenting the is_base_exception flag. - Remove hooks: from the bundled conductor skill (SKILL.md, authoring.md, yaml-schema.md) so agents no longer generate workflows that hard-fail. - Scrub remaining stale 'on_error/on_complete hooks' prose in exceptions.py, AGENTS.md, authoring.md, and a test docstring. - Add a WorkflowDef model validator giving a targeted microsoft#476 error naming the removal and the workflow_completed/workflow_failed replacement, instead of the generic extra_forbidden message. - Rework/extend tests: schema, loader (YAML), and CLI (conductor validate) now assert the removal message; add invalid_hooks.yaml fixture. - Fix CHANGELOG spacing.
Thanks for the thorough review — all five items addressed in 73e3b9d. Blocking: B1 (garbled except BaseException comment) — restored the comment using your suggested text, including the is_base_exception paragraph documenting what the flag is for. The duplicated lines and cut-off clause are gone; no executable lines were touched. Recommended: R1 (stale "on_error hooks" prose) — reworded exceptions.py (the SubworkflowTerminatedError docstring), AGENTS.md:216, and authoring.md:657-660 to match the wording already used in docs/workflow-syntax.md. I also found and fixed one more the sweep missed: a docstring in tests/test_engine/test_subworkflow.py. On the process gap: agreed a grep -rn 'hooks:' plugins/ docs/ examples/ would've caught B2. I ran that sweep this round and it's clean apart from the intended references (the validator message and the CHANGELOG entry). |
CI note: the one failing check (Test (Python 3.13, ubuntu-latest)) is a flaky Fleet TUI test, not a regression from this PR. It failed on tests/test_fleet/test_tui_runs.py::TestRunsScreenPausesWhileNotOnTop::test_the_animation_timer_is_paused_and_resumed — a timing assertion on the splash animation timer. An earlier run of this same branch failed instead on a different set of Fleet TUI tests (test_tui_theme.py::TestShortenHome and test_tui_actions.py::TestDirectoryPickerModal, on the Windows job). Different platform, different tests, all under tests/test_fleet/ — the inconsistency across runs points to pre-existing flakiness/platform-fragility in the Fleet TUI suite rather than anything this change introduced. For reference, this PR's changes (git diff --name-only upstream/main...HEAD) don't touch fleet/ or tui/ at all — they're limited to config/schema, engine, exceptions, the bundled conductor skill docs, and the corresponding tests. Every test this PR adds or modifies passes on all jobs. A re-run of the failed job should likely go green; happy to open a separate issue for the flaky Fleet tests if that's useful. |
Jason Robert (jrob5756)
left a comment
There was a problem hiding this comment.
LGTM, thanks for contributing!
6cdbabb
into
microsoft:mainUh oh!
There was an error while loading. Please reload this page.
Thank you! I’m really interested in contributing more to the project. How can I connect with you to collaborate on issues and work on such repositories? I’d love to learn from the community and contribute more. Looking forward to hearing from you! |
Closes#476.
What
The
hooks:block (on_start/on_complete/on_error) was documented and parsed, but the feature was dead code: hook templates were rendered and the result discarded. Nothing observed it — no event, no log entry, no dashboard/console output, no context write, no side effect — so a hook was completely unobservable, including when it failed.Changes
HooksConfigandWorkflowDef.hooksfromconfig/schema.py, and the re-exports fromconfig/__init__.py._execute_hook,LifecycleHookResult, and all call sites fromengine/workflow.py, plus now-stale docstring references.docs/workflow-syntax.md.tests/fixtures/valid_full.yaml); addedTestHooksRemovedasserting a workflow declaringhooks:now fails validation with a clear error.Acceptance criteria
hooks:removed from the schema — declaring it produces a clear validation error (extra_forbidden)._execute_hook/LifecycleHookResultand all call sites removed from the engine.docs/workflow-syntax.md.Notes
If lifecycle hooks are wanted later, the right syntax should be designed against a concrete requirement (emitting an event, invoking a
type: scriptstep, or calling a webhook) rather than restoring a placeholder that renders a template and throws it away.Because
hooks:was documented and previously parsed (silently doing nothing), this is technically a breaking change for any workflow that declares it — those will now fail validation, which is the intended behavior per the issue.Verified locally:
ruff check/formatclean, affected test suites green. The remainingtydiagnostics are pre-existing Windows-only platform issues (termios/signal.SIGKILL/etc.) present on a clean checkout, unrelated to this change.