docs: remove unreachable action == "modify" branch from orchestrator contract - #102
Closed
Michael J. Jabbour (michaeljabbour) wants to merge 1 commit into
Closed
Conversation
…r contract The orchestrator contract told authors to consume hook modifications with `if pre_result.action == "modify"`. That branch can never execute -- `emit()` normalizes the aggregate result to `continue` on every path. Verified against crates/amplifier-core/src/hooks.rs: - no handlers registered (:170-174) -> Continue, with `data` - no matching entries (:180-184) -> Continue, with `data` - normal path (:269-274) -> Continue, with `value_to_map(¤t_data)`, under the comment "Return final result with potentially modified data" `modify` is a handler-to-handler chaining semantic *inside* the dispatch loop; the payload reaches the caller in `data`, never via the action. Replaces the dead branch with the consumption that actually works -- read `data` unconditionally, guarded on it being a dict -- and adds a "Consuming modifications" section explaining why. Also documents the interaction at hooks.rs:249-267, currently written down nowhere: if any handler on the same event returns `inject_context` or `ask_user`, that handler's result is returned instead of the accumulated payload, so an earlier handler's modification is silently discarded, and on the approval path the returned result carries no `data` at all. Docs-only. No code or behavior change. 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Contributor
Author
|
Withdrawing this. It was pushed as a branch directly into this repo; it should Docs-only and conflicts with nothing, but withdrawing for consistency with the |
Michael J. Jabbour (michaeljabbour)
deleted the
docs/modify-action-is-normalized-away
branch
August 20, 2026 10:31
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
docs/contracts/ORCHESTRATOR_CONTRACT.mdtold orchestrator authors to consume a hook modification withif pre_result.action == "modify". That branch can never execute —emit()normalizes the aggregate result tocontinueon every path.dataunconditionally, guarded on it being a dict) and adds a Consuming modifications section explaining why.inject_contextorask_userresult from any handler on the same event is returned instead of the accumulated payload, so an earlier handler's modification is silently discarded.Filed as the fix rather than an issue because issues are disabled on this repo.
The verification
Checked directly against
crates/amplifier-core/src/hooks.rsat92b339a:hooks.rs:170-174HookAction::Continue,data: Some(value_to_map(&data))hooks.rs:180-184HookAction::Continue,data: Some(value_to_map(&data))hooks.rs:269-274HookAction::Continue,data: Some(value_to_map(¤t_data))— under the comment "Return final result with potentially modified data"modifyis a handler-to-handler chaining semantic inside the dispatch loop: each handler returningmodifyupdates the payload passed to the next one. The aggregate result handed back to a caller is alwayscontinue, with the possibly-modified payload indata.The
inject_context/ask_userinteraction is athooks.rs:249-267, wherespecial_resultshort-circuits the return — so an earlier handler's modification never reaches the caller, and on the approval path the returned result carries nodataat all.Why it matters
An orchestrator following the documented pattern contains a branch that never fires, and every handler that rewrites event data becomes a silent no-op: the handler runs, returns its correction, and the original data is used anyway — with no error and no log.
This is not hypothetical:
amplifier-module-loop-streaminghad exactly this bug at bothtool:predispatch sites. Fixed in fix: always emit execution:end, honor tool:pre rewrites, and break identical failure loops amplifier-module-loop-streaming#41 (commitd4ce28b) by readingdataunconditionally.tool:posthandling shows the author hit the wall too: it detects modification by object identity, with a comment explaining thatactioncould not be checked. That workaround is itself unreliable — the kernel round-trips the payload throughserde_json::Value, so the returned dict is always a fresh object.action="modify"anywhere — which is what you would expect of a documented capability nobody can successfully use.Scope and risk
Docs-only. No code, no behavior change — the only file touched is
docs/contracts/ORCHESTRATOR_CONTRACT.md(+30 / −4). The risk is therefore confined to the documentation being wrong in the other direction, and the kernel citations above are there to check it against.Because nothing shipped in the wheel changed, no version bump or E2E smoke test was run —
docs/CORE_DEVELOPMENT_PRINCIPLES.md§10 scopes the release gate to "code shipped in the wheel". Flagging that reading explicitly so a maintainer can confirm it rather than have it silently omitted.Test plan
crates/amplifier-core/src/hooks.rsat all threeHookAction::Continuereturn sites and thespecial_resultshort-circuit, cited above.Suggested follow-up (not part of this change)
amplifier-coreasserts this today, which is why two dispatch sites in a shipped orchestrator could ignore it indefinitely.Generated with Amplifier