fix(bridge): count pipeline-shaped coders toward CODER_AGENT_SLOTS - #338
Conversation
_coder_agent_name only read spec.coderAgentRef, so pipeline-shaped Workloads (spec.pipeline, e.g. a retry re-dispatched with an explicit pipeline) named their coder on the issue-fix step's agentRef and resolved to None. Such Workloads contributed nothing to _load_by_coder_agent, so their coder never consumed a slot and a second coder could be dispatched alongside them -- observed as two 'coder' Jobs running at once under a coder:1 cap. Fall back to the pipeline issue-fix step's agentRef so these Workloads count.
There was a problem hiding this comment.
AI Automated Review
Full PR review.
Analysis engine: MiniMax-M3@https://litellm.jory.dev/v1 (anthropic) — escalated (fast_low_confidence)
Recommendation
Approve. This is a narrowly scoped, well-explained fix to the coder-load accounting in _coder_agent_name. It restores correctness for pipeline-shaped Workloads without expanding scope or touching unrelated logic, and it ships with a load-bearing unit test that the author confirms fails on the unfixed code path. CI is green (docker and test both succeeded on the head commit).
Change-by-change findings
bridge/main.py — _coder_agent_name
- The previous implementation read
spec.coderAgentRefunconditionally and returnedNoneif it was missing or empty (ref.get("name")on an empty dict). The new implementation preserves the top-level path and adds a fallback that walksspec.pipelinefor the first step withkind == "issue-fix"and readsagentRef.namefrom there. That matches the documented pipeline shape and the observed workload (wl-…-578) on the cluster. - Defensive handling is appropriate and matches the surrounding codebase style:
isinstance(..., dict),ref.get("name")truthiness check, list iteration with continue on malformed entries. The loop returns the first matchingissue-fixstep's agent, which is consistent with how a pipeline-shaped Workload would be produced by retry re-dispatch. - The docstring now describes both shapes and the failure mode this fixes, including the concrete
coder:1cap observation. Helpful for future readers. - Scope is contained: counting only, as the PR body states.
coderAgentRefcontinues to take precedence, so any Workload that already had a top-level ref still resolves identically. No behavioral change for existing workloads.
tests/test_bridge_runtime.py — _pipeline_workload fixture + test_counts_pipeline_shaped_coder
- The fixture builds a minimal but representative pipeline-shaped Workload (
spec.pipelinewith anissue-fixstep and areviewstep, nocoderAgentRef, with thecreated-by: dispatch-bridgelabel needed by_list_bridge_workloadsto filter in). This matches the shape described in the docstring and the test catches the exact bug class (returning{}before,{"coder-py": 1}after). - The test wires the fixture through the same
FakeAPI+_load_by_coder_agentplumbing astest_counts_running_issue_fix, so it exercises the real code path end-to-end rather than calling_coder_agent_namedirectly. Good. - The author confirmed load-bearing behavior (fails without the fix) and the full suite passes (636 tests), which is consistent with the CI
testcheck being green.
Risk flags
The classifier returned no risk flags. The change touches the coder-load accounting path that gates the CODER_AGENT_SLOTS cap, but it strictly extends visibility (additional workloads now count) without altering which workloads count when both shapes are present. The wildcard / default branches in _load_by_coder_agent are unaffected. No auth, public-routes, file-serving, path, secret, or migration surfaces in this diff.
Standards Compliance
- AGENTS.md sets expectations about issue authoring (imperative ask + named file paths) for the autonomous loop. That governs how issues are filed, not PR review. The PR body is descriptive and identifies the bug, the shape, the observed evidence, and the verification (failing-without-fix, passing-with-fix, full-suite green), which aligns with the repo's commit-message style seen in history (
fix(bridge): …). - No repository convention appears violated by the diff (no new modules, no API surface change, no manifest change). The change is consistent with prior bridge-runtime fixes in style and scope.
Tool Harness Findings
The tool harness issued no tool calls and the reviewer relied on the corpus directly. The diff is small and self-contained, and the impacted function _coder_agent_name plus its sole caller in _load_by_coder_agent are visible in the impact scan, so the absence of native tool reads does not materially weaken this review.
CI
docker and test checks both succeeded on the head commit a3e61e6. Authoritative.
Unknowns or Needs Verification
- The exact pipeline step ordering and
kindvalue used by Foreman's retry re-dispatch when this PR was filed is not externally documented in the corpus; the code's reliance onkind == "issue-fix"is consistent with the codebase's task model (_taskfixtures usekind="issue-fix") and with the pipeline shape shown in the test fixture, but I have not verified the Foreman CRD schema itself. This is a minor unverifiable point, not a blocker, since the test mirrors the real shape closely and the docstring documents the assumption. - Whether other pipeline shapes (e.g. pipelines without an
issue-fixstep at all) are ever produced by retry re-dispatch could not be confirmed from the corpus. The current fallback handles the absence ofissue-fixcleanly by returningNone, matching pre-fix behavior for that case, so no regression is implied.
What
_coder_agent_nameonly readspec.coderAgentRef, so pipeline-shaped Workloads —spec.pipeline, the shape a retry re-dispatched with an explicit pipeline produces — resolved toNone. Those Workloads name the coder on theissue-fixstep'sagentRef, not at the top level, so they contributed nothing to_load_by_coder_agent. Their coder never consumed aCODER_AGENT_SLOTSslot, and a second coder could be dispatched alongside them.Fall back to the pipeline's
issue-fixstepagentRefwhen there's no top-levelcoderAgentRef, so these Workloads count toward coder load.Evidence
Observed on the cluster: two
coderJobs running concurrently underCODER_AGENT_SLOTS={"coder":1}.wl-…-587: standard shape,spec.coderAgentRef.name = coder→ counted.wl-…-578: pipeline shape (spec.pipeline[], coder on theissue-fixstep), nospec.coderAgentRef→ invisible to the load counter.When 587's tick ran, 578 was active but uncounted, so
load[coder]=0and the slot cap admitted a second coder.Test
Added
test_counts_pipeline_shaped_coder. Verified load-bearing: it fails without the fix ({}instead of{"coder-py": 1}) and passes with it. Full suite: 636 passed.Scope
Counting only. Does not change how pipeline Workloads are created or which agent they use — it makes an existing coder visible to the slot accounting it was already meant to be subject to.