feat(#677): add needs_input pushback for the code agent - #682
Conversation
The code agent had no way to refuse to open a PR it couldn't stand behind. Broken environment/tooling and genuinely uninterpretable issues both fell through to a generic "no changed files" no-op comment with no actionable signal for a human. Add an optional needs_input field to the code-result schema. When set, the post-script skips push/PR creation, applies the fs-code-needs-input label, removes ready-to-code, and posts an explanatory comment on the issue instead. skills/code-implementation/SKILL.md now directs the agent to set needs_input (and stop without committing) in three cases: a genuinely uninterpretable issue, a missing scan-secrets helper, and tests/linters that still can't run after one setup attempt. The last case is a behavioral reversal — previously the agent would commit anyway with a disclosure in the commit message. Closes #677 Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
Add eval case 002-push-back-on-nonsense covering the needs_input pushback path: a contradictory issue where the code agent should refuse rather than open a PR. Extend the pr_created judge to assert the negative when annotations.expect_pr is false, and add a required_labels judge (borrowed from eval/triage/eval.yaml) so the fs-code-needs-input label is checked. Document the fs-code-needs-input label in docs/code.md and record the design in docs/plans/code-agent-needs-input.md. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
|
🤖 Finished Review · ✅ Success · Started 8:11 PM UTC · Completed 8:28 PM UTC |
PR Summary by QodoAdd needs_input pushback path for the code agent (label + comment, no PR)
AI Description
Diagram
High-Level Assessment
Files changed (15)
|
Code Review by Qodo
1.
|
ReviewFindingsMedium
Previous runReviewFindingsHigh
Medium
Low
Labels: PR implements the needs_input pushback feature for the code agent, modifying agent definitions, harness config, post-scripts, skills, and eval infrastructure. Next steps:
|
waynesun09
left a comment
There was a problem hiding this comment.
Additional finding (no line in this PR's diff to anchor it to — schemas/code-result.schema.json line 7 isn't within the changed hunk):
[MEDIUM] target_branch kept unconditionally required, untested for the broken-tooling needs_input scenario — schemas/code-result.schema.json:7-8
The schema keeps required: ["target_branch"] unconditional even when needs_input is set. The PR's own design doc (docs/plans/code-agent-needs-input.md) justifies this only as "per current design the agent always writes target_branch regardless" and explicitly lists it under "Open items to watch during implementation" as an unconfirmed assumption, not a verified guarantee. The PR's stated motivation for needs_input is two-fold — (1) a genuinely uninterpretable issue and (2) broken sandbox tooling/environment — but only scenario (1) got an eval case (eval/code/cases/002-push-back-on-nonsense/); there is no case exercising a broken-environment run where the agent's normal means of determining target_branch (git/gh calls) might also fail. If that happens, agent-result.json fails schema validation, validation_loop skips post_script per ADR 0022, and the needs_input signal this feature exists to produce is lost silently — regressing to the pre-PR generic no-op.
Suggestion: Either add an eval case simulating broken tooling (unrelated to git/gh) to confirm target_branch is still reliably produced, or relax the schema so target_branch is optional when needs_input is set (e.g. via oneOf/if-then), since no push/PR happens on the needs_input path regardless of target_branch's value.
|
Re: #682 (comment) Good catch on the schema-compliance line in SKILL.md step 11 — it still said only On the protected-path note: intentional — this feature has to touch scripts/, harness/, and skills/ to exist at all. The schema-compatibility point (optional field + additionalProperties: false being backward-incompatible for a stale CLI copy of the schema) is a real question but not one I can resolve unilaterally — flagging it for a human to confirm how the fullsend CLI resolves this schema at runtime. |
|
Re: #682 (comment) These four findings are the same ones raised inline — handled there: protected-path note dismissed as intentional, the |
- Fix wrong label name (needs-input -> fs-code-needs-input) in agents/code.md and the needs_input schema description. - Close a pr_created judge loophole: fail on any PR at all (open, merged, or closed), not just open/merged, when expect_pr is false. - SKILL.md: needs_input is now listed among the allowed output fields (step 11), and the stale "you must disclose that" line (step 9c) now points at needs_input instead of the old disclosure flow. - Remove docs/plans/code-agent-needs-input.md and ignore docs/plans/ going forward -- planning scratch files aren't meant to be committed. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
- Warn (instead of silently swallowing) label create/apply/remove failures in post_needs_input_comment, matching the existing comment-post failure pattern. - Stop truncating the needs_input comment from the tail -- it's forward, human-authored prose already length-capped by the schema (maxLength 4000), not command/log output where tail-ing makes sense. Truncating from the tail dropped the opening context of longer explanations. - Guard against a needs_input contract violation: warn (in both the workflow log and the posted comment) if the agent committed local work before setting needs_input, since that work is silently discarded, and check for an already-open PR on the branch to avoid posting a "no PR" comment alongside a real one. Adds a regression test for the truncation fix and two git-repo-backed tests for the new contract-violation guards. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
|
Re: #682 (comment) Following up on the schema-compatibility point — the schema ships bundled with this agent, not the CLI, so an old pinned CLI paired with the new agent would indeed reject |
max_turns/max_cost_usd were plausibility-based guesses. Update them using the one CI run we have (21 turns / $0.64, run 31042840745), applying the same headroom multipliers as 001-fix-add (~1.7x turns, ~2x cost) since we only have a single observation so far. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
|
🤖 Finished Review · ✅ Success · Started 10:09 PM UTC · Completed 10:23 PM UTC |
Superseded by updated review
| -X DELETE --silent 2>/dev/null || \ | ||
| gha_echo warning "Failed to remove 'ready-to-code' label from issue #${safe_issue_number}" | ||
|
|
||
| # Guard against a contract violation: needs_input means "stop before |
There was a problem hiding this comment.
[MEDIUM] Contract-violation guard is comment-only, never fails the run
post_needs_input_comment() (added in 6d90896 as a fix for two earlier review threads) detects a genuine contract violation — the agent set needs_input but also left local unpushed commits or already has an open PR for the branch — and appends a warning sentence to the issue comment plus a gha_echo warning to the runner log. But the caller (scripts/post-code.sh:836-839) still exit 0s unconditionally right after calling this function, identical to the clean needs_input path. There's no distinct label, non-zero exit, or other machine-queryable signal — a maintainer/dashboard watching exit codes or labels can't distinguish "clean needs_input" from "agent violated the needs_input contract" without reading full comment prose.
Suggestion: keep posting the caveat prose, but also apply a separate marker (e.g. an fs-code-needs-input-conflict label) or route through the fail path so this state is alertable, not just buried text in a comment.
| gha_echo warning "needs_input set but an open PR already exists for branch '${current_branch}': ${existing_pr_url}" | ||
| else | ||
| local default_branch commits_ahead | ||
| default_branch="$(gh api "repos/${REPO_FULL_NAME}" --jq '.default_branch' 2>/dev/null || echo main)" |
There was a problem hiding this comment.
[MEDIUM] Silent default-branch fallback to "main" can mask the discarded-commits caveat it exists to produce
default_branch="$(gh api "repos/${REPO_FULL_NAME}" --jq '.default_branch' 2>/dev/null || echo main)" silently falls back to the literal string "main" on any API failure (auth hiccup, rate limit, transient network error). If the repo's actual default branch differs (e.g. "master") and the agent's branch genuinely has unpushed commits ahead of it, the following git rev-list --count "origin/${default_branch}..HEAD" either errors against a nonexistent ref (caught by || echo 0) or diffs against the wrong branch, so commits_ahead reports 0 and the "these commits were not pushed and will be discarded" caveat — the exact informative signal this block exists to surface — is silently dropped.
Suggestion: on API failure, log a warning that the discarded-commits check could not run instead of assuming "main", or derive the comparison branch more robustly (e.g. from the upstream tracking ref) rather than defaulting to a guessed branch name.
|
|
||
| > Note: <suite-name> tests could not run (<reason>). <other-suite> | ||
| > tests passed. Manual verification of <suite-name> is required. | ||
| `make setup`, etc.) — one attempt only. If the tool still cannot run |
There was a problem hiding this comment.
[MEDIUM] premature-decision: "one attempt only" setup-retry count for missing tooling is asserted without a cited requirement
The new guidance says: "try the Makefile's setup targets first (make deps, make setup, etc.) — one attempt only. If the tool still cannot run after that attempt, write needs_input...". Issue #677 and the PR description don't specify how many setup attempts the agent should make before giving up; this exact number appears to be a plausibility guess with no cited design-doc or incident basis. Too few attempts risks needs_input pushback (and the human-in-the-loop cost that entails) on transient/flaky setup failures a second attempt or alternate target would resolve; too many burns turn/cost budget on a genuinely broken sandbox.
Suggestion: cite where "one attempt" was decided, or soften to "a reasonable number of attempts (typically one, more only if the failure looks transient)" and let the eval harness gather real data before hard-coding a specific count.
Summary
needs_inputfield to the code-result schema so the agent can refuse to open a PR (broken sandbox tooling or a genuinely uninterpretable issue) and instead post an explanatory comment +fs-code-needs-inputlabel.eval/code/eval.yaml'spr_createdjudge to assert the negative whenannotations.expect_pr: false, add arequired_labelsjudge, and add eval case002-push-back-on-nonsensecovering the pushback path.Test plan
make check-bundlemake testCloses #677
Assisted-by: Claude Opus 4.6 noreply@anthropic.com