Share parallel-roles/map spec validation across sync and async paths - #485
Draft
lezama wants to merge 1 commit into
Draft
Share parallel-roles/map spec validation across sync and async paths#485lezama wants to merge 1 commit into
lezama wants to merge 1 commit into
Conversation
…ync paths The SYNC in-process loops (`run_parallel_roles()` / `run_parallel_map()`) and the ASYNC dispatch-plan builders (`build_roles_dispatch_plan()` / `build_map_dispatch_plan()`) independently re-implemented the SAME parallel spec validation. Because the two copies were maintained by hand, they could silently DRIFT — a rule tightened on one path but not the other would make the substrate accept a spec synchronously that it rejects asynchronously (or vice versa), a hard-to-diagnose correctness gap. Extract two shared private helpers — `validate_parallel_roles_spec()` and `validate_parallel_map_spec()` — that enforce the rules once (roles: entries-are-arrays / non-empty branches / at-most-one aggregator; map: items resolve to an array / non-empty nested steps) and return the parsed split (sibling branches + optional aggregator, or items + steps), or a WP_Error with the shared error code on an invalid spec. Route all four entry points through them. Behavior is IDENTICAL: same error codes, same messages, same accepted and rejected specs — only the duplication is removed. Adds tests/workflow-parallel-spec-validation-parity-smoke.php, which asserts the sync and async entry points reject the same invalid specs with the same error codes AND accept the same valid roles (with aggregator) and map specs, so the two paths can never drift again. All existing workflow smoke tests still pass; PHPStan (max) is clean. Co-Authored-By: Claude Opus 4.8 (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
The
parallelworkflow step handler validated its spec in two independent places that could silently drift:run_parallel_roles()andrun_parallel_map()insrc/Workflows/class-wp-agent-workflow-runner.php(~L1310 / ~L1238 on the pre-change file).build_roles_dispatch_plan()andbuild_map_dispatch_plan()in the same file (~L983 / ~L1063).Both pairs re-implemented the identical validation by hand:
workflow_parallel_branch_invalid), non-empty branches (workflow_parallel_branches_empty), at-most-one aggregator (workflow_parallel_aggregator_invalid).workflow_parallel_items_invalid), non-empty nested steps (workflow_parallel_steps_invalid).Because the two copies were maintained separately, a rule tightened on one path but not the other would make the substrate accept a spec synchronously that it rejects asynchronously (or vice versa) — a hard-to-diagnose correctness gap that only surfaces once a caller registers a branch executor and the run takes the async path.
Fix
Extract two shared private helpers and route all four entry points through them:
validate_parallel_roles_spec( array $step )— enforces the three roles rules once and returns the parsed split (sibling branches + optional aggregator), or aWP_Errorwith the shared code on an invalid spec.validate_parallel_map_spec( array $step )— enforces the two map rules once and returns the resolved items + steps, or aWP_Error.This is a behavior-preserving refactor: same error codes, same messages, same set of accepted and rejected specs. Only the duplication is removed. Each caller keeps its own path-specific bits (the sync loop's raw shared-context snapshot vs. the async builder's
string_keyed_array()normalization and descriptor building) — those were never part of the shared validation and are left untouched.Testing
tests/workflow-parallel-spec-validation-parity-smoke.phpasserts parity by invoking both entry points (via reflection, so it targets the exact drift-prone methods):composer smokearray.composer smoke— all green (exit 0), including the existingworkflow-parallel-smokeandworkflow-parallel-async-smokesuites (38 + 38 assertions unchanged).vendor/bin/phpstan analyse --no-progress --memory-limit=2G— No errors (level max).This came out of an automated tech-debt audit of the workflow runner. Opening as a draft for review — the change is intentionally scoped to removing the duplication with a parity safety net, with no change to which specs are accepted or rejected.