Repository navigation
fix(core): process and validate inputs before pre_run_step in astep (#979) - #995
legend91019 wants to merge 2 commits into
Conversation
xihaian251
left a comment
There was a problem hiding this comment.
Thanks — processing and validating the inputs before pre_run_step is the right direction, and the async path now behaves correctly. The new tests cover both symptoms described in #979.
There is one remaining problem in the synchronous-action path. _astep now processes the inputs before the hooks, but the sync branch still delegates with
output = self._step(inputs=inputs, _run_hooks=False)and _step calls _process_inputs again on those same inputs. When the action declares a generated dependency (__context or __tracer), the factory therefore runs twice, and the object the hook sees is not the object the action receives.
Reproduction on 3ff45707, with an action that declares __context and a factory that returns a fresh object() on every call. Identical results on Python 3.12.14 and 3.13.14:
astep(), sync action : 2 factory calls
AssertionError: __context factory ran 2 times, expected once
assert <object object at 0x...2860> is <object object at 0x...39B0> # hook vs action
astep(), async action : 1 factory call, hook and action share the object
step(), sync action : 1 factory call, hook and action share the object
So only the sync branch through astep() is affected; the async branch and step() already behave correctly.
#979 lists this as expected behaviour:
The same processed input dictionary should be used by both the hook and the action.
I read this as the last piece of the issue rather than a new concern.
Same root cause, one more data point: astream_result halting on a non-streaming action now processes the inputs three times (it was two on main), because _astep processes them even when _run_hooks=False and _step then processes them again. That is a separate call site and fixing it is not required for #979, but the count does go up with this change.
PR #980 handles the duplicate by threading the already-processed dict into _step through a _processed_inputs parameter. Note that simply passing action_inputs into inputs= does not work: _process_inputs rejects any key starting with __, so feeding it its own output raises ValueError: Inputs starting with a double underscore ... are reserved. Reusing the processed inputs on this branch would be the equivalent fix.
Happy to share the focused regression test — it is one parametrised test covering step(), astep() with a sync action and astep() with an async action, asserting a single factory call plus object identity between the hook and the action. I can open it against your branch or paste it here, whichever you prefer.
Disclosure: this verification was produced with AI assistance against the pinned commit above. Every number comes from a reproducible local pytest run; happy to provide the test file and exact commands.
_astep() processed the inputs before pre_run_step, but the sync branch still delegated with _step(inputs=inputs), so _process_inputs ran a second time. For an action declaring __context or __tracer the factory therefore ran twice and the object seen by the hook was not the object the action received. Thread the already-processed dict into _step through a _processed_inputs parameter, matching the approach in apache#980. Passing action_inputs back through inputs= is not an option, since _process_inputs rejects keys starting with __. Adds a parametrised regression test over step(), astep() with a sync action and astep() with an async action, asserting a single factory call and object identity between the hook and the action.
|
Thanks @xihaian251 — the sync branch is fixed in Fix. output = self._step(
inputs=inputs,
_run_hooks=False,
_processed_inputs=action_inputs,
)Same shape as #980. Your note about feeding Regression test. Added Negative control, test unchanged, only the production change reverted (Python 3.14.6, Windows): That is the same two-case split you reported.
I left Runs. Happy to take your focused test as well if it covers a case mine misses — otherwise I think this one pins the behaviour you reproduced. |
|
Thanks for the quick follow-up and for incorporating the feedback. |
|
Hi @xihaian251 — thanks again for the careful review and for confirming that the Since that was the last open item, would you be able to approve so this can land? Happy to address anything else you'd like to see before merge. @skrawcz — this one is ready for a maintainer merge whenever convenient: CI green, MERGEABLE, reviewer has signed off on the mechanism and the parametrised regression test. |
xihaian251
left a comment
There was a problem hiding this comment.
Reviewed the updated head 7a58bba.
The _processed_inputs handoff correctly prevents duplicate input processing in the synchronous-action path of astep(). The parametrized regression test covers step(), astep() with a synchronous action, and astep() with an asynchronous action, verifying both single factory invocation and object identity between the hook and action.
I have no remaining code-level concerns and approve this change.
One CI note: please ensure the full required test workflows have completed before merging. The latest checks visible to me still show Build Burr and Release Validation as action_required, while the documentation workflow reports startup_failure.
|
Cross-checking #995 against #1019, which also touches Overlap with #980 Overlap with #1019 Scope Suggested sequencing, if maintainers agree One gap either way CI |
Summary
Fixes #979.
Application.step()processes inputs before callingpre_run_step, butApplication.astep()previously passed the raw input dictionary to the hook before processing and validation. As a result, the hook could receive undeclared inputs or run before a missing required input was rejected.This change processes inputs before the async pre-step hook and passes the resulting
action_inputsto it, for both synchronous and asynchronous actions executed throughastep().Changes
burr/core/application.py: call_process_inputs(inputs, next_action)beforepre_run_stepin_astep()and reuse the processed inputs for async execution.tests/core/test_application.py: cover filtering undeclared inputs and rejecting missing required inputs before the hook runs, for sync and async actions.Verification
Implementation verification previously recorded for this branch:
tests/core/test_application.py: 144 tests passed.tests/core: 432 tests passed.This description-only update repairs Markdown escaping and corrupted identifiers. It does not change the branch or claim a new test run.