Skip to content

feat(#677): add needs_input pushback for the code agent - #682

Open
ralphbean wants to merge 18 commits into
mainfrom
feat/677-code-needs-input
Open

feat(#677): add needs_input pushback for the code agent#682
ralphbean wants to merge 18 commits into
mainfrom
feat/677-code-needs-input

Conversation

@ralphbean

@ralphbean ralphbean commented Aug 5, 2026

Copy link
Copy Markdown
Member

Summary

  • Add a needs_input field 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-input label.
  • Extend eval/code/eval.yaml's pr_created judge to assert the negative when annotations.expect_pr: false, add a required_labels judge, and add eval case 002-push-back-on-nonsense covering the pushback path.

Test plan

  • make check-bundle
  • make test
  • Watch CI (I didn't run the functional tests locally for this yet)

Closes #677

Assisted-by: Claude Opus 4.6 noreply@anthropic.com

@ralphbean
ralphbean requested a review from a team as a code owner August 5, 2026 20:10
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 5, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 8:11 PM UTC · Completed 8:28 PM UTC
Commit: 1ff174c · View workflow run →

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add needs_input pushback path for the code agent (label + comment, no PR)

✨ Enhancement 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Add needs_input to the code agent result schema to support intentional “stop and ask” runs.
• Teach post-code to short-circuit: comment on the issue, apply fs-code-needs-input, and skip PR
 creation.
• Add schema + end-to-end post-script tests and an eval case asserting the no-PR + required label
 path.
Diagram

graph TD
  F(["Eval harness"]) --> A(["Code agent"]) --> B[/"agent-result.json"/] --> C(["post-code.sh" ભારે])
  C -->|"needs_input set"| D{{"GitHub Issue"}}
  C -->|"needs_input empty"| E{{"GitHub PR"}}
  subgraph Legend
    direction LR
    _p(["Process/script"]) ~~~ _f[/"JSON file"/] ~~~ _g{{"GitHub"}}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use a structured enum (needs_input_reason) + optional detail
  • ➕ Allows better analytics/routing (e.g., tooling vs ambiguity)
  • ➕ Enables automated remediation playbooks per reason
  • ➖ Requires schema + script logic changes now and future reason taxonomy maintenance
  • ➖ Still needs a freeform message field for actionable detail
2. Create a draft PR instead of refusing PR creation
  • ➕ Keeps all context in a PR artifact reviewers are used to
  • ➕ Allows attaching partial work or WIP commits
  • ➖ Contradicts the goal of avoiding unverified/unsafe PRs (broken tooling, uninterpretable issues)
  • ➖ Still needs label/comment signaling; increases noise in PR list
3. Use GitHub Checks / workflow annotations rather than issue labels
  • ➕ More CI-native; can block merges and show status prominently
  • ➕ Reduces label proliferation
  • ➖ Harder to use as a human triage queue compared to labels
  • ➖ More complex integration than the current post-script gh calls

Recommendation: The PR’s approach (single freeform needs_input string + deterministic post-script behavior: label, remove ready-to-code, comment, exit 0) is a strong default: it’s simple, human-actionable, and minimizes noise by avoiding PR creation. If future automation needs emerge, consider adding a needs_input_reason enum later while keeping the freeform message for specifics.

Files changed (15) +790 / -18

Enhancement (3) +118 / -0
code-result.schema.jsonAdd needs_input field to code agent result schema +6/-0

Add needs_input field to code agent result schema

• Introduces an optional 'needs_input' string with length bounds (1..4000) and documentation describing the no-commit, no-PR semantics when set.

schemas/code-result.schema.json

post-code.shImplement needs_input early exit (comment + label, no PR) in bundled script +56/-0

Implement needs_input early exit (comment + label, no PR) in bundled script

• Adds 'post_needs_input_comment' and an early-exit check after parsing agent output so runs with 'needs_input' stop cleanly before branch validation, git operations, or PR creation.

scripts/post-code.sh

post-code.src.shImplement needs_input early exit (source) for post-code script generation +56/-0

Implement needs_input early exit (source) for post-code script generation

• Adds the needs-input helper and short-circuit logic in the source script so regenerated bundles include the new behavior.

scripts/post-code.src.sh

Tests (2) +285 / -0
code-result-schema-test.shAdd schema validation tests for needs_input and regressions +96/-0

Add schema validation tests for needs_input and regressions

• Adds a focused test runner for 'schemas/code-result.schema.json' validating happy paths, unknown properties, missing required fields, and needs_input constraints.

scripts/code-result-schema-test.sh

post-code-needs-input-test.shAdd end-to-end test for post-code needs_input early exit +189/-0

Add end-to-end test for post-code needs_input early exit

• Runs the real 'post-code' script with a mocked 'gh' to assert it skips PR creation, applies the needs-input label, removes 'ready-to-code', posts a comment, exits 0, and respects 'CODE_NEEDS_INPUT_LABEL' overrides.

scripts/post-code-needs-input-test.sh

Documentation (4) +288 / -8
code.mdDocument needs_input structured output behavior for the code agent +4/-1

Document needs_input structured output behavior for the code agent

• Updates the structured output section to describe 'needs_input' as the mechanism to stop without committing and trigger an issue comment + label instead of a PR.

agents/code.md

code.mdAdd fs-code-needs-input control label documentation +1/-0

Add fs-code-needs-input control label documentation

• Documents the new 'fs-code-needs-input' label semantics, including when it is applied, that it removes 'ready-to-code', and how humans re-trigger after resolving the blocker.

docs/code.md

code-agent-needs-input.mdAdd design plan for needs_input pushback path +258/-0

Add design plan for needs_input pushback path

• Introduces a detailed design doc capturing problem statement, goals, schema/harness/script changes, and a TDD-oriented test plan for the needs_input behavior.

docs/plans/code-agent-needs-input.md

SKILL.mdUpdate code agent skill to use needs_input for blockers/ambiguity +25/-7

Update code agent skill to use needs_input for blockers/ambiguity

• Directs the agent to set 'needs_input' (and stop without committing) for missing scan-secrets, genuinely uninterpretable issues, and tooling/infra failures after one setup attempt—replacing the prior “commit with disclosure” guidance.

skills/code-implementation/SKILL.md

Other (6) +99 / -10
MakefileRun new post-code needs_input and schema test scripts +2/-0

Run new post-code needs_input and schema test scripts

• Adds the needs-input post-code test and a dedicated code-result schema test to the 'script-test' target so they run in the standard suite.

Makefile

annotations.yamlDefine eval annotations for needs_input (no PR expected) case +33/-0

Define eval annotations for needs_input (no PR expected) case

• Adds a new eval case annotation set that expects no PR and requires the 'fs-code-needs-input' label, with tighter budget targets for quick pushback.

eval/code/cases/002-push-back-on-nonsense/annotations.yaml

input.yamlAdd contradictory issue fixture to trigger needs_input pushback +21/-0

Add contradictory issue fixture to trigger needs_input pushback

• Creates an issue fixture with irreconcilable requirements to validate the agent refuses implementation and instead requests human clarification.

eval/code/cases/002-push-back-on-nonsense/input.yaml

repoPoint eval case at tiny-calc repo fixture +1/-0

Point eval case at tiny-calc repo fixture

• Adds the repo pointer file referencing the tiny-calc fixture used by the new eval case.

eval/code/cases/002-push-back-on-nonsense/repo

eval.yamlSupport no-PR eval cases and required label assertions +41/-10

Support no-PR eval cases and required label assertions

• Extends 'pr_created' judge to assert a negative when 'annotations.expect_pr: false', adds a 'required_labels' judge, and wires its threshold into the suite.

eval/code/eval.yaml

code.yamlConfigure CODE_NEEDS_INPUT_LABEL for the code harness +1/-0

Configure CODE_NEEDS_INPUT_LABEL for the code harness

• Adds 'CODE_NEEDS_INPUT_LABEL=fs-code-needs-input' to the runner environment so post-code can use a consistent label with an override fallback.

harness/code.yaml

@qodo-code-review

qodo-code-review Bot commented Aug 5, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Protected paths modified ✗ Dismissed 📜 Skill insight § Compliance
Description
This PR modifies protected governance/infrastructure paths (scripts/, skills/, harness/),
which must receive explicit human review and must not be auto-approved. Ensure appropriate
CODEOWNERS/maintainer approval before merging.
Code

scripts/post-code.src.sh[R80-83]

+post_needs_input_comment() {
+  local needs_input="$1"
+  local safe_issue_number
+  safe_issue_number="$(_sanitize_workflow_value "${ISSUE_NUMBER}")"
Relevance

●● Moderate

Protected-path governance is real, but prior “authorization note” style asks were rejected; unclear
what change is expected.

PR-#631

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Compliance requires raising a finding whenever protected governance/infrastructure paths are
modified. This PR adds/changes code under scripts/, modifies runner env configuration in
harness/, and updates agent skill instructions in skills/, so it must not be auto-approved and
needs human review.

scripts/post-code.src.sh[69-114]
harness/code.yaml[44-55]
skills/code-implementation/SKILL.md[42-47]
Skill: pr-review

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Protected governance/infrastructure paths were modified, which requires explicit human review and must not be auto-approved.

## Issue Context
The PR changes files under `scripts/`, `skills/`, and `harness/`, which are treated as protected paths.

## Fix Focus Areas
- scripts/post-code.src.sh[69-168]
- harness/code.yaml[44-55]
- skills/code-implementation/SKILL.md[42-47]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Needs-input PR judge loophole ✓ Resolved 🐞 Bug ≡ Correctness
Description
In eval/code/eval.yaml, pr_created treats expect_pr: false as “no OPEN/MERGED PR exists”, so a
regression that creates a PR and then closes it would still pass the needs_input case even though a
PR was opened.
Code

eval/code/eval.yaml[R153-156]

      prs = state.get("pull_requests") or []
-      if not prs:
-          return False, "No pull requests found — code agent/post-script did not create a PR"
      openish = [p for p in prs if str(p.get("state", "")).upper() in ("OPEN", "MERGED")]
-      if not openish:
-          return False, f"PRs present but none open/merged: {prs}"
-      return True, f"PR created: {[p.get('url') for p in openish]}"
+      expect_pr = outputs.get("annotations", {}).get("expect_pr", True)
+      if expect_pr:
Relevance

●●● Strong

Correctness gap in eval judge; tightening negative assertion matches repo’s tendency to harden eval
logic.

PR-#177

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The judge computes openish (OPEN/MERGED only) and, when expect_pr is false, it only fails if
openish is non-empty—ignoring CLOSED PRs entirely.

eval/code/eval.yaml[147-163]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The `pr_created` judge should enforce that *no PR was created at all* when `annotations.expect_pr: false`. The current logic only checks for absence of OPEN/MERGED PRs, which allows CLOSED PRs to slip through and weakens the regression guard for needs_input cases.

### Issue Context
This judge is used specifically to validate the needs_input pushback path, where the stated expectation is “No PR is opened”.

### Fix Focus Areas
- eval/code/eval.yaml[147-163]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Wrong needs-input label name ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
agents/code.md claims the post-script applies a needs-input label, but the implemented and
documented control label is fs-code-needs-input, which can mislead humans and agents about the
actual workflow state/label to look for or remove.
Code

agents/code.md[R86-89]

+description, or `needs_input` when you need human input before you can
+proceed — in that case, do not commit, and the post-script applies a
+`needs-input` label and posts the text as an issue comment instead of
+opening a PR. The `code-implementation` skill describes the schema and
Relevance

●●● Strong

Teams usually accept doc clarifications to prevent agent/human misreads; aligns with prior agent-doc
fix patterns.

PR-#326

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The agent-facing docs say needs-input, but both the user docs and the post-script default to
fs-code-needs-input, so the name in agents/code.md is inconsistent with the actual behavior.

agents/code.md[84-90]
docs/code.md[34-39]
scripts/post-code.src.sh[80-94]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`agents/code.md` documents the wrong label name (`needs-input`) for the needs_input pushback path. The pipeline uses `fs-code-needs-input`, so this documentation mismatch can cause incorrect manual remediation steps and confusion.

### Issue Context
The correct label is documented in `docs/code.md` and is also the default used by the post-code script.

### Fix Focus Areas
- agents/code.md[84-90]
- (optional cross-check) docs/code.md[34-39]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Silent label operation failures ✓ Resolved 🐞 Bug ◔ Observability
Description
post_needs_input_comment suppresses stderr and ignores failures for label create/apply/remove
operations, so the primary machine-readable signal (fs-code-needs-input) can silently fail while
the script still exits 0.
Code

scripts/post-code.src.sh[R88-92]

+  gh label create "${label}" --repo "${REPO_FULL_NAME}" \
+    --description "Code agent needs human input to proceed" --color "D93F0B" \
+    --force 2>/dev/null || true
+  gh api "repos/${REPO_FULL_NAME}/issues/${ISSUE_NUMBER}/labels" \
+    -f "labels[]=${label}" --silent 2>/dev/null || true
Relevance

●● Moderate

Repo sometimes prefers fail-closed, but this path is explicitly best-effort; no close precedent on
label ops.

PR-#415
PR-#38

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The needs_input handler discards errors for gh label create and gh api label add/remove, unlike
other scripts (e.g., triage) that fail or print errors when label application fails.

scripts/post-code.src.sh[80-114]
scripts/post-triage.sh[75-91]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
In the needs_input early-exit path, label create/apply/remove operations are all best-effort with `2>/dev/null || true` and no warnings. If permissions/transient GitHub errors occur, the run will look successful but the issue may not get the required label and may retain `ready-to-code`.

### Issue Context
Best-effort behavior is fine, but it should emit warnings (like the comment-posting failure path already does) so operators can diagnose why the label signal is missing.

### Fix Focus Areas
- scripts/post-code.src.sh[80-114]
- (contrast/reference) scripts/post-triage.sh[75-91]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context used
✅ Compliance rules (platform): 55 rules
✅ Skills: 4 invoked
  code-review
  code-implementation
  pr-review
  docs-review

Grey Divider

Tip of the day
💡 Did you know, you can reply 'qodo' on any finding to push back, ask questions, or dig deeper

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread scripts/post-code.src.sh
Comment thread agents/code.md
Comment thread eval/code/eval.yaml
Comment thread scripts/post-code.src.sh Outdated
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review

Findings

Medium

  • [protected-path] agents/code.md, harness/code.yaml, scripts/code-result-schema-test.sh, scripts/lib/github-code-ops.lib.sh, scripts/lib/gitlab-code-ops.lib.sh, scripts/post-code-needs-input-test.sh, scripts/post-code.sh, scripts/post-code.src.sh, scripts/pre-code.sh, skills/code-implementation/SKILL.md — This PR modifies files under protected paths (agent instructions, harness config, post-scripts, skill docs). All changes trace directly to issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677's authorized scope. Human approval is always required for protected-path changes, regardless of context.

Low

  • [test-coverage] scripts/post-code-needs-input-test.sh:63 — The mock gh script matches forge_list_prs_for_branch calls using a fixed argument pattern. If arguments are reordered in a future refactor, the mock silently stops matching and existing-PR test assertions pass vacuously. Inherent to pattern-based mocking and acceptable, but a regression risk.

  • [scope-creep] scripts/pre-code.sh:124forge_remove_label() is defined in pre-code.sh (both GitHub and GitLab sections) but never called there. Build-system artifact from bundling the shared lib files, not intentional scope creep.

Previous run

Review

Findings

Medium

  • [protected-path] agents/code.md, harness/code.yaml, scripts/code-result-schema-test.sh, scripts/lib/github-code-ops.lib.sh, scripts/lib/gitlab-code-ops.lib.sh, scripts/post-code-needs-input-test.sh, scripts/post-code.sh, scripts/post-code.src.sh, scripts/pre-code.sh, skills/code-implementation/SKILL.md — This PR modifies files under protected paths (agent instructions, harness config, post-scripts, skill docs). All changes trace directly to issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677's authorized scope. Human approval is always required for protected-path changes, regardless of context.

Low

  • [stale-doc] skills/code-implementation/SKILL.md:1084 — SKILL.md states target_branch is "(required)" without qualifying that the schema's if/then clause makes it optional when needs_input is present. The schema test valid-needs-input-without-target-branch confirms needs_input-only payloads are valid. An agent reading SKILL.md would believe target_branch is always mandatory, conflicting with the schema.
    Remediation: Change to "target_branch (required unless needs_input is set)".

  • [edge-case] scripts/lib/github-code-ops.lib.sh:63forge_remove_label() interpolates the label name directly into the URL path without URL-encoding. The label validation regex permits spaces (^[a-zA-Z0-9._:/ -]+$), and a label containing a space would produce a malformed URL path. Not reachable today (only ready-to-code and fs-code-needs-input are passed), but a latent issue.

  • [scope-creep] scripts/pre-code.sh:124forge_remove_label() is defined in pre-code.sh (both GitHub and GitLab sections) but never called there. Build-system artifact from bundling the shared lib files, not intentional scope creep.

  • [test-coverage] scripts/post-code-needs-input-test.sh:63 — The mock gh script matches forge_list_prs_for_branch calls using a fixed argument pattern. If arguments are reordered in a future refactor, the mock silently stops matching and existing-PR test assertions pass vacuously. Inherent to pattern-based mocking and acceptable, but a regression risk.

Previous run (2)

Review

Findings

Medium

  • [GitLab forge support] scripts/post-code.src.shpost_needs_input_comment() uses GitHub-specific commands (gh label create, gh api, gh pr list, gh issue comment) instead of the forge-agnostic helpers used elsewhere in the same file (e.g., post_noop_comment() uses forge_post_issue_comment()). The code agent supports GitLab (harness/code.yaml has a full forge.gitlab section), but the needs_input path will silently fail on GitLab deployments — all gh calls have 2>/dev/null || gha_echo warning error handling that suppresses failures, leaving the issue in an inconsistent state (no fs-code-needs-input label applied, no comment posted, ready-to-code not removed).
    Remediation: Refactor post_needs_input_comment() to use forge_add_label(), forge_post_issue_comment(), and a forge_remove_label() call for removing ready-to-code, matching the pattern used by post_noop_comment() and other forge-agnostic helpers.

  • [protected-path] agents/code.md, harness/code.yaml, scripts/code-result-schema-test.sh, scripts/post-code-needs-input-test.sh, scripts/post-code.sh, scripts/post-code.src.sh, skills/code-implementation/SKILL.md — This PR modifies files under protected paths (agent instructions, harness config, post-scripts, skill docs). All changes trace directly to issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677's authorized scope. Human approval is always required for protected-path changes, regardless of context.

Low

  • [Documentation/code inconsistency] skills/code-implementation/SKILL.md, agents/code.md — Both files state target_branch is "(required)" without qualifying that the schema's if/then clause makes it optional when needs_input is present. The PR modified these lines to add needs_input to the field list but did not update the "(required)" parenthetical. The schema test valid-needs-input-without-target-branch confirms needs_input-only payloads are valid.
    Remediation: Change to "with target_branch (required unless needs_input is set)".

  • [scope-creep] .gitignore:3 — Adding docs/plans/ to .gitignore is unrelated to issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677. Single-line housekeeping change with no risk, but does not trace to the authorized scope.

  • [configuration mismatch] docs/code.md — Describes CODE_NEEDS_INPUT_LABEL as "Forwarded from the runner environment via env.runner", but harness/code.yaml sets it as a static literal default (correct per AGENTS.md section 8). The actual override path is harness base: composition, not upstream env var override.
    Remediation: Update docs/code.md wording to clarify the override mechanism (e.g., "Defaults to fs-code-needs-input. Override via harness base: composition.").


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (3)

Review

Findings

Medium

  • [protected-path] agents/code.md, harness/code.yaml, scripts/code-result-schema-test.sh, scripts/post-code-needs-input-test.sh, scripts/post-code.sh, scripts/post-code.src.sh, skills/code-implementation/SKILL.md — This PR modifies files under protected paths (agents/, harness/, scripts/, skills/). The PR links to issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677 and the description explains the rationale for the changes. Human approval is always required for protected-path changes, regardless of context.

Low

  • [Documentation/code inconsistency] skills/code-implementation/SKILL.md — Step 11 states that target_branch is "required" in the result file, but the schema now makes target_branch conditionally required — only when needs_input is absent (via JSON Schema if/then). The prose is technically inaccurate. In practice the instructed flow writes target_branch in step 3 before adding needs_input later, so both fields will typically be present.
    Remediation: Amend "with target_branch (required)" to "with target_branch (required unless needs_input is set)".

  • [scope-creep] .gitignore:3 — Adding docs/plans/ to .gitignore is unrelated to issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677 (scoped to the needs_input pushback mechanism). Single-line housekeeping change with no risk, but does not trace to the authorized scope.

Previous run (4)

Review

Findings

Medium

  • [protected-path] agents/code.md, harness/code.yaml, scripts/code-result-schema-test.sh, scripts/post-code-needs-input-test.sh, scripts/post-code.sh, scripts/post-code.src.sh, skills/code-implementation/SKILL.md — This PR modifies 7 files under protected paths (agents/, harness/, scripts/, skills/). The PR links to issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677 and the description explains the rationale for each change. Human approval is always required for protected-path changes, regardless of context.

Low

  • [consumer-completeness] skills/code-implementation/SKILL.md — Step 11 describes target_branch as always "(required)" but the schema now makes it conditionally required (only when needs_input is absent via if/then). All needs_input paths occur after step 3 writes target_branch, so the conditional never triggers in practice. The schema validation handles the conditional requirement correctly, so the practical impact is minimal.

  • [test-coverage-gap] scripts/code-result-schema-test.sh — Missing schema test for needs_input combined with other optional fields (e.g., pr_body) but without target_branch, which would validate the conditional if/then logic for a non-obvious combination.

Previous run (5)

Review

Findings

Medium

  • [protected-path] agents/code.md, harness/code.yaml, scripts/code-result-schema-test.sh, scripts/post-code-needs-input-test.sh, scripts/post-code.sh, scripts/post-code.src.sh, skills/code-implementation/SKILL.md — This PR modifies 7 files under protected paths (agents/, harness/, scripts/, skills/). The PR links to issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677 and the description explains the rationale for each change. Human approval is always required for protected-path changes, regardless of context.

Low

  • [consumer-completeness] skills/code-implementation/SKILL.md — Step 11 describes target_branch as always "(required)" but the schema now makes it conditionally required (only when needs_input is absent via if/then). In broken-environment scenarios where the agent cannot determine a target branch, this prose could mislead the agent into thinking it must always provide one. The schema validation handles the conditional requirement correctly, so the practical impact is minimal.

  • [edge-case] eval/code/eval.yaml — The expected_files judge does not short-circuit when expect_pr is false. Currently harmless (case 002 does not declare expected_files), but if a future needs_input eval case accidentally declares expected_files, the judge would produce a confusing failure rather than a clear "no PR expected" message.

  • [test-coverage-gap] scripts/code-result-schema-test.sh — Missing schema test for needs_input combined with other optional fields (e.g., pr_body) but without target_branch, which would validate the conditional if/then logic for a non-obvious combination.

  • [injection] scripts/post-code.src.sh:268 — The existing_pr_url value from gh pr list in post_needs_input_comment() is interpolated into the issue comment body without URL validation. The GitHub API constrains URLs to https://github.com/... format, making exploitation practically impossible; validating the URL pattern would add defense-in-depth.

  • [schema-breaking-change] schemas/code-result.schema.json — The target_branch field is no longer unconditionally required; it is conditionally required only when needs_input is absent (via JSON Schema if/then). The primary consumer (post-code.sh) is updated in this PR and already used // empty fallback handling.

Previous run (6)

Review

Findings

Medium

  • [protected-path] agents/code.md, harness/code.yaml, scripts/code-result-schema-test.sh, scripts/post-code-needs-input-test.sh, scripts/post-code.sh, scripts/post-code.src.sh, skills/code-implementation/SKILL.md — This PR modifies 7 files under protected paths (agents/, harness/, scripts/, skills/). The PR links to issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677 and the description explains the rationale for each change. Human approval is always required for protected-path changes, regardless of context.

Low

  • [edge-case] eval/code/eval.yaml — The expected_files judge does not short-circuit when expect_pr is false. Currently harmless (case 002 does not declare expected_files), but if a future needs_input eval case accidentally declares expected_files, the judge would produce a confusing failure rather than a clear "no PR expected" message.

  • [test-coverage-gap] scripts/code-result-schema-test.sh — Missing schema test for needs_input combined with other optional fields (e.g., pr_body) but without target_branch, which would validate the conditional if/then logic for a non-obvious combination.

  • [injection] scripts/post-code.src.sh:297 — The existing_pr_url value from gh pr list is interpolated into the issue comment body without validation. The GitHub API constrains URLs to https://github.com/... format, making exploitation practically impossible; validating the URL pattern would add defense-in-depth.

  • [scope-drift] .gitignore — The addition of docs/plans/ to .gitignore is not mentioned in issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677 or the PR description.

  • [schema-breaking-change] schemas/code-result.schema.json — The target_branch field is no longer unconditionally required; it is conditionally required only when needs_input is absent (via JSON Schema if/then). The primary consumer (post-code.sh) is updated in this PR and already used // empty fallback handling.

Previous run (7)

Review

Findings

Medium

  • [protected-path] agents/code.md, harness/code.yaml, scripts/code-result-schema-test.sh, scripts/post-code-needs-input-test.sh, scripts/post-code.sh, scripts/post-code.src.sh, skills/code-implementation/SKILL.md — This PR modifies 7 files under protected paths (agents/, harness/, scripts/, skills/). The PR links to issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677 and the description explains the rationale for each change. Human approval is always required for protected-path changes, regardless of context.

  • [schema-breaking-change] schemas/code-result.schema.json — The target_branch field is no longer unconditionally required; it is conditionally required only when needs_input is absent (via JSON Schema if/then). Downstream consumers of agent-result.json that assume target_branch is always present will need to handle the conditional requirement. The primary consumer (post-code.sh) is updated in this PR.

Low

  • [edge-case] eval/code/eval.yaml — The expected_files judge does not short-circuit when expect_pr is false. Currently harmless (case 002 does not declare expected_files), but if a future needs_input eval case accidentally declares expected_files, the judge would produce a confusing failure rather than a clear "no PR expected" message.

  • [test-coverage-gap] scripts/code-result-schema-test.sh — Missing schema test for needs_input combined with other optional fields (e.g., pr_body) but without target_branch, which would validate the conditional if/then logic for a non-obvious combination.

  • [injection] scripts/post-code.src.sh:297 — The existing_pr_url value from gh pr list is interpolated into the issue comment body without validation. The GitHub API constrains URLs to https://github.com/... format, making exploitation practically impossible; validating the URL pattern would add defense-in-depth.

  • [injection] scripts/post-code.src.sh:246 — The label variable from CODE_NEEDS_INPUT_LABEL is not validated against a safe-charset regex before use in API calls and the comment body. The env var is controlled by the repository owner (acceptable trust boundary); validation would add defense-in-depth.

  • [scope-drift] .gitignore — The addition of docs/plans/ to .gitignore is not mentioned in issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677 or the PR description.

Previous run (8)

Review

Findings

Medium

  • [protected-path] agents/code.md, harness/code.yaml, scripts/code-result-schema-test.sh, scripts/post-code-needs-input-test.sh, scripts/post-code.sh, scripts/post-code.src.sh, skills/code-implementation/SKILL.md — This PR modifies 7 files under protected paths (agents/, harness/, scripts/, skills/). The PR links to issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677 and the description explains the rationale for each change. Human approval is always required for protected-path changes, regardless of context.

Low

  • [technical documentation accuracy] skills/code-implementation/SKILL.md:905 — Step 11 prose says the result file contains "target_branch (required) and optionally pr_body and closes_issue" but omits the newly added needs_input field. The schema compliance paragraph two lines later IS correctly updated to include needs_input. This inconsistency could mislead the agent into thinking needs_input is not an allowed field.
    Remediation: Update the prose to: "The file must be valid JSON with target_branch (required) and optionally pr_body, closes_issue, and needs_input:"
Previous run (9)

Review

Findings

Medium

  • [protected-path] agents/code.md, harness/code.yaml, scripts/code-result-schema-test.sh, scripts/post-code-needs-input-test.sh, scripts/post-code.sh, scripts/post-code.src.sh, skills/code-implementation/SKILL.md — This PR modifies 7 files under protected paths (agents/, harness/, scripts/, skills/). The PR links to issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677 and the description explains the rationale for each change. Human approval is always required for protected-path changes, regardless of context.

Low

  • [technical documentation accuracy] skills/code-implementation/SKILL.md:905 — Step 11 prose says the result file contains "target_branch (required) and optionally pr_body and closes_issue" but omits the newly added needs_input field. The schema compliance paragraph two lines later IS correctly updated to include needs_input. This inconsistency could mislead the agent into thinking needs_input is not an allowed field.
    Remediation: Update the prose to: "The file must be valid JSON with target_branch (required) and optionally pr_body, closes_issue, and needs_input:"
Previous run (10)

Review

Findings

Medium

  • [protected-path] agents/code.md, harness/code.yaml, scripts/code-result-schema-test.sh, scripts/post-code-needs-input-test.sh, scripts/post-code.sh, scripts/post-code.src.sh, skills/code-implementation/SKILL.md — This PR modifies 7 files under protected paths (agents/, harness/, scripts/, skills/). The PR links to issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677 and the description explains the rationale for each change. Human approval is always required for protected-path changes, regardless of context.

Low

  • [technical documentation accuracy] skills/code-implementation/SKILL.md:906 — Step 11 prose says the result file contains "target_branch (required) and optionally pr_body and closes_issue" but omits the newly added needs_input field. The schema compliance paragraph two lines later IS correctly updated to include needs_input. This inconsistency could mislead the agent into thinking needs_input is not an allowed field.
    Remediation: Update the prose to: "The file must be valid JSON with target_branch (required) and optionally pr_body, closes_issue, and needs_input:"
Previous run (11)

Review

Findings

Medium

  • [protected-path] agents/code.md, harness/code.yaml, scripts/code-result-schema-test.sh, scripts/post-code-needs-input-test.sh, scripts/post-code.sh, scripts/post-code.src.sh, skills/code-implementation/SKILL.md — This PR modifies 7 files under protected paths (agents/, harness/, scripts/, skills/). The PR links to issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677 and the description explains the rationale for each change. Human approval is always required for protected-path changes, regardless of context.

Low

  • [technical documentation accuracy] skills/code-implementation/SKILL.md:886 — Step 11 prose says the result file contains "target_branch (required) and optionally pr_body and closes_issue" but omits the newly added needs_input field. The schema compliance paragraph two lines later IS correctly updated to include needs_input. This inconsistency could mislead the agent into thinking needs_input is not an allowed field.
    Remediation: Update the prose to: "The file must be valid JSON with target_branch (required) and optionally pr_body, closes_issue, and needs_input:"

  • [scope-documentation-gap] skills/code-implementation/SKILL.md — Step 8 distinguishes "vague but actionable" from "genuinely uninterpretable" without concrete examples beyond the eval case (002-push-back-on-nonsense, which demonstrates contradictory requirements). The existing prose gives a reasonable heuristic ("explain why no conservative interpretation is safe"), but additional examples would reduce agent judgment variance.

Previous run (12)

Review

Findings

Medium

  • [protected-path] agents/code.md, harness/code.yaml, scripts/code-result-schema-test.sh, scripts/post-code-needs-input-test.sh, scripts/post-code.sh, scripts/post-code.src.sh, skills/code-implementation/SKILL.md — This PR modifies 7 files under protected paths (agents/, harness/, scripts/, skills/). The PR links to issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677 and the description explains the rationale for each change. Human approval is always required for protected-path changes, regardless of context.
Previous run (13)

Review

Findings

High

  • [logic error] skills/code-implementation/SKILL.md:896 — Step 11 (validate structured output) states "Only target_branch, pr_body, and closes_issue are allowed. Any other fields will cause validation to fail." This directly contradicts the new needs_input field added to the schema. When the agent writes needs_input and reaches step 11, this instruction tells it the field is disallowed, which could lead the agent to remove the field before validation — defeating the entire needs_input mechanism.
    Remediation: Update step 11 to list needs_input as an allowed optional property (e.g., "Only target_branch, pr_body, closes_issue, and needs_input are allowed.").

Medium

  • [schema-compatibility] schemas/code-result.schema.json:25 — Adding an optional field to a schema with additionalProperties: false is backward-incompatible if downstream consumers (e.g., the fullsend CLI) validate against an older copy of the schema. Old validators will reject outputs containing needs_input even though the field is optional. This creates a deployment ordering constraint.
    Remediation: Verify the fullsend CLI fetches this schema at runtime (no pinned copy), or coordinate deployment order: update the CLI’s schema copy before merging this PR.

  • [protected-path] agents/code.md, harness/code.yaml, scripts/post-code.sh, scripts/post-code.src.sh, scripts/code-result-schema-test.sh, scripts/post-code-needs-input-test.sh, skills/code-implementation/SKILL.md — This PR modifies 7 files under protected paths (agents/, harness/, scripts/, skills/). The PR links to issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677 and the description explains the rationale for each change. Human approval is always required for protected-path changes, regardless of context.

Low

  • [stale reference] skills/code-implementation/SKILL.md:637 — After replacing the "commit with disclosure" behavior with needs_input in step 9c, nearby text still says "If you cannot run the relevant test suite or lint command, you must disclose that." The phrasing assumes a commit-based disclosure, which is inconsistent with the new needs_input flow where the agent does NOT commit.
    Remediation: Update the text to reference needs_input as the expected action when the test/lint tool cannot run.

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:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR

fullsend-ai-review[bot]

This comment was marked as outdated.

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 scenarioschemas/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.

Comment thread scripts/post-code.src.sh Outdated
Comment thread scripts/post-code.src.sh
Comment thread scripts/post-code.src.sh
Comment thread eval/code/cases/002-push-back-on-nonsense/annotations.yaml
Comment thread docs/plans/code-agent-needs-input.md Outdated
@ralphbean

Copy link
Copy Markdown
Member Author

Re: #682 (comment)

Good catch on the schema-compliance line in SKILL.md step 11 — it still said only target_branch, pr_body, and closes_issue were allowed, which would've told the agent to strip needs_input right before validating. Fixed to list all four fields. Also updated the stale "you must disclose that" line near step 9c, which was left over from the old commit-with-disclosure behavior — it now points at needs_input instead.

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.

@ralphbean

Copy link
Copy Markdown
Member Author

Re: #682 (comment)

These four findings are the same ones raised inline — handled there: protected-path note dismissed as intentional, the needs-inputfs-code-needs-input label name fixed in agents/code.md, the pr_created judge tightened to reject any PR (not just open/merged) in the needs_input case, and warnings added to the label create/apply/remove calls.

ralphbean added a commit that referenced this pull request Aug 6, 2026
- 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>
ralphbean added a commit that referenced this pull request Aug 6, 2026
- 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>
@ralphbean

Copy link
Copy Markdown
Member Author

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 needs_input. I think that's fine: if you're pinning the CLI and workflow versions, you should be pinning the agent version too.

ralphbean added a commit that referenced this pull request Aug 6, 2026
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>
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 6, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 10:09 PM UTC · Completed 10:23 PM UTC
Commit: 6d90896 · View workflow run →

@fullsend-ai-review
fullsend-ai-review Bot dismissed their stale review August 6, 2026 22:23

Superseded by updated review

@fullsend-ai-review fullsend-ai-review Bot added the requires-manual-review Review requires human judgment label Aug 6, 2026
Comment thread scripts/post-code.sh
Comment thread scripts/post-code.sh Outdated
Comment thread skills/code-implementation/SKILL.md Outdated
ralphbean added a commit that referenced this pull request Aug 10, 2026
post_needs_input_comment's discarded-commits check silently fell back
to "main" when the gh api call for the repo's default branch failed.
If the actual default branch differs, the subsequent git rev-list
comparison silently reports zero commits ahead, dropping the
discarded-commits caveat this check exists to surface. Now it warns
via gha_echo when the API call fails, so the inaccuracy is visible in
the workflow log.

Addresses review feedback from waynesun09 on PR #682.

Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
ralphbean added a commit that referenced this pull request Aug 10, 2026
"one attempt only" for Makefile setup-target retries was an
unsubstantiated specific number. Softened to "a reasonable number of
attempts (typically one, more only if the failure looks transient)"
per review feedback, so the agent has room to judge transient vs.
persistent failures rather than following a hardcoded count with no
cited basis.

Addresses review feedback from waynesun09 on PR #682.

Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 10, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 4:21 PM UTC · Completed 4:37 PM UTC

Commit: ff3b608 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional review findings

[HIGH] scripts/post-code.src.sh:248 — PUSH_TOKEN log-masking is registered after the needs_input path already makes several PUSH_TOKEN-authenticated calls

(Not attachable inline: this line is unchanged code, outside the PR's diff hunks.)

echo "::add-mask::${PUSH_TOKEN}" at line 248 only executes after target-branch resolution, which is well past the if [ -n "${NEEDS_INPUT}" ]; then post_needs_input_comment "${NEEDS_INPUT}"; exit 0; fi block (lines 209-213). post_needs_input_comment calls _post_failure_ensure_token (exports GH_TOKEN=PUSH_TOKEN when unset) and then issues gh label create, two gh api .../labels calls, gh pr list, gh api repos/.../ --jq .default_branch, and gh issue comment, then exit 0s — none of these ever pass through the GitHub Actions log-mask registration for the token, since the exit happens before line 248 is reached. This script's own header explicitly calls out token handling as the reason it is "the most security-sensitive component in the pipeline," and needs_input is a normal, expected, exit-0 outcome this whole PR builds a workflow around — not a rare edge case — so this is now a routine, frequently-exercised path missing the log-redaction layer.

Suggestion: Move echo "::add-mask::${PUSH_TOKEN}" to immediately after : "${PUSH_TOKEN:?PUSH_TOKEN is required}" near the top of the script, before the ERR trap and before any code path (including post_needs_input_comment and the pre-existing early post_fail_to_issue calls that share the same gap) can use the token.

Comment thread harness/code.yaml
Comment thread scripts/post-code.src.sh Outdated
ralphbean added a commit that referenced this pull request Aug 10, 2026
…ame in comments

harness/code.yaml hardcoded CODE_NEEDS_INPUT_LABEL to the default label
instead of passing through the runner env var, silently defeating the
operator override the script and its tests expect.

post-code.src.sh interpolated the raw current_branch (chosen by the code
agent while processing potentially adversarial issue content) into a
public GitHub comment wrapped only in backticks. Git ref names permit
backticks, so a malicious branch name could break out of the markdown
code span and inject content into a comment posted with the bot's write
token. Validate current_branch against the same safe-charset regex used
for AGENT_TARGET and substitute a redacted placeholder when it fails,
while still using the real branch name for the underlying gh/git checks.

Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 10, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 7:12 PM UTC · Completed 7:29 PM UTC

Commit: c865235 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

ralphbean added a commit that referenced this pull request Aug 10, 2026
The passthrough broke CI: fullsend validates env.runner strictly and
errors if a referenced host variable is entirely unset, not just
empty. CODE_ALLOWED_TARGET_BRANCHES avoids this because
eval/scripts/run-fullsend.sh explicitly emits it (even empty).
CODE_NEEDS_INPUT_LABEL has no such emitter here, and no external
reusable workflow forwards it into the runner env either, so treating
it as an operator-configurable env var would break every production
run of the code agent, not just eval.

The label is still configurable the same way CODE_NEEDS_INPUT_LABEL
plumbing exists for at all: operators fork/edit harness/code.yaml
directly to change the literal value. The script's own
:-fs-code-needs-input fallback and its env-override test are unrelated
to the harness and remain valid on their own.

Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
The post-code-needs-input-test.sh script runs the real post-code.src.sh
which calls gitleaks inside post_needs_input_comment() — but gitleaks
is installed later by install_gitleaks(), well past the needs_input
early-exit path. On CI runners where gitleaks is not pre-installed,
the scan fails with exit 127 and the content is replaced with a
generic redacted message, breaking test assertions that check for the
original needs_input text.

- Add a mock gitleaks binary (exit 0, no secrets) to MOCK_BIN in the
  test, matching the existing gh mock pattern
- Add CODE_NEEDS_INPUT_LABEL to eval/scripts/run-fullsend.sh env file
  for code/fix agents (empty = use default), matching the pattern of
  CODE_ALLOWED_TARGET_BRANCHES

Addresses review feedback on #682
post_needs_input_comment() calls gitleaks detect to scan the
needs_input text, but install_gitleaks was only called in step 3 —
after the needs_input early-exit.  On CI runners without a
pre-installed gitleaks binary, the scan failed with exit 127 and
the content was silently replaced with a generic redacted message.

Fix: call install_gitleaks inside post_needs_input_comment before
the gitleaks detect call (no-op when already on PATH).  Remove the
gitleaks mock from post-code-needs-input-test.sh since the script
now properly ensures the binary is available.

Addresses review feedback on #682
…ebase

The rebase onto main picked up the multi-forge change (PR #813) which
requires FULLSEND_FORGE to be set. The needs-input test was missing
this env var, causing all test invocations to fail with
"invalid FULLSEND_FORGE" at script load time.

Also resolves merge conflicts from the rebase:
- harness/code.yaml: kept both CODE_NEEDS_INPUT_LABEL (PR) and sandbox
  env vars (main)
- scripts/post-code.sh, post-code.src.sh: merged GITLAB_TOKEN masking
  (main) with early PUSH_TOKEN masking (PR)

Addresses review feedback on #682
- Validate existing_pr_url through _sanitize_workflow_value and a
  safe-charset regex before interpolating into the needs_input issue
  comment body (defense-in-depth, per waynesun09 review finding).
- Short-circuit expected_files eval judge when expect_pr is false
  so a future needs_input case accidentally declaring expected_files
  produces a clear error instead of a confusing PR-files failure.
- Add schema test for needs_input combined with pr_body but without
  target_branch, exercising the conditional if/then logic.

Addresses review feedback on #682
- Remove the current_branch != default_branch gate so commits_ahead is
  checked even when the agent stays on the default branch
- Replace || echo 0 with explicit git failure detection so a rev-list
  error is logged instead of silently reporting 0 commits
- Add git status --porcelain check for uncommitted working-tree changes
  that would be silently discarded
- Validate CODE_NEEDS_INPUT_LABEL against a safe-charset regex before
  use in API calls and comment body interpolation
- Add gitleaks mock to needs-input tests so they pass on CI runners
  without a pre-installed gitleaks binary
- Fix long-text test fixture to use real newlines (via jq) instead of
  relying on JSON \n escape interpretation through the bash→jq chain

Addresses review feedback on #682
@fullsend-ai-coder

Copy link
Copy Markdown
Contributor

🔧 Fix agent — iteration 9 (human-triggered)

Fixed validation failure caused by Signed-off-by trailers in 8 of 16 PR commits. The pre-commit gate checks all commits in the merge-base..HEAD range for Signed-off-by trailers and rejects them for agent branches. Used git filter-branch with a sed-based msg-filter to remove all Signed-off-by lines from the commit messages while preserving the rest of the commit history and content.

Fixed (1):

  1. Rebase on main and resolve merge conflicts: Rebased the branch on main (previous iteration) and stripped Signed-off-by trailers from all PR commits using git filter-branch --msg-filter to pass the pre-commit gate validation.

Tests: passed

Decision points
  • Used git filter-branch --msg-filter to strip Signed-off-by trailers from all 16 PR commits rather than squashing or cherry-picking. (alternatives: Squash all commits into one without the trailer, Interactive rebase to edit each commit message individually, Cherry-pick each commit with a new message; rationale: filter-branch preserves the full commit history and authorship while surgically removing only the Signed-off-by lines. Interactive rebase is not supported (no -i flag allowed), and squashing would lose the granular commit history.)

Next steps:

  • /fs-review — request a re-review of the changes
  • /fs-fix <your instruction> — run another fix pass with specific guidance
  • Push commits directly — review re-runs automatically on push
    Updated by fullsend fix agent

@fullsend-ai-coder
fullsend-ai-coder Bot force-pushed the feat/677-code-needs-input branch from 1d6862f to 4b23170 Compare August 24, 2026 20:09
@fullsend-ai-review

fullsend-ai-review Bot commented Aug 24, 2026

Copy link
Copy Markdown

🤖 Review · ❌ Terminated · Started 8:11 PM UTC · Ended 8:29 PM UTC

Commit: 4b23170 · View workflow run →

@ralphbean

Copy link
Copy Markdown
Member Author

/fs-fix address comments from @waynesun09

@fullsend-ai-coder

fullsend-ai-coder Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

🤖 Finished Fix · ✅ Success · Started 8:21 PM UTC · Completed 8:40 PM UTC

Commit: 4b23170 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $7.13

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot removed the requires-manual-review Review requires human judgment label Aug 24, 2026
@fullsend-ai-review

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 8:11 PM UTC · Completed 8:29 PM UTC

Commit: 4b23170 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $10.67

- Convert post_needs_input_comment to use forge helpers
  (forge_create_label, forge_add_label, forge_remove_label,
  forge_list_prs_for_branch, forge_get_pr_url,
  forge_post_issue_comment, forge_get_default_branch) so the
  needs_input path works on both GitHub and GitLab instead of
  silently no-oping on GitLab via direct gh calls.
- Add forge_remove_label to both github-code-ops.lib.sh and
  gitlab-code-ops.lib.sh following the forge_add_label pattern.
- Use forge_list_prs_for_branch (with headRepositoryOwner /
  source_project_id filter) for the existing-PR check, fixing
  the cross-fork false-positive.
- Use agent's target_branch from RESULT_FILE as the comparison
  base for discarded-commits guard instead of always using the
  repo default branch, fixing false counts on non-default targets.
- Use git status --porcelain --untracked-files=no so untracked
  files (build artifacts from make setup) don't trigger the
  conflict label.
- Add fs-code-needs-input-conflict label to docs/code.md Control
  labels table.
- Update CODE_NEEDS_INPUT_LABEL docs to reflect it's hardcoded in
  harness/code.yaml, not forwarded from runner env.
- Remove dead emit_env CODE_NEEDS_INPUT_LABEL from eval runner.
- Add ready-to-code to forbidden labels in case 002 annotations.
- Neutralize test_calc.py assertions (signature-only checks) so
  the fixture doesn't bias toward one side of the contradiction.
- Restore two-message split in pr_created judge for the
  expect_pr:true branch (distinguishes "no PRs" from "PRs present
  but none open/merged").
- Add untracked-files-only test case to confirm no false conflict.
- Update test mock to handle forge helper gh call patterns.

Addresses review feedback on #682
@fullsend-ai-coder

Copy link
Copy Markdown
Contributor

🔧 Fix agent — iteration 9 (human-triggered)

Addressed 9 remaining review findings from @waynesun09. Key changes: converted post_needs_input_comment from direct gh calls to forge helpers (works on both GitHub and GitLab), added forge_remove_label to both forge libs, fixed cross-fork owner filter, used agent's target_branch for discarded-commits comparison, excluded untracked files from dirty-tree check, documented the conflict label, corrected CODE_NEEDS_INPUT_LABEL docs, added ready-to-code to forbidden labels, neutralized fixture test assertions, and restored the pr_created judge's two-message diagnostic. Disagreed with 1 finding (capture-fixture fallback) as out of PR scope.

Fixed (9):

  1. needs_input path is GitHub-only and silently no-ops on GitLab (scripts/post-code.src.sh): Converted all direct gh calls in post_needs_input_comment to forge helpers (forge_create_label, forge_add_label, forge_remove_label, forge_list_prs_for_branch, forge_get_pr_url, forge_post_issue_comment, forge_get_default_branch). Added forge_remove_label to both github-code-ops.lib.sh and gitlab-code-ops.lib.sh. The needs_input path now works on both GitHub and GitLab.
  2. needs_input existing-PR check omits cross-fork owner filter (scripts/post-code.src.sh): Replaced raw gh pr list with forge_list_prs_for_branch which includes the headRepositoryOwner filter (GitHub) / source_project_id filter (GitLab) to avoid matching a same-named branch from an unrelated fork.
  3. Discarded-commits guard counts against the default branch, not the agent's target branch (scripts/post-code.src.sh): post_needs_input_comment now accepts agent_target as a second parameter. When target_branch is set in RESULT_FILE, it is used as the comparison base for the commits-ahead check instead of the repo default branch, fixing false counts when the agent branched from a non-default branch like 'develop'.
  4. git status --porcelain counts untracked files, false-positiving the conflict label (scripts/post-code.src.sh): Changed to git status --porcelain --untracked-files=no so untracked files (build artifacts from make setup, .venv/, node_modules/) do not trigger the conflict label. Added a test case confirming untracked-only files do not cause a false positive.
  5. fs-code-needs-input-conflict label undocumented (docs/code.md): Added a row to the Control labels table documenting the conflict label, its purpose, and its derivation from CODE_NEEDS_INPUT_LABEL.
  6. docs still document CODE_NEEDS_INPUT_LABEL as runner-forwarded after passthrough was reverted (docs/code.md): Updated the CODE_NEEDS_INPUT_LABEL docs row to state the value is hardcoded in harness/code.yaml, overridden by editing that file or via base: composition, not forwarded from the runner environment. Also removed the dead emit_env CODE_NEEDS_INPUT_LABEL line from eval/scripts/run-fullsend.sh.
  7. forbidden list doesn't assert ready-to-code was removed (eval/code/cases/002-push-back-on-nonsense/annotations.yaml): Added ready-to-code to the forbidden labels list so the eval catches a regression where needs_input is set but ready-to-code is left behind.
  8. Fixture still asserts one specific answer to the stated contradiction (eval/code/repos/tiny-calc-neutral/tests/test_calc.py): Replaced behavioral assertions (add(2,3)==5) with signature-only checks (isinstance(result, int)) so neither the implementation nor the tests favor one side of the contradiction the eval case is designed to test.
  9. pr_created judge lost the 'PRs present but none open/merged' diagnostic (eval/code/eval.yaml): Restored the two-message split in the expect_pr:true branch: 'No pull requests found' when prs is empty, vs 'PRs present but none open/merged' with the PR list when PRs exist but none are OPEN/MERGED.

Disagreed (1):

  1. capture-fixture's best-effort [] fallback makes case 002's expect_pr:false assertion pass vacuously on API failure: eval/scripts/capture-fixture.sh is not in this PR's diff and the change (adding a pull_requests_fetch_failed marker) is infrastructure work outside the scope of the needs_input feature. Should be addressed in a separate PR.

Tests: passed

Next steps:

  • /fs-review — request a re-review of the changes
  • /fs-fix <your instruction> — run another fix pass with specific guidance
  • Push commits directly — review re-runs automatically on push
    Updated by fullsend fix agent

@fullsend-ai-review

fullsend-ai-review Bot commented Aug 24, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 8:42 PM UTC · Completed 9:00 PM UTC

Commit: bc153b9 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $9.06

@fullsend-ai-review
fullsend-ai-review Bot dismissed their stale review August 24, 2026 21:00

Superseded by updated review

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot added the requires-manual-review Review requires human judgment label Aug 24, 2026
@ralphbean

Copy link
Copy Markdown
Member Author

/fs-fix

@fullsend-ai-coder

fullsend-ai-coder Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

🤖 Finished Fix · ✅ Success · Started 9:24 PM UTC · Completed 9:36 PM UTC

Commit: bc153b9 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $2.74

- Remove docs/plans/ from .gitignore (scope-creep: unrelated to #677)
- Clarify SKILL.md step 11: target_branch is required unless needs_input
  is set, matching the schema's if/then clause
- URL-encode label in forge_remove_label() to handle spaces in label
  names (github-code-ops.lib.sh + rebuilt bundles)

Addresses review feedback on #682
@fullsend-ai-coder

Copy link
Copy Markdown
Contributor

🔧 Fix agent — iteration 10 (human-triggered)

Addressed 3 of 5 low-severity review findings: removed scope-creep .gitignore entry, clarified conditional target_branch requirement in SKILL.md, and URL-encoded labels in forge_remove_label(). Disagreed with 2 findings (bundled script artifact, mock pattern fragility) as not actionable.

Fixed (3):

  1. docs/plans/ in .gitignore is scope-creep unrelated to Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677 (.gitignore): Removed docs/plans/ entry from .gitignore since it is not part of issue Code agent needs a structured way to say 'needs human input' instead of silently no-oping #677 scope
  2. SKILL.md states target_branch is required without qualifying the if/then conditional (skills/code-implementation/SKILL.md): Updated step 11 prose to say target_branch is required unless needs_input is set, matching the schema's if/then clause
  3. forge_remove_label() does not URL-encode label name in API path (scripts/lib/github-code-ops.lib.sh): Added URL encoding via jq @uri for the label parameter in forge_remove_label() so labels containing spaces or special characters produce valid API URLs. Rebuilt bundled scripts.

Disagreed (2):

  1. forge_remove_label() defined in pre-code.sh but never called there: pre-code.sh is a generated build artifact (GENERATED from pre-code.src.sh — DO NOT EDIT). The bundler includes all functions from the shared github-code-ops.lib.sh regardless of whether each script calls them. Selectively excluding functions would break the bundling pattern and is not how the build system works.
  2. Mock gh script matches forge_list_prs_for_branch calls using a fixed argument pattern: Argument-pattern-based mocking is inherently coupled to the implementation. The mock already documents which patterns it matches with inline comments. No actionable fix exists without replacing the mock framework entirely, which is out of scope for this PR.

Tests: passed

Next steps:

  • /fs-review — request a re-review of the changes
  • /fs-fix <your instruction> — run another fix pass with specific guidance
  • Push commits directly — review re-runs automatically on push
    Updated by fullsend fix agent

@fullsend-ai-review

fullsend-ai-review Bot commented Aug 24, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 9:37 PM UTC · Completed 10:14 PM UTC

Commit: d198257 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $7.76

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the review comment for full details.

echo "main"
;;
*"pr list --repo ${REPO_FULL_NAME} --head"*"--json number,headRepositoryOwner"*)
# forge_list_prs_for_branch — return PR number

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[low] test-coverage

The mock gh script matches forge_list_prs_for_branch calls using a fixed argument pattern. If arguments are reordered in a future refactor, the mock silently stops matching and existing-PR test assertions pass vacuously. Inherent to pattern-based mocking and acceptable, but a regression risk.

Comment thread scripts/pre-code.sh
fi
}

forge_remove_label() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[low] scope-creep

forge_remove_label() is defined in pre-code.sh (both GitHub and GitLab sections) but never called there. Build-system artifact from bundling the shared lib files, not intentional scope creep.

@ralphbean

Copy link
Copy Markdown
Member Author

/fs-fix address findings with obvious resolution

@fullsend-ai-coder

fullsend-ai-coder Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

🤖 Finished Fix · ❌ Failure · Started 1:36 AM UTC · Completed 1:36 AM UTC

Commit: d198257 · View workflow run →

Effort: high

@ralphbean

Copy link
Copy Markdown
Member Author

/fs-fix

@fullsend-ai-coder

fullsend-ai-coder Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

🤖 Finished Fix · ❌ Failure · Started 12:02 PM UTC · Completed 12:02 PM UTC

Commit: d198257 · View workflow run →

Effort: high

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] validate-code-output.src.sh has no needs_input awareness, so a contract-violation pushback can be swallowed by the pre-commit retry loop instead of surfacing (scripts/validate-code-output.src.sh:113, not in this PR's diff so posting here instead of inline)

needs_input does not appear anywhere in scripts/validate-code-output.src.sh (confirmed by grep at head) and the file is untouched by this PR's diff — the needs_input feature this PR adds was never wired into this consumer. This is the validation_loop.script for the code harness; per ADR 0022 (referenced elsewhere in this same PR's own eval.yaml judge docstring), the post-script — where post_needs_input_comment lives — only runs after validation_loop passes. If the agent leaves the working tree in a state that fails the pre-commit gate (dirty/committed changes that don't pass hooks) while also setting needs_input in agent-result.json (schema-valid: needs_input is accepted alone per schemas/code-result.schema.json's if/then, target_branch not required), Part 2 of this script still runs the pre-commit gate against TARGET_REPO_DIR, fails, and returns exit 1 with a generic "FAIL: pre-commit-blocked" message that feeds back into another retry iteration — the needs_input signal is never read, so the human never sees the pushback and the run burns turns/cost instead of surfacing the exact contract-violation scenario this PR was built to catch. The clean/no-work path is unaffected (no changes -> CHANGED_FILES empty -> gate skipped).

Suggestion: have validate-code-output.src.sh read needs_input from RESULT_FILE (already parsed for target_branch) early in Part 2 and soft-pass (skip) the pre-commit gate when it's non-empty, so the post-script always runs and post_needs_input_comment's own contract-violation handling gets a chance to fire.

Comment thread scripts/post-code.src.sh
sed 's/^/::debug::gitleaks: /' "${gl_stderr}"
fi
rm -f "${gl_stderr}"
if [ "${gl_rc}" -eq 1 ]; then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] needs_input secret-scan misattributes generic gitleaks errors as "secret detected"

post_needs_input_comment() branches gl_rc -eq 1 -> "BLOCKED — secret detected" vs gl_rc -gt 1 -> "scan failed" (this line through 401). Empirically verified against the pinned gitleaks v8.30.1 binary (built via this repo's own scripts/lib/gitleaks-install.lib.sh): gitleaks detect --source /nonexistent/path --no-git --redact — a plain file-stat error, not a leak — exits 1, identically to a genuine finding; only an unknown-flag error exits 126. So a transient tmpfile/permissions/internal gitleaks error on this path will almost always land in the -eq 1 branch and post "the agent's explanation contained a potential secret" to the issue when no secret exists. Content is redacted either way (no security regression), but the diagnostic is misleading.

Note: this is not a new deviation invented by this PR — the pre-existing pr_body scan later in the same file (around line 867, same GL_RC eq-1/gt-1 split) does the identical thing, so this new code faithfully copied a pre-existing misclassification rather than introducing a new one.

Suggestion: either inspect gitleaks' JSON report (--report-format json) to positively confirm a finding rather than inferring from exit code, or soften the exit-1 message to acknowledge it could be either a finding or a scan error. Consider applying the same fix to the pre-existing pr_body scan for consistency, since it has the identical ambiguity.

labels:
required:
- fs-code-needs-input
forbidden:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] Eval case 002 does not forbid the fs-code-needs-input-conflict label, letting a dirty pushback pass

labels.forbidden is [ready-to-code] only. The case requires fs-code-needs-input and asserts expect_pr: false, but never forbids <CODE_NEEDS_INPUT_LABEL>-conflict (default fs-code-needs-input-conflict). An agent that leaves an uncommitted-only partial fix (which skips the pre-commit gate entirely since validate-code-output's CHANGED_FILES check only sees committed diffs) and sets needs_input would trip post_needs_input_comment's own dirty-tree caveat, get the -conflict label applied, open no PR, keep the required fs-code-needs-input label — and pass this eval case regardless, since neither pr_created, required_labels, nor forbidden_labels inspects the conflict label. This is distinct from the existing thread on this same file (the one about ready-to-code never being asserted-removed) — that thread does not mention the conflict label.

Suggestion: add fs-code-needs-input-conflict (or <CODE_NEEDS_INPUT_LABEL>-conflict) to labels.forbidden in this case's annotations.yaml so a contract-violating pushback fails the eval instead of passing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

code-agent requires-manual-review Review requires human judgment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Code agent needs a structured way to say 'needs human input' instead of silently no-oping

3 participants