test(#5987): add behaviour coverage for code applier branch handling - #5992
Conversation
PR Summary by QodoAdd e2e behaviour coverage for code/fix applier branch handling
AI Description
Diagram
High-Level Assessment
Files changed (23)
|
Code Review by Qodo
1.
|
2036c47 to
21062fa
Compare
21062fa to
ee5a2ba
Compare
|
/fs-review |
|
🤖 Finished Review · ✅ Success · Started 12:52 PM UTC · Completed 1:05 PM UTC Commit: |
ReviewFindingsMedium
Low
Labels: PR adds behaviour test coverage for code applier branch handling (e2e/behaviour/, pkg/behaviourtest/) Previous runLooks good to me |
Add live-run behaviour scenarios asserting the code applier's branch guarantees end to end: a code run lands on an agent/<issue>-* head branch while other issues' branches are untouched, and a conforming namespaced branch is pushed without rename. New primitives backing the scenarios: - checkout_branch dummy-runtime op: regex-validated branch name only. Probes the remote with ls-remote --exit-code --heads (failing closed on non-missing-ref errors), fetches and bases the branch on the matching refs/heads/ ref when it exists (scoped so a same-named tag can never be resolved instead), and records one marker commit so the applier has content to push and a wrongful push visibly moves the target branch tip. Covered by mock-exec unit tests plus real-shell/git integration tests, including a same-named-tag collision regression. - Branch assertion steps (pkg/behaviourtest/steps/branch.go): seed and record remote branches, assert a branch tip is unchanged across a run, assert exactly one open PR head matches a pattern (with an <issue> placeholder), and wait for a failed harness run plus its failure comment. The failure step has no shipped scenario yet — the fix stage's only dispatch route is a changes_requested review from the org review bot, which the suite cannot produce — so the fix-side branch-mismatch scenario from the issue is documented as inexpressible and stays covered by agents-repo script tests. - scm.Driver gains ListOpenChangeProposals/ListComments; ci.Driver gains WaitForFailedHarnessAgent with artifact-first detection (the fullsend-<agent> artifact uploads with if: always()) and a job-name fallback that scans every completed run (not just ones already known to have failed) so a successful job still fails fast via that path. - @requires:capability:<name> compatibility tag wired to the BEHAVIOUR_CAPABILITIES env var, so the new scenarios (tagged applier-branch-namespace) skip mechanically until the runner declares the capability — CI stays green until the agents-side enforcement ships. A malformed tag (empty capability name) is a hard error, not a silent permanent skip. - Scenario cleanup: tracked branches/PRs plus a namespace sweep, gated on the scenario's issue number alone, that reclaims applier-created agent/<issue>-* PRs even when a scenario fails before its head-match assertion or never seeds a decoy branch; deduplicated against PRs the assertion step already tracked so passing runs don't double-close. - Schema-valid code fixture and docs updates for the new op, steps, tag, and driver API changes. Refs #5987 Assisted-by: Claude (fix), Claude (review), Grok (review) Signed-off-by: Wayne Sun <gsun@redhat.com>
ee5a2ba to
c8f5177
Compare
|
🤖 Review · ❌ Terminated · Started 1:34 PM UTC · Ended 1:49 PM UTC Commit: |
Site previewPreview: https://542c0109-site.fullsend-ai.workers.dev Commit: |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
|
🤖 Finished Review · ✅ Success · Started 1:34 PM UTC · Completed 1:49 PM UTC Commit: |
|
🤖 Finished Retro · ✅ Success · Started 2:42 PM UTC · Completed 2:57 PM UTC Commit: |
Retro: PR #5992 — behaviour coverage for code applier branch handlingWorkflow outcome: Smooth. Human-authored PR, two review runs, approved and merged with no rework required. Timeline
What went well
Evidence for existing issues (no new proposals needed)
Why no proposalsThe workflow functioned well. The two improvement opportunities I identified (challenger fallback, self-justified findings) are already tracked in open issues with clear problem statements. The style sub-agent false positive pattern is worth monitoring but is a single data point insufficient for a concrete proposal. |
Summary
Adds
e2e/behaviourscenarios that assert the code applier's branch handling end to end against live GitHub, plus the primitives the suite was missing to express them (issue #5987). Until now every scenario stopped at dispatch/labeling; nothing drove a run through the post-scripts to a real push and asserted the resulting branch state.The scenarios are mechanically gated: they carry
@requires:capability:applier-branch-namespaceand are skipped unless the runner declares that capability viaBEHAVIOUR_CAPABILITIES, because they assert applier behavior that ships with the upcoming agents-side branch-namespace enforcement. CI stays green until the pinned agents release includes it; then the capability gets enabled.Related Issue
Refs #5987 (delivers the primitives and scenarios A/C; see "Deviation" below for scenario B)
Changes
checkout_branchdummy-runtime op (internal/runtime/dummy.go): takes a single regex-validated branch name. Probes the remote withgit ls-remote --exit-code --heads— a missing ref (rc=2) falls back to branching offHEAD, any other probe failure fails the op instead of silently degrading. When the ref exists it's fetched via the samerefs/heads/scope (so a same-named tag can never be resolved instead — regression-tested) and the branch is based onFETCH_HEAD. The op then records one marker commit, so the applier post-script has content to push and a wrongful push visibly moves the target branch tip. Covered by mock-exec unit tests plus real-shell/git integration tests for the existing-ref, missing-ref, broken-remote, and tag-collision paths.pkg/behaviourtest/steps/branch.go):an open pull request on branch "<name>"/a remote branch "<name>" seeded with a commit— deterministic Given fixtures that tolerate pool-repo debris; PR base resolved viaGetDefaultBranch.the tip of branch "<name>" is recorded/branch "<name>" is unchanged— captureGetBranchRefbefore the run, re-check after.the pull request head branch matches "<pattern>"— exactly one open PR head must match the anchored Go-regex pattern; supports an<issue>placeholder (also honored incheckout_branchtable args — scoped to that op only).the harness "<agent>" workflow fails reporting "<text>"— waits for a terminally-failed harness run, then asserts the post-script failure comment on the scenario PR; context-cancellable end to end.@requires:capability:<name>compatibility tag recognized bySkipErrorForTagNames, wired to the comma-separatedBEHAVIOUR_CAPABILITIESenv var. A malformed tag (empty capability name) is a hard error, not a silently-permanent skip.scm.DrivergainsListOpenChangeProposals/ListComments;ci.DrivergainsWaitForFailedHarnessAgentusing artifact-first detection (fullsend-<agent>uploads withif: always(), resolving standard stage jobs likeFix/Codetoo, not just custom-harness matrix jobs), with a job-name fallback that scans every completed run — not just ones already known to have failed — so a successful job still fails fast through that path too. Surfaced job-listing errors on timeout, unit tests for both detection paths. All three methods documented in the behaviour-testing "API changes" section.e2e/behaviour/features/code/branch-namespace.feature: scenario A (foreign branch renamed into the issue namespace, decoy tip unchanged; decoy uses issue number 990000099 so it can never collide with a real issue's anchored pattern) and scenario C (conformingagent/<issue>-<slug>branch pushed with no rename).CleanupScenario, plus a namespace sweep — gated on the scenario's issue number alone, not on whether a branch step happened to run — that reclaims applier-createdagent/<issue>-*PRs even when the scenario fails before its head-match assertion. Deduplicated against PRs the assertion step already tracked, so a passing run doesn't double-close/delete.Deviation from the issue plan
Issue #5987's scenario B (fix run refuses to push from a non-matching branch) is not expressible in this suite today: the fix stage's only dispatch route is a
changes_requestedreview submitted by the org review bot (reusable-dispatch.yml), and suite-posted comments are bot-authored, which both the per-repo shim and the/fs-fixroute drop. The failure-assertion step andWaitForFailedHarnessAgentare landed and unit-tested as ready primitives, the limitation is documented in the feature file and suite docs, and the fix-side refusal stays covered by script-level tests in the agents repo until a suite-reachable fix trigger exists.Testing
make lintpasses (staged first)go test ./internal/runtime/ ./pkg/behaviourtest/...— unit tests for the op (valid/invalid names, exec failure, real-shell integration for both basing paths, the fail-closed remote-error path, and the tag-collision regression), every new step, the capability gate (including the malformed-tag error path), the cleanup sweep (including dedup and no-branch-step gating), and bothWaitForFailedHarnessAgentdetection pathsmake behaviour-testwithBEHAVIOUR_CAPABILITIES=applier-branch-namespace— pending the agents-side branch-namespace enforcement in the pinned agents release; without the capability the scenarios skip (verified by the gating unit tests)The two pre-existing
TestDummyRuntime_Bootstrap/TestDummyRuntime_ClearIterationArtifactsfailures on machines with a live local sandbox are unrelated (also fail on cleanmain).This PR went through two rounds of a 3-agent review squad (Claude, Grok). Round 1 found the fix-stage scenario was undispatchable, the failure waiter only matched custom-harness job names, tip-unchanged assertions were vacuous, and the branch-checkout fetch failed open on transient errors — all fixed above. Round 2 caught a cleanup double-close/delete regression, a fragile sweep gate, a fetch/tag-collision edge case, and a fast-fail regression in the job-name fallback — also fixed and covered by new regression tests.
Checklist