test(langgraph): capture parallel dispatch node-flag regression (#97) #109

Open
CoreRasurae wants to merge 1 commits from tdd/m1-pure-graph-parallel-node-gate into master
Member

Summary

Adds a failing-first Behave regression test proving issue #97: PureLangGraph's three concurrent-dispatch sites (pure_graph.py lines 1078, 1860, 1965) fire every candidate next-node concurrently via asyncio.gather/asyncio.create_task whenever the graph-level parallel_execution: true (the default) and there are 2+ candidates, without ever consulting each node's own parallel flag (NodeConfig.parallel / can_execute_parallel()). This violates Actor Configuration Standard §6.7 and §12.3.

The scenario builds a pure-graph route where a trigger node has two unconditional edges to sibling agent nodes, neither marked parallel: true, and drives both through a shared TimingRecorderAgent test double (features/mocks/) that records start/end timestamps. The Then step asserts the two agents' execution intervals never overlap; this assertion currently fails (both start concurrently) while the bug is present.

Tagged @tdd_issue, @tdd_issue_97, and @tdd_expected_fail per the project's TDD issue-capture workflow, so nox -s unit_tests stays green via the existing TddExpectedFailPolicy inversion hook. The actual fix is delivered separately by issue #97 on a bugfix/ branch.

Closes #98

Test plan

  • nox -s lint — green
  • nox -s format -- --check — green
  • nox -s typecheck — green (Pyright strict, 0 errors)
  • nox -s security_scan — green
  • nox -s dead_code — green
  • nox -s unit_tests — green (assertion fails while bug present, inverted to pass via @tdd_expected_fail)
  • nox -s coverage_report — 96.7% (≥ 96.5% threshold)
  • nox -s integration_tests — green
## Summary Adds a failing-first Behave regression test proving issue #97: `PureLangGraph`'s three concurrent-dispatch sites (`pure_graph.py` lines 1078, 1860, 1965) fire every candidate next-node concurrently via `asyncio.gather`/`asyncio.create_task` whenever the graph-level `parallel_execution: true` (the default) and there are 2+ candidates, without ever consulting each node's own `parallel` flag (`NodeConfig.parallel` / `can_execute_parallel()`). This violates Actor Configuration Standard §6.7 and §12.3. The scenario builds a pure-graph route where a trigger node has two unconditional edges to sibling agent nodes, neither marked `parallel: true`, and drives both through a shared `TimingRecorderAgent` test double (`features/mocks/`) that records start/end timestamps. The Then step asserts the two agents' execution intervals never overlap; this assertion currently fails (both start concurrently) while the bug is present. Tagged `@tdd_issue`, `@tdd_issue_97`, and `@tdd_expected_fail` per the project's TDD issue-capture workflow, so `nox -s unit_tests` stays green via the existing `TddExpectedFailPolicy` inversion hook. The actual fix is delivered separately by issue #97 on a `bugfix/` branch. Closes #98 ## Test plan - [x] `nox -s lint` — green - [x] `nox -s format -- --check` — green - [x] `nox -s typecheck` — green (Pyright strict, 0 errors) - [x] `nox -s security_scan` — green - [x] `nox -s dead_code` — green - [x] `nox -s unit_tests` — green (assertion fails while bug present, inverted to pass via `@tdd_expected_fail`) - [x] `nox -s coverage_report` — 96.7% (≥ 96.5% threshold) - [x] `nox -s integration_tests` — green
CoreRasurae added 1 commit 2026-08-04 20:10:21 +00:00
test(langgraph): capture parallel dispatch node-flag regression (#97)
CI / lint (pull_request) Successful in 1m1s
CI / typecheck (pull_request) Successful in 1m39s
CI / security (pull_request) Successful in 1m27s
CI / quality (pull_request) Successful in 48s
CI / build (pull_request) Successful in 1m53s
CI / integration_tests (pull_request) Successful in 3m55s
CI / unit_tests (pull_request) Successful in 5m3s
CI / coverage (pull_request) Successful in 4m13s
CI / status-check (pull_request) Successful in 6s
CI / benchmark (pull_request) Failing after 27m42s
9e2aebd3a7
Adds a failing-first Behave regression test proving issue #97:
PureLangGraph fires every candidate next-node concurrently via
asyncio.gather/asyncio.create_task whenever the graph-level
parallel_execution flag is true (the default) and there are 2+
candidates, without ever consulting each node's own `parallel` flag
(NodeConfig.parallel / can_execute_parallel()). This violates Actor
Configuration Standard §6.7 and §12.3, which require that only the
subset of next-nodes with parallel: true run concurrently while the
rest run sequentially.

The scenario builds a pure-graph route where a trigger node has two
unconditional edges to sibling agent nodes, neither marked
parallel: true, and drives both through a shared TimingRecorderAgent
test double (features/mocks/) that records start/end timestamps.
The assertion checks that the two agents' execution intervals never
overlap; it currently fails (both start concurrently) while the bug
is present.

Tagged @tdd_issue, @tdd_issue_97, and @tdd_expected_fail per the
project's TDD issue-capture workflow, so nox -s unit_tests stays
green via the existing TddExpectedFailPolicy inversion hook. The fix
itself is delivered separately by issue #97 on a bugfix/ branch.

ISSUES CLOSED: #98
CoreRasurae added this to the v2.1.0 milestone 2026-08-04 20:11:47 +00:00
CoreRasurae added the
Type
Testing
label 2026-08-04 20:12:09 +00:00
hurui200320 approved these changes 2026-08-05 05:51:12 +00:00
hurui200320 left a comment
Member

PR Review: !109 (Ticket #98)

Verdict: Approve

This PR delivers the requested failing-first Behave regression capture for issue #97. The scenario is correctly tagged with @tdd_issue @tdd_issue_97 @tdd_expected_fail, signals the bug exclusively via AssertionError, and exercises the execute() concurrent-dispatch site in pure_graph.py. The new TimingRecorderAgent mock is a clean, reusable test double. No critical or major correctness issues were found in the changed code. The few observations below are minor hygiene/robustness notes and a project-level coverage-threshold inconsistency that is not introduced by this PR.

Critical Issues

None

Major Issues

None

Minor Issues

  • Coverage threshold mismatch (noxfile.py / CONTRIBUTING.md)
    The PR test plan reports coverage_report at 96.7% and passes because noxfile.py uses COVERAGE_THRESHOLD = 96.5. However, CONTRIBUTING.md states the project’s enforced merge gate is 97%, and the CI workflow comment also says “fail-under 97%”. The ticket acceptance criteria likewise ask to verify >= 97%. This is a pre-existing project-level inconsistency, and the PR does not regress coverage (it only adds test/mock files, which are excluded from the slipcover source paths), but the documented gate is not met. Recommend reconciling noxfile.py/CONTRIBUTING.md/CI wording, or addressing coverage separately.

  • Then step could fail with KeyError instead of AssertionError (features/steps/pure_graph_parallel_node_gate_steps.py:74-94)
    If a regression ever caused one of the two agents not to run at all, intervals[left] or intervals[right] would raise KeyError. The @tdd_expected_fail hook only inverts AssertionError, so the scenario would fail CI with the wrong exception type. Consider adding an explicit guard such as:

    assert left in intervals and right in intervals, "Expected both agents to execute"
    

    before the overlap assertion.

  • Out-of-scope note for the eventual fix (#97)
    The scenario intentionally covers only the execute() dispatch site; the two execute_stream() branches mentioned in issue #97 are correctly left for the bugfix PR. This is not a defect, just a scope marker.

Nits

  • Unused context attributes (features/steps/pure_graph_parallel_node_gate_steps.py:59-60)
    context.left_agent_name and context.right_agent_name are assigned but never referenced. They can be removed to reduce noise.

  • Empty background step (features/steps/pure_graph_parallel_node_gate_steps.py:25-27)
    The Given a fresh pure graph test context (pg) step is a no-op. It is harmless, but since Behave provides a fresh context per scenario anyway, the Background could be omitted entirely.

Summary

A focused, well-documented TDD capture PR that matches the issue metadata, branch name, commit message, and tagging requirements. The test correctly reproduces the per-node parallel flag violation from docs/index.md §6.7/§12.3, and the @tdd_expected_fail inversion path is compliant with the project policy in features/tdd_expected_fail.py. Once the minor robustness guard is added (optional) and the project-level coverage threshold is reconciled elsewhere, this is ready for merge.

## PR Review: !109 (Ticket #98) ### Verdict: Approve This PR delivers the requested failing-first Behave regression capture for issue #97. The scenario is correctly tagged with `@tdd_issue @tdd_issue_97 @tdd_expected_fail`, signals the bug exclusively via `AssertionError`, and exercises the `execute()` concurrent-dispatch site in `pure_graph.py`. The new `TimingRecorderAgent` mock is a clean, reusable test double. No critical or major correctness issues were found in the changed code. The few observations below are minor hygiene/robustness notes and a project-level coverage-threshold inconsistency that is not introduced by this PR. ### Critical Issues None ### Major Issues None ### Minor Issues - **Coverage threshold mismatch** (`noxfile.py` / `CONTRIBUTING.md`) The PR test plan reports `coverage_report` at 96.7% and passes because `noxfile.py` uses `COVERAGE_THRESHOLD = 96.5`. However, `CONTRIBUTING.md` states the project’s enforced merge gate is **97%**, and the CI workflow comment also says “fail-under 97%”. The ticket acceptance criteria likewise ask to verify `>= 97%`. This is a pre-existing project-level inconsistency, and the PR does not regress coverage (it only adds test/mock files, which are excluded from the slipcover source paths), but the documented gate is not met. Recommend reconciling `noxfile.py`/`CONTRIBUTING.md`/CI wording, or addressing coverage separately. - **`Then` step could fail with `KeyError` instead of `AssertionError`** (`features/steps/pure_graph_parallel_node_gate_steps.py:74-94`) If a regression ever caused one of the two agents not to run at all, `intervals[left]` or `intervals[right]` would raise `KeyError`. The `@tdd_expected_fail` hook only inverts `AssertionError`, so the scenario would fail CI with the wrong exception type. Consider adding an explicit guard such as: ```python assert left in intervals and right in intervals, "Expected both agents to execute" ``` before the overlap assertion. - **Out-of-scope note for the eventual fix (#97)** The scenario intentionally covers only the `execute()` dispatch site; the two `execute_stream()` branches mentioned in issue #97 are correctly left for the bugfix PR. This is not a defect, just a scope marker. ### Nits - **Unused context attributes** (`features/steps/pure_graph_parallel_node_gate_steps.py:59-60`) `context.left_agent_name` and `context.right_agent_name` are assigned but never referenced. They can be removed to reduce noise. - **Empty background step** (`features/steps/pure_graph_parallel_node_gate_steps.py:25-27`) The `Given a fresh pure graph test context (pg)` step is a no-op. It is harmless, but since Behave provides a fresh `context` per scenario anyway, the Background could be omitted entirely. ### Summary A focused, well-documented TDD capture PR that matches the issue metadata, branch name, commit message, and tagging requirements. The test correctly reproduces the per-node `parallel` flag violation from `docs/index.md` §6.7/§12.3, and the `@tdd_expected_fail` inversion path is compliant with the project policy in `features/tdd_expected_fail.py`. Once the minor robustness guard is added (optional) and the project-level coverage threshold is reconciled elsewhere, this is ready for merge.
Some checks are pending
CI / lint (pull_request) Successful in 1m1s
CI / typecheck (pull_request) Successful in 1m39s
CI / security (pull_request) Successful in 1m27s
CI / quality (pull_request) Successful in 48s
CI / build (pull_request) Successful in 1m53s
CI / integration_tests (pull_request) Successful in 3m55s
CI / unit_tests (pull_request) Successful in 5m3s
CI / coverage (pull_request) Successful in 4m13s
CI / status-check (pull_request) Successful in 6s
CI / benchmark (pull_request) Failing after 27m42s
This pull request can be merged automatically.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin tdd/m1-pure-graph-parallel-node-gate:tdd/m1-pure-graph-parallel-node-gate
git checkout tdd/m1-pure-graph-parallel-node-gate
Sign in to join this conversation.
No Reviewers
No Label
Type
Testing
2 Participants
Notifications
Due Date
No due date set.
Reference: cleveragents/cleveractors-core#109