Skip to content

docs(#2345): ADR 0053 — agent-driven branch targeting for code agent - #2346

Merged
ralphbean merged 12 commits into
fullsend-ai:mainfrom
Marcusk19:fix/dynamic-target-branch
Jun 22, 2026
Merged

docs(#2345): ADR 0053 — agent-driven branch targeting for code agent#2346
ralphbean merged 12 commits into
fullsend-ai:mainfrom
Marcusk19:fix/dynamic-target-branch

Conversation

@Marcusk19

@Marcusk19 Marcusk19 commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Proposes ADR 0047: move branch-targeting logic from the hardcoded TARGET_BRANCH: main workflow env var to agent-driven selection with post-script policy enforcement.

  • Agent determines target branch from issue context, writes it to code-result.json (structured output)
  • Post-script validates the agent's choice against CODE_ALLOWED_TARGET_BRANCHES (or auto-detected default)
  • Workflow no longer contains branch-targeting business logic (portable to non-GHA environments)

Motivation

  • TARGET_BRANCH: main is hardcoded in reusable-code.yml, breaking repos with non-main default branches (example failure)
  • The agent understands the target better than the workflow (issue context says "set up builds on the 3.18 branch")
  • Business logic in GitHub Actions workflows is not portable to future execution environments (k8s pods)

Changes

  • docs/ADRs/0047-agent-driven-branch-targeting.md — the ADR (Proposed status)
  • Reverts the previous workflow-level fix in favor of the ADR approach

Design summary

See ADR 0047 for full details. Key points:

  1. New schemas/code-result.schema.json with target_branch field
  2. Post-script reads agent output, validates against CODE_ALLOWED_TARGET_BRANCHES
  3. Falls back to auto-detected default branch when no agent output
  4. Harness wires up structured output and removes TARGET_BRANCH from runner_env

Closes #2345

@fullsend-ai-review

fullsend-ai-review Bot commented Jun 16, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 6:31 PM UTC · Completed 6:42 PM UTC
Commit: f467d6b · View workflow run →

@fullsend-ai-review

fullsend-ai-review Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review

Findings

High

  • [missing-documentation] docs/agents/code.md — Per ADR 0049, agent configuration environment variables must be documented in docs/agents/<agent>.md. CODE_ALLOWED_TARGET_BRANCHES is a user-facing configuration variable introduced by this PR but is not documented there. The Variables section currently says "None." Undocumented config vars are undiscoverable by users who need to restrict which branches agents may target.

Medium

  • [protected-path] .github/workflows/reusable-code.yml — This file is under the .github/ protected path. The PR links to issue Code agent hardcodes TARGET_BRANCH to main, breaking repos with non-main default branches #2345 and explains the rationale (replacing hardcoded TARGET_BRANCH: main with agent-driven branch targeting per ADR 0053). Human approval is required for protected-path changes regardless of context.

  • [scope-exceeded] docs/ADRs/0053-agent-driven-branch-targeting.md — Issue Code agent hardcodes TARGET_BRANCH to main, breaking repos with non-main default branches #2345 requests auto-detection of the default branch with an optional override via --branch flag. The ADR proposes agent-driven selection where the agent writes a target branch to structured output. The PR does implement auto-detection as the default fallback path, but agent-driven selection is an additional capability beyond the issue's authorization. This is a design choice that merits human review.

  • [design-direction] docs/ADRs/0053-agent-driven-branch-targeting.md — ADR 0053 proposes the agent writes a target branch to structured output, which the post-script then reads and validates. The existing pattern (demonstrated by the fix agent) flows configuration downward: the workflow resolves the base ref, then passes TARGET_BRANCH to the harness as configuration. The new pattern has the agent produce configuration that the post-script consumes, which inverts the established control flow direction.

  • [breaking-env-contract] internal/scaffold/fullsend-repo/harness/code.yaml:45 — Removal of TARGET_BRANCH from runner_env breaks enrolled repos with customized code.yaml files that still reference ${TARGET_BRANCH}. ValidateRunnerEnvWith in harness.go checks os.LookupEnv for all ${VAR} references, so a customized harness containing TARGET_BRANCH: "${TARGET_BRANCH}" will fail validation because the workflow no longer provides this variable. ADR 0053 documents this as a consequence with concrete before/after YAML, but does not provide automated detection or a deprecation period.

Low

  • [stale-reference] docs/plans/adr-0045-forge-portable-harness-phase2.md:130 — Phase 2 implementation plan lists TARGET_BRANCH as a top-level runner_env variable for code.yaml (lines 117, 130, 142). After this PR, code.yaml replaces TARGET_BRANCH with CODE_ALLOWED_TARGET_BRANCHES. This is a planning document so impact is limited, but it could mislead future contributors consulting it.

  • [edge-case] internal/scaffold/fullsend-repo/scripts/post-code.sh:82 — The comma-separated allowlist matching does not handle whitespace in entries. When CODE_ALLOWED_TARGET_BRANCHES is set to 'main, develop' (with a space), the grep -qF check will fail for develop because ', develop,' does not match ',develop,'. Document that the list must not contain spaces, or strip whitespace before matching.

  • [wildcard-allowlist] internal/scaffold/fullsend-repo/scripts/post-code.sh — The allowlist supports * as a value for CODE_ALLOWED_TARGET_BRANCHES, which permits the agent to target any branch. The regex validation constrains branch names to ^[a-zA-Z0-9._/-]+$ and PR creation still requires review/merge approval, limiting the attack surface. The wildcard is an intentional, documented design choice.

  • [error-message-format] internal/scaffold/fullsend-repo/scripts/post-code.sh — Error messages in the new branch resolution logic use plain echo instead of the established ::error:: GHA annotation format used elsewhere in the script (e.g., lines 218-220, 282-284, 340-341).

  • [stale-reference] skills/spec-start-github/SKILL.md:27 — The spec-start-github skill references TARGET_BRANCH as an optional input variable (line 27) and uses it for branching (line 51). This skill is for the spec agent (not the code agent), so it may remain valid independently, but is noted for awareness.

  • [naming-convention] internal/scaffold/fullsend-repo/harness/code.yamlCODE_ALLOWED_TARGET_BRANCHES uses an agent-type prefix (CODE_) that no other runner_env variable currently uses. ADR 0049 prescribes this convention for agent config vars, so this may be the first adopter rather than an inconsistency.

Previous run

Review

Findings

Medium

  • [protected-path] .github/workflows/reusable-code.yml, harness/code.yaml, scripts/post-code.sh, skills/code-implementation/SKILL.md — This PR modifies files under four protected paths: .github/, harness/, scripts/, and skills/. The PR links to issue Code agent hardcodes TARGET_BRANCH to main, breaking repos with non-main default branches #2345 and explains the rationale (replacing hardcoded TARGET_BRANCH: main with agent-driven branch targeting per ADR 0053). Human approval is required for protected-path changes regardless of context.

  • [breaking-env-contract] internal/scaffold/fullsend-repo/harness/code.yaml:45 — Removal of TARGET_BRANCH from runner_env breaks enrolled repos with customized code.yaml files that still reference ${TARGET_BRANCH}. ValidateRunnerEnvWith in harness.go checks os.LookupEnv for all ${VAR} references, so a customized harness containing TARGET_BRANCH: "${TARGET_BRANCH}" will fail validation because the workflow no longer provides this variable. ADR 0053 documents this as a consequence with concrete before/after YAML, but does not provide automated detection or a deprecation period.

Low

  • [stale-reference] docs/plans/adr-0045-forge-portable-harness-phase2.md:130 — Phase 2 implementation plan lists TARGET_BRANCH as a top-level runner_env variable for code.yaml (lines 117, 130, 142). After this PR, code.yaml replaces TARGET_BRANCH with CODE_ALLOWED_TARGET_BRANCHES. This is a planning document so impact is limited, but it could mislead future contributors consulting it.

  • [edge-case] internal/scaffold/fullsend-repo/scripts/post-code.sh:82 — The comma-separated allowlist matching does not handle whitespace in entries. When CODE_ALLOWED_TARGET_BRANCHES is set to main, develop (with a space), the grep -qF check will fail for develop because , develop, does not match ,develop,. Document that the list must not contain spaces, or strip whitespace before matching.

  • [documentation-completeness] docs/agents/code.mdCODE_ALLOWED_TARGET_BRANCHES is a user-facing configuration variable (repos can set it to restrict allowed target branches) but is not documented in docs/agents/code.md. The Variables section currently says "None." Per ADR 0049 convention, agent config vars should be documented there.

Previous run (2)

Review

Reason: stale-head

The review agent reviewed commit 9070c779f2f154c204d82a1725c69379e8a40856 but the PR HEAD is now af03ca70a989c88f63a1bd0465e997a376515d3a. This review was discarded to avoid approving unreviewed code.

Previous run (3)

Review

Findings

Medium

  • [protected-path] .github/workflows/reusable-code.yml — This file is under the .github/ protected path. The PR links to issue Code agent hardcodes TARGET_BRANCH to main, breaking repos with non-main default branches #2345 and explains the rationale (replacing hardcoded TARGET_BRANCH: main with agent-driven branch targeting). Human approval is required for protected-path changes regardless of context.

  • [stale-reference] docs/plans/adr-0045-forge-portable-harness-phase2.md:130 — Lines 117, 130, and 142 describe TARGET_BRANCH as remaining at the top level of code.yaml's runner_env. This PR replaces TARGET_BRANCH with CODE_ALLOWED_TARGET_BRANCHES, FULLSEND_OUTPUT_SCHEMA, and FULLSEND_OUTPUT_FILE. The plan document now contradicts the actual scaffold template.

Low

  • [fail-open] .github/workflows/reusable-code.yml:182 — The gh api fallback || echo 'main' for default branch detection could silently target the wrong branch in repos whose default is not main. This is the exact problem the PR aims to fix, and while the API failure path is unlikely, a warning log when the fallback triggers would improve observability.

  • [edge-case] internal/scaffold/fullsend-repo/scripts/post-code.sh:82 — The post-script validates the agent's chosen branch against the allowlist but does not verify the branch actually exists in the remote repository. If the agent specifies a nonexistent but allowed branch, gh pr create --base will fail with a confusing GitHub API error rather than a clear validation message.

  • [injection] internal/scaffold/fullsend-repo/scripts/post-code.sh:82 — Defense-in-depth gap: AGENT_TARGET is validated with regex ^[a-zA-Z0-9._/-]+$ in the post-script, which is the sole enforcement point — the code agent harness has no validation_loop, so the JSON schema's pattern constraint is never enforced before the post-script runs. The regex is adequate to prevent injection, but the gap between schema-declared and actually-enforced validation is worth documenting.

  • [naming-convention] internal/scaffold/fullsend-repo/harness/code.yaml:45CODE_ALLOWED_TARGET_BRANCHES uses plural where the existing pattern uses singular (TARGET_BRANCH). The plural is semantically correct for a comma-separated allowlist but diverges from established naming.

  • [documentation-completeness] docs/agents/code.md — The file's Variables section currently says "None." If CODE_ALLOWED_TARGET_BRANCHES is a user-facing configuration variable, it should be documented there per ADR 0049 convention.

Previous run (4)

Review

Findings

Critical

  • [runtime-mechanism] internal/scaffold/fullsend-repo/harness/code.yaml:45CODE_ALLOWED_TARGET_BRANCHES is referenced via ${CODE_ALLOWED_TARGET_BRANCHES} in runner_env but is never set in the workflow env. The PR removes TARGET_BRANCH: main from reusable-code.yml without adding CODE_ALLOWED_TARGET_BRANCHES to the step env. ValidateRunnerEnvWith in harness.go:493 checks that every ${VAR} reference in runner_env is defined in the host environment via os.LookupEnv. The lookup function in run.go:313-318 only special-cases FULLSEND_DIR; all other vars use os.LookupEnv. Since CODE_ALLOWED_TARGET_BRANCHES is not set, validation will fail with host variable CODE_ALLOWED_TARGET_BRANCHES is not set, preventing the code agent from running entirely. This was flagged in the prior review and remains unaddressed.
    Remediation: Either (1) add CODE_ALLOWED_TARGET_BRANCHES: '' to the workflow env in reusable-code.yml, or (2) change the harness value to a literal empty string default instead of a ${...} reference, or (3) add a special case in run.go's lookup function similar to FULLSEND_DIR. Option 2 is recommended since the variable is intentionally optional.

High

  • [breaking-env-contract] internal/scaffold/fullsend-repo/harness/code.yaml:45 — Removal of TARGET_BRANCH from runner_env breaks enrolled repos with customized harness/code.yaml files. When orgs copy the upstream harness to customized/harness/code.yaml (per ADR 0035 layered resolution), they get a complete file replacement. If their customized harness still references ${TARGET_BRANCH} in runner_env, the ValidateRunnerEnvWith() check will fail because the workflow no longer provides TARGET_BRANCH.
    Remediation: Add migration guidance to the ADR or release notes with concrete before/after examples for customized harness files. Consider adding detection in fullsend admin install --upgrade to scan customized dirs for TARGET_BRANCH references.

Medium

  • [internal-consistency] internal/scaffold/fullsend-repo/scripts/post-code.sh:65 — The comment in the branch resolution block says ADR 0047 but the ADR file added by this PR is numbered 0051 (docs/ADRs/0051-agent-driven-branch-targeting.md). ADR 0047 is 0047-vendored-installs-with-vendor-flag.md, which is unrelated to branch targeting.

  • [stale-reference] docs/plans/adr-0045-forge-portable-harness-phase2.md:130 — Stale reference to removed TARGET_BRANCH. Lines 117, 130, and 142 describe TARGET_BRANCH as remaining at the top level of code.yaml's runner_env. After this PR, code.yaml replaces TARGET_BRANCH with CODE_ALLOWED_TARGET_BRANCHES.

  • [missing-migration-guidance] docs/ADRs/0051-agent-driven-branch-targeting.md — The ADR's Consequences section mentions that repos with customized code.yaml must update, but does not provide step-by-step migration instructions or a detection mechanism.

  • [protected-path] .github/workflows/reusable-code.yml — This file is under the .github/ protected path. The PR links to issue Code agent hardcodes TARGET_BRANCH to main, breaking repos with non-main default branches #2345 and explains the rationale (fixing hardcoded TARGET_BRANCH: main for repos with non-main default branches). Human approval is required for protected-path changes regardless of context.

Low

  • [edge-case] internal/scaffold/fullsend-repo/scripts/post-code.sh:82 — The post-script validates the agent's chosen branch against the allowlist but does not verify the branch actually exists in the remote repository. If the agent specifies a nonexistent but allowed branch, gh pr create --base will fail with a confusing GitHub API error.

  • [injection] internal/scaffold/fullsend-repo/scripts/post-code.sh:82 — Defense-in-depth gap: AGENT_TARGET is read from agent-produced code-result.json via jq -r without re-validating the character set. The code agent harness has no validation_loop, so the JSON schema's ^[a-zA-Z0-9._/-]+$ pattern is not enforced before the post-script runs. When CODE_ALLOWED_TARGET_BRANCHES='*', AGENT_TARGET bypasses allowlist validation and flows into TARGET_BRANCH.

  • [title-adr-mismatch] PR metadata — PR title references 'ADR 0047' but the diff adds ADR 0051. ADR 0047 is 0047-vendored-installs-with-vendor-flag.md (unrelated). Update the PR title to reference ADR 0051.

  • [naming-convention] internal/scaffold/fullsend-repo/harness/code.yaml:45 — Variable name uses plural BRANCHES where the existing pattern uses singular (TARGET_BRANCH). The plural is semantically correct (comma-separated list), but diverges from established naming.

  • [documentation-completeness] docs/architecture.mdAGENTS.md is not updated to reflect the new structured output contract for the code agent.

  • [missing-version-bump] internal/scaffold/fullsend-repo/schemas/code-result.schema.json — New structured output schema introduced without a version field. Other schemas (triage-result, review-result, etc.) also lack version fields, so this is consistent with current practice but worth noting for future schema evolution.

Previous run (5)

Review

Findings

Critical

  • [runtime-mechanism] internal/scaffold/fullsend-repo/harness/code.yaml:45CODE_ALLOWED_TARGET_BRANCHES is referenced via ${CODE_ALLOWED_TARGET_BRANCHES} in runner_env but is never set in the workflow env. The PR removes TARGET_BRANCH: main from reusable-code.yml without adding CODE_ALLOWED_TARGET_BRANCHES to the step env. ValidateRunnerEnvWith in harness.go:493 checks that every ${VAR} reference in runner_env is defined in the host environment via os.LookupEnv. Since CODE_ALLOWED_TARGET_BRANCHES is not set, validation will fail with host variable CODE_ALLOWED_TARGET_BRANCHES is not set, preventing the code agent from running entirely.
    Remediation: Either (1) add CODE_ALLOWED_TARGET_BRANCHES: '' to the workflow env in reusable-code.yml, or (2) change the harness value to not use a ${...} reference for this optional variable (e.g., use a literal empty string as default), or (3) add a special-case in run.go's lookup function similar to FULLSEND_DIR.

High

  • [internal-consistency] docs/ADRs/0049-agent-driven-branch-targeting.md — ADR number collision: docs/ADRs/0049-agent-configuration-env-var-convention.md already exists on main. After merge, there would be two ADR files with number 0049. The PR title also references "ADR 0047" which is yet another existing ADR (0047-vendored-installs-with-vendor-flag.md).
    Remediation: Renumber the new ADR to 0050 (the next available number). Update all references in docs/architecture.md, the post-script comment at post-code.sh:65, and the PR title/body.

Medium

  • [internal-consistency] internal/scaffold/fullsend-repo/scripts/post-code.sh:65 — The comment in the branch resolution block says ADR 0047 but the ADR file added by this PR is numbered 0049 (and should be renumbered to 0050 per the above finding). ADR 0047 is 0047-vendored-installs-with-vendor-flag.md, which is unrelated to branch targeting.
    Remediation: Update the comment to reference the correct ADR number.

  • [breaking-env-contract] internal/scaffold/fullsend-repo/harness/code.yaml:45 — Removal of TARGET_BRANCH from runner_env is a contract change. The reusable-code.yml workflow no longer sets TARGET_BRANCH in env. Enrolled repos with customized harness/code.yaml files that still reference ${TARGET_BRANCH} will fail ValidateRunnerEnvWith validation because the variable is no longer provided by the workflow.
    Remediation: Add a migration note to the ADR's Consequences section explaining that repos with customized code.yaml must update their runner_env to replace TARGET_BRANCH with CODE_ALLOWED_TARGET_BRANCHES.

  • [protected-path] .github/workflows/reusable-code.yml — This file is under the .github/ protected path. The PR links to issue Code agent hardcodes TARGET_BRANCH to main, breaking repos with non-main default branches #2345 and explains the rationale (fixing hardcoded TARGET_BRANCH: main for repos with non-main default branches). Human approval is required for protected-path changes regardless of context.

Low

  • [injection] internal/scaffold/fullsend-repo/scripts/post-code.sh:82 — Defense-in-depth gap: AGENT_TARGET is read from agent-produced code-result.json via jq -r without re-validating against the schema's regex pattern (^[a-zA-Z0-9._/-]+$). When CODE_ALLOWED_TARGET_BRANCHES="*", the value bypasses allowlist validation and flows into TARGET_BRANCH, which is interpolated into GHA workflow commands at lines 116 and 417 (::warning:: and ::error:: prefixes). The practical risk is low — the JSON schema is enforced inside the sandbox before the post-script runs.

  • [edge-case] internal/scaffold/fullsend-repo/scripts/post-code.sh:82 — The post-script validates the agent's chosen branch against the allowlist but does not verify the branch exists in the remote repository. If the agent specifies a non-existent but allowed branch, gh pr create --base will fail with a confusing error.

  • [stale-reference] docs/plans/adr-0045-forge-portable-harness-phase2.md:130 — Phase 2 implementation plan lists TARGET_BRANCH as a top-level runner_env variable for code.yaml. After this PR, TARGET_BRANCH is replaced.


Labels: PR modifies code agent harness config, CI workflow, ADR, and post-script

Previous run (6)

Review

Findings

Medium

  • [internal-consistency] internal/scaffold/fullsend-repo/scripts/post-code.sh:65 — The comment in the branch resolution block says ADR 0047 but the ADR file added by this PR is numbered 0049 (docs/ADRs/0049-agent-driven-branch-targeting.md). ADR 0047 already exists as 0047-vendored-installs-with-vendor-flag.md, so this reference points to the wrong document.
    Remediation: Change # Resolve target branch (ADR 0047) to # Resolve target branch (ADR 0049).

  • [breaking-env-contract] internal/scaffold/fullsend-repo/harness/code.yaml:45 — Removal of TARGET_BRANCH from runner_env (and TARGET_BRANCH: main from reusable-code.yml) is a contract change for enrolled repos with customized harness/code.yaml files. Per ADR-0035, customized harnesses use file-level replacement, so repos that copied the upstream code.yaml and reference ${TARGET_BRANCH} in runner_env will receive an empty string. The post-script handles this gracefully (it computes TARGET_BRANCH internally via the new branch resolution logic), so the standard post-script still works. However, repos with custom post-scripts that read TARGET_BRANCH from the environment would be affected. The ADR's Consequences section mentions this but does not provide migration instructions.
    Remediation: Add a brief migration note to the ADR's Consequences section: repos with customized harness/code.yaml should replace TARGET_BRANCH: "${TARGET_BRANCH}" with CODE_ALLOWED_TARGET_BRANCHES: "${CODE_ALLOWED_TARGET_BRANCHES}" and update any custom scripts to use the new branch resolution pattern.

  • [protected-path] .github/workflows/reusable-code.yml — This file is under the .github/ protected path. The PR links to issue Code agent hardcodes TARGET_BRANCH to main, breaking repos with non-main default branches #2345 and explains the rationale (fixing hardcoded TARGET_BRANCH: main for repos with non-main default branches). Human approval is required for protected-path changes regardless of context.

Low

  • [injection] internal/scaffold/fullsend-repo/scripts/post-code.sh:82 — Defense-in-depth gap: AGENT_TARGET is read from agent-produced code-result.json via jq -r without re-validating against the schema's regex pattern (^[a-zA-Z0-9._/-]+$). When CODE_ALLOWED_TARGET_BRANCHES="*", the value bypasses allowlist validation entirely. The actual risk is low — the JSON schema is enforced inside the sandbox before the post-script runs, and jq -r only produces newlines from JSON-escaped \n which the schema pattern rejects. Adding a regex check in the post-script would provide defense-in-depth.

  • [edge-case] internal/scaffold/fullsend-repo/scripts/post-code.sh:82 — The post-script validates the agent's chosen branch against the allowlist but does not verify the branch exists in the remote repository. If the agent specifies a non-existent but allowed branch, gh pr create --base will fail with a confusing error.

  • [stale-reference] docs/plans/adr-0045-forge-portable-harness-phase2.md:130 — Phase 2 implementation plan lists TARGET_BRANCH as a top-level runner_env variable for code.yaml. After this PR, TARGET_BRANCH is replaced. This is a planning document so impact is limited, but it could mislead future contributors consulting it.

  • [internal-consistency] docs/ADRs/0049-agent-driven-branch-targeting.md:89 — The JSON schema declares target_branch as required, meaning the file cannot exist without the field. Step 4 of the policy gate says "If the agent did not specify a branch, use the auto-detected default." The implementation correctly handles this (file absence = no preference), but the ADR text could be clearer that "did not specify" means "did not write the file," not "wrote the file without the field."

  • [title-body-mismatch] docs/ADRs/0049-agent-driven-branch-targeting.md — PR title and body reference "ADR 0047" but the actual file is 0049-agent-driven-branch-targeting.md. The code is correctly numbered; only the PR metadata is stale. See also: [internal-consistency] comment finding at post-code.sh:65.

  • [env-var-naming-inconsistency] internal/scaffold/fullsend-repo/harness/code.yaml:45CODE_ALLOWED_TARGET_BRANCHES uses an agent-type prefix (CODE_) that no other harness runner_env variable uses. All other harness files use generic, unprefixed names (TARGET_BRANCH, FULLSEND_OUTPUT_SCHEMA, TRIGGER_SOURCE, etc.).

  • [stale-reference] skills/spec-start-github/SKILL.md:27 — References TARGET_BRANCH as an optional environment variable (line 27) and uses it for branching (line 51). This skill is for the spec agent, not the code agent, so it may remain valid independently. Noted for awareness.

  • [documentation-staleness] docs/guides/user/running-agents-locally.md:175 — The substitution from TARGET_BRANCH=main to CODE_ALLOWED_TARGET_BRANCHES=main is correct, but the surrounding docs don't explain the allowlist semantics (comma-separated list, * for wildcard).

Previous run (7)

Review

Findings

Critical

  • [adr-numbering] docs/ADRs/0047-agent-driven-branch-targeting.md — ADR number collision: ADR 0047 already exists on main as 0047-vendored-installs-with-vendor-flag.md (status: Accepted). ADR 0048 (automatic-updates.md) also exists. The next available number is 0049.
    Remediation: Renumber this ADR to 0049. Update filename, frontmatter title, and markdown heading. The /renumber-adr skill can automate this.

High

  • [stale-reference] internal/scaffold/scaffold_test.go:653 — Test expects code.yaml runner_env to contain topLevelKeys: ["TARGET_BRANCH"], but the diff replaces TARGET_BRANCH with CODE_ALLOWED_TARGET_BRANCHES, FULLSEND_OUTPUT_SCHEMA, and FULLSEND_OUTPUT_FILE. This test will fail after merge.
    Remediation: Update the test case to topLevelKeys: []string{"CODE_ALLOWED_TARGET_BRANCHES", "FULLSEND_OUTPUT_SCHEMA", "FULLSEND_OUTPUT_FILE"}.

  • [stale-reference] internal/harness/scaffold_integration_test.go:304 — Integration test expects code.yaml runner_env to contain topLevelKeys: ["TARGET_BRANCH"]. Same issue — test will fail after merge.
    Remediation: Update the test case to match the new runner_env keys.

  • [invalid-status] docs/ADRs/0047-agent-driven-branch-targeting.md:3 — Invalid status value Proposed in frontmatter and body. AGENTS.md states valid ADR statuses are Accepted, Deprecated, and Superseded. Per AGENTS.md: "If the decision is made, set status to Accepted in the ADR you are proposing — not a lesser status merely because the PR is open."
    Remediation: Change status: Proposed to status: Accepted in both the YAML frontmatter and the Status section body.

Medium

  • [injection] internal/scaffold/fullsend-repo/scripts/post-code.sh:89 — GHA workflow command injection via agent-controlled AGENT_TARGET in ::error:: output. The value is read from code-result.json (agent output) via jq -r '.target_branch' and interpolated unsanitized into echo "::error::...". The exploitability is constrained (sandboxed agent, last step in job), but defense-in-depth applies.
    Remediation: Use plain echo instead of ::error:: since the step already exits with code 1, or sanitize AGENT_TARGET for :: sequences and encoded newlines.

  • [stale-reference] skills/spec-start-github/SKILL.md:27 — References TARGET_BRANCH as an optional environment variable (line 27) and uses it for branching (line 51). While this is a separate skill from the code agent, the removal of TARGET_BRANCH from the code agent's runner_env may signal a broader deprecation.

  • [stale-reference] docs/guides/user/running-agents-locally.md:175 — Documents TARGET_BRANCH=main as a required env var for running the code agent locally. After this PR, the code agent's post-script no longer reads TARGET_BRANCH — it uses code-result.json and auto-detects the default branch.

  • [internal-consistency] docs/ADRs/0047-agent-driven-branch-targeting.md:89 — The JSON schema declares target_branch as required with additionalProperties: false, meaning the field is mandatory when the file exists. Step 4 of the policy gate says "If the agent did not specify a branch, use the auto-detected default," which is ambiguous about file-absent vs field-absent. The implementation handles this correctly, but the ADR text should clarify that "did not specify" means "did not write the file."

  • [env-var-naming-inconsistency] internal/scaffold/fullsend-repo/harness/code.yaml:45CODE_ALLOWED_TARGET_BRANCHES uses an agent-type prefix (CODE_) that no other harness file uses. All other runner_env vars use generic names: TARGET_BRANCH, FULLSEND_OUTPUT_SCHEMA, TRIGGER_SOURCE, etc.
    Remediation: Consider renaming to ALLOWED_TARGET_BRANCHES to match the established pattern.

  • [stale-reference] docs/plans/adr-0045-forge-portable-harness-phase2.md:130 — Phase 2 implementation plan lists TARGET_BRANCH as a top-level runner_env variable to keep in code.yaml. This conflicts with the PR's removal of TARGET_BRANCH.

  • [protected-path] .github/workflows/reusable-code.yml — This file is under the .github/ protected path. The PR links to issue Code agent hardcodes TARGET_BRANCH to main, breaking repos with non-main default branches #2345 and explains the rationale (fixing hardcoded TARGET_BRANCH: main for repos with non-main default branches). Human approval is required for protected-path changes regardless of context.

Low

  • [authorization] internal/scaffold/fullsend-repo/scripts/post-code.sh:82 — Wildcard * in CODE_ALLOWED_TARGET_BRANCHES disables branch-targeting validation entirely. The ADR explicitly justifies this feature. Consider adding a log warning when wildcard is active.

  • [edge-case] internal/scaffold/fullsend-repo/scripts/post-code.sh:82 — Post-script validates the agent's chosen branch against the allowlist but does not verify the branch exists in the remote repository. gh pr create --base will fail with an unhelpful error if the branch is nonexistent.

  • [workflow-breaking-change] .github/workflows/reusable-code.yml — Removal of TARGET_BRANCH: main is a behavioral change affecting all enrolled repos on next deployment. The post-script's auto-detection fallback provides a safe migration path.

  • [schema-output-file-pattern] internal/scaffold/fullsend-repo/harness/code.yaml:46 — Addition of both FULLSEND_OUTPUT_SCHEMA and FULLSEND_OUTPUT_FILE follows the fix.yaml pattern but diverges from triage.yaml/review.yaml which only define FULLSEND_OUTPUT_SCHEMA.

Previous run (8)

Review

Findings

Critical

  • [adr-numbering] docs/ADRs/0047-agent-driven-branch-targeting.md — ADR number collision: ADR 0047 already exists on main as 0047-vendored-installs-with-vendor-flag.md (status: Accepted). ADR 0048 (automatic-updates.md) also exists. The next available number is 0049.
    Remediation: Renumber this ADR to 0049. Update filename, frontmatter title, and markdown heading. The /renumber-adr skill can automate this.

High

  • [invalid-status] docs/ADRs/0047-agent-driven-branch-targeting.md:3 — Invalid status value Proposed in frontmatter (line 3) and body (line 19). AGENTS.md states valid ADR statuses are Accepted, Deprecated, and Superseded. Proposed is not in the allowed set.
    Remediation: Change status: Proposed to status: Accepted.

Medium

  • [missing-authorization] docs/ADRs/0047-agent-driven-branch-targeting.md — Issue Code agent hardcodes TARGET_BRANCH to main, breaking repos with non-main default branches #2345 authorizes fixing the hardcoded TARGET_BRANCH: main problem and expects a working fix. This PR contains only an ADR document without implementation.
    Remediation: Clarify in the PR description that this is a design-first PR with implementation to follow.

  • [internal-consistency] docs/ADRs/0047-agent-driven-branch-targeting.md:89 — The JSON schema declares "required": ["target_branch"] with "additionalProperties": false, meaning the field is mandatory when the file exists. Step 4 of the policy gate says "If the agent did not specify a branch, use the auto-detected default," which is ambiguous.

  • [stale-reference] docs/ADRs/0047-agent-driven-branch-targeting.md:135 — The ADR proposes removing TARGET_BRANCH from runner_env but does not enumerate all consumers.

  • [adr-status-mismatch] docs/ADRs/0047-agent-driven-branch-targeting.md — AGENTS.md requires that when an ADR has status Accepted, docs/architecture.md and related problem docs must be updated in the same PR.

Low

  • [revert-claim-unverified] docs/ADRs/0047-agent-driven-branch-targeting.md — The PR body claims "Reverts the previous workflow-level fix in favor of the ADR approach." However, reusable-code.yml on main still has TARGET_BRANCH: main hardcoded.

  • [incomplete-context] docs/ADRs/0047-agent-driven-branch-targeting.md — The ADR does not acknowledge that the code-implementation skill already has dynamic branch detection fallback.

  • [edge-case] docs/ADRs/0047-agent-driven-branch-targeting.md:113 — The policy gate does not specify what happens when the agent's chosen branch passes the allowlist but does not exist in the remote repository.

Previous run (9)

Review

Findings

Medium

Low

  • [injection] .github/workflows/reusable-code.yml:161 — When branch name validation fails, the unvalidated TARGET value is interpolated into a ::error:: workflow command.

  • [logic-error] .github/workflows/reusable-code.yml:140 — The --branch regex (?<=--branch\s)\S+ matches only one whitespace after --branch, and head -1 limits parsing to the first line.

  • [error-handling] .github/workflows/reusable-code.yml:148 — The gh api fallback uses || echo '' (empty string) while reusable-fix.yml uses || echo 'main'.

  • [edge-case] .github/workflows/reusable-code.yml:157 — The branch name validation regex ^[a-zA-Z0-9._/-]+$ rejects valid git branch names containing #, @, or other special characters.

Previous run (10)

Review

Findings

Critical

  • [adr-numbering] docs/ADRs/0047-agent-driven-branch-targeting.md — ADR number collision: ADR 0047 already exists on main as 0047-vendored-installs-with-vendor-flag.md (status: Accepted). ADR 0048 (automatic-updates.md) also exists. The next available number is 0049.
    Remediation: Renumber this ADR to 0049. Update filename, frontmatter title, and markdown heading. The /renumber-adr skill can automate this.

High

  • [stale-reference] internal/scaffold/scaffold_test.go:653 — Test expects code.yaml runner_env to contain topLevelKeys: ["TARGET_BRANCH"], but the diff replaces TARGET_BRANCH with CODE_ALLOWED_TARGET_BRANCHES, FULLSEND_OUTPUT_SCHEMA, and FULLSEND_OUTPUT_FILE. This test will fail after merge.
    Remediation: Update the test case to topLevelKeys: []string{"CODE_ALLOWED_TARGET_BRANCHES", "FULLSEND_OUTPUT_SCHEMA", "FULLSEND_OUTPUT_FILE"}.

  • [stale-reference] internal/harness/scaffold_integration_test.go:304 — Integration test expects code.yaml runner_env to contain topLevelKeys: ["TARGET_BRANCH"]. Same issue — test will fail after merge.
    Remediation: Update the test case to match the new runner_env keys.

  • [invalid-status] docs/ADRs/0047-agent-driven-branch-targeting.md:3 — Invalid status value Proposed in frontmatter and body. AGENTS.md states valid ADR statuses are Accepted, Deprecated, and Superseded. Per AGENTS.md: "If the decision is made, set status to Accepted in the ADR you are proposing — not a lesser status merely because the PR is open."
    Remediation: Change status: Proposed to status: Accepted in both the YAML frontmatter and the Status section body.

Medium

  • [injection] internal/scaffold/fullsend-repo/scripts/post-code.sh:89 — GHA workflow command injection via agent-controlled AGENT_TARGET in ::error:: output. The value is read from code-result.json (agent output) via jq -r '.target_branch' and interpolated unsanitized into echo "::error::...". The exploitability is constrained (sandboxed agent, last step in job), but defense-in-depth applies.
    Remediation: Use plain echo instead of ::error:: since the step already exits with code 1, or sanitize AGENT_TARGET for :: sequences and encoded newlines.

  • [stale-reference] skills/spec-start-github/SKILL.md:27 — References TARGET_BRANCH as an optional environment variable (line 27) and uses it for branching (line 51). While this is a separate skill from the code agent, the removal of TARGET_BRANCH from the code agent's runner_env may signal a broader deprecation.

  • [stale-reference] docs/guides/user/running-agents-locally.md:175 — Documents TARGET_BRANCH=main as a required env var for running the code agent locally. After this PR, the code agent's post-script no longer reads TARGET_BRANCH — it uses code-result.json and auto-detects the default branch.

  • [internal-consistency] docs/ADRs/0047-agent-driven-branch-targeting.md:89 — The JSON schema declares target_branch as required with additionalProperties: false, meaning the field is mandatory when the file exists. Step 4 of the policy gate says "If the agent did not specify a branch, use the auto-detected default," which is ambiguous about file-absent vs field-absent. The implementation handles this correctly, but the ADR text should clarify that "did not specify" means "did not write the file."

  • [env-var-naming-inconsistency] internal/scaffold/fullsend-repo/harness/code.yaml:45CODE_ALLOWED_TARGET_BRANCHES uses an agent-type prefix (CODE_) that no other harness file uses. All other runner_env vars use generic names: TARGET_BRANCH, FULLSEND_OUTPUT_SCHEMA, TRIGGER_SOURCE, etc.
    Remediation: Consider renaming to ALLOWED_TARGET_BRANCHES to match the established pattern.

  • [stale-reference] docs/plans/adr-0045-forge-portable-harness-phase2.md:130 — Phase 2 implementation plan lists TARGET_BRANCH as a top-level runner_env variable to keep in code.yaml. This conflicts with the PR's removal of TARGET_BRANCH.

  • [protected-path] .github/workflows/reusable-code.yml — This file is under the .github/ protected path. The PR links to issue Code agent hardcodes TARGET_BRANCH to main, breaking repos with non-main default branches #2345 and explains the rationale (fixing hardcoded TARGET_BRANCH: main for repos with non-main default branches). Human approval is required for protected-path changes regardless of context.

Low

  • [authorization] internal/scaffold/fullsend-repo/scripts/post-code.sh:82 — Wildcard * in CODE_ALLOWED_TARGET_BRANCHES disables branch-targeting validation entirely. The ADR explicitly justifies this feature. Consider adding a log warning when wildcard is active.

  • [edge-case] internal/scaffold/fullsend-repo/scripts/post-code.sh:82 — Post-script validates the agent's chosen branch against the allowlist but does not verify the branch exists in the remote repository. gh pr create --base will fail with an unhelpful error if the branch is nonexistent.

  • [workflow-breaking-change] .github/workflows/reusable-code.yml — Removal of TARGET_BRANCH: main is a behavioral change affecting all enrolled repos on next deployment. The post-script's auto-detection fallback provides a safe migration path.

  • [schema-output-file-pattern] internal/scaffold/fullsend-repo/harness/code.yaml:46 — Addition of both FULLSEND_OUTPUT_SCHEMA and FULLSEND_OUTPUT_FILE follows the fix.yaml pattern but diverges from triage.yaml/review.yaml which only define FULLSEND_OUTPUT_SCHEMA.

Previous run (11)

Review

Findings

Critical

  • [adr-numbering] docs/ADRs/0047-agent-driven-branch-targeting.md — ADR number collision: ADR 0047 already exists on main as 0047-vendored-installs-with-vendor-flag.md (status: Accepted). ADR 0048 (automatic-updates.md) also exists. The next available number is 0049.
    Remediation: Renumber this ADR to 0049. Update filename, frontmatter title, and markdown heading. The /renumber-adr skill can automate this.

High

  • [invalid-status] docs/ADRs/0047-agent-driven-branch-targeting.md:3 — Invalid status value Proposed in frontmatter (line 3) and body (line 19). AGENTS.md states valid ADR statuses are Accepted, Deprecated, and Superseded. Proposed is not in the allowed set. Per AGENTS.md: "If the decision is made, set status to Accepted in the ADR you are proposing — not a lesser status merely because the PR is open."
    Remediation: Change status: Proposed to status: Accepted in both the YAML frontmatter (line 3) and the Status section body. Valid statuses are Accepted, Deprecated, and Superseded.

Medium

  • [missing-authorization] docs/ADRs/0047-agent-driven-branch-targeting.md — Issue Code agent hardcodes TARGET_BRANCH to main, breaking repos with non-main default branches #2345 authorizes fixing the hardcoded TARGET_BRANCH: main problem and expects a working fix. This PR contains only an ADR document without implementation. Submitting an ADR before implementation is a legitimate design-first workflow, but the PR description should clarify this intent.
    Remediation: Clarify in the PR description that this is a design-first PR with implementation to follow in a separate PR. Consider whether Closes #2345 is premature if the implementation hasn't landed.

  • [internal-consistency] docs/ADRs/0047-agent-driven-branch-targeting.md:89 — The JSON schema declares "required": ["target_branch"] with "additionalProperties": false, meaning the field is mandatory when the file exists. Step 4 of the policy gate says "If the agent did not specify a branch, use the auto-detected default," which is ambiguous about whether this means file-absent or field-absent. The backward compatibility section clarifies that fallback applies when the file is absent, but step 4's phrasing creates confusion.
    Remediation: Clarify that fallback only applies when the entire code-result.json file is absent, or remove target_branch from the required array to support the field-absent case.

  • [stale-reference] docs/ADRs/0047-agent-driven-branch-targeting.md:135 — The ADR proposes removing TARGET_BRANCH from runner_env but does not enumerate all consumers: (1) skills/code-implementation/SKILL.md line 181 instructs agents to use TARGET_BRANCH, (2) internal/harness/scaffold_integration_test.go line 304 and internal/scaffold/scaffold_test.go line 653 assert TARGET_BRANCH in code.yaml topLevelKeys, (3) docs/guides/user/running-agents-locally.md line 175 documents TARGET_BRANCH=main. The Consequences section's "any tooling that reads it directly must be updated" is insufficiently specific for implementers.
    Remediation: Add an explicit list of files that must be updated when TARGET_BRANCH is removed.

  • [adr-status-mismatch] docs/ADRs/0047-agent-driven-branch-targeting.md — AGENTS.md requires that when an ADR has status Accepted, docs/architecture.md and related problem docs must be updated in the same PR. If the status is changed to Accepted (as the invalid-status finding recommends), this PR must also update docs/architecture.md.
    Remediation: When setting status to Accepted, include docs/architecture.md updates in the same PR.

Low

  • [revert-claim-unverified] docs/ADRs/0047-agent-driven-branch-targeting.md — The PR body claims "Reverts the previous workflow-level fix in favor of the ADR approach." However, reusable-code.yml on main still has TARGET_BRANCH: main hardcoded at line 177. No prior fix appears to have been merged.

  • [incomplete-context] docs/ADRs/0047-agent-driven-branch-targeting.md — The ADR does not acknowledge that the code-implementation skill already has dynamic branch detection fallback (git rev-parse --abbrev-ref origin/HEAD) when TARGET_BRANCH is not set (SKILL.md line 181). The problem may be partially addressable by simply removing the hardcoded env var.

  • [edge-case] docs/ADRs/0047-agent-driven-branch-targeting.md:113 — The policy gate does not specify what happens when the agent's chosen branch passes the allowlist but does not exist in the remote repository. gh pr create --base <nonexistent> would fail at PR creation time.

Previous run (12)

Review

Findings

Critical

  • [adr-numbering] docs/ADRs/0047-agent-driven-branch-targeting.md — ADR number collision: ADR 0047 already exists on main as 0047-vendored-installs-with-vendor-flag.md (status: Accepted). ADR 0048 (automatic-updates.md) also exists. The next available number is 0049.
    Remediation: Renumber this ADR to 0049. Update filename, frontmatter title, and markdown heading. The /renumber-adr skill can automate this.

High

  • [invalid-status] docs/ADRs/0047-agent-driven-branch-targeting.md:3 — Invalid status value Proposed in frontmatter (line 3) and body (line 19). AGENTS.md states valid ADR statuses are Accepted, Deprecated, and Superseded. Proposed is not in the allowed set. Per AGENTS.md: "If the decision is made, set status to Accepted in the ADR you are proposing — not a lesser status merely because the PR is open."
    Remediation: Change status: Proposed to status: Accepted if the decision is made. If the ADR is not yet decided, it should still use a valid status value per project policy.

Medium

  • [missing-authorization] docs/ADRs/0047-agent-driven-branch-targeting.md — Issue Code agent hardcodes TARGET_BRANCH to main, breaking repos with non-main default branches #2345 authorizes fixing the hardcoded TARGET_BRANCH: main problem and expects a working fix. This PR contains only an ADR document without implementation. Submitting an ADR before implementation is a legitimate design-first workflow, but the PR description should clarify this intent.
    Remediation: Clarify in the PR description that this is a design-first PR with implementation to follow in a separate PR. Consider whether Closes #2345 is premature if the implementation hasn't landed.

  • [internal-consistency] docs/ADRs/0047-agent-driven-branch-targeting.md:89 — The JSON schema declares "required": ["target_branch"] with "additionalProperties": false, meaning the field is mandatory when the file exists. Step 4 of the policy gate says "If the agent did not specify a branch, use the auto-detected default," which is ambiguous about whether this means file-absent or field-absent. The backward compatibility section clarifies that fallback applies when the file is absent, but step 4's phrasing creates confusion.
    Remediation: Clarify that fallback only applies when the entire code-result.json file is absent, or remove target_branch from the required array to support the field-absent case.

  • [stale-reference] docs/ADRs/0047-agent-driven-branch-targeting.md:135 — The ADR proposes removing TARGET_BRANCH from runner_env but does not enumerate all consumers: (1) skills/code-implementation/SKILL.md line 181 instructs agents to use TARGET_BRANCH, (2) internal/harness/scaffold_integration_test.go line 304 and internal/scaffold/scaffold_test.go line 653 assert TARGET_BRANCH in code.yaml topLevelKeys, (3) docs/guides/user/running-agents-locally.md line 175 documents TARGET_BRANCH=main. The Consequences section's "any tooling that reads it directly must be updated" is insufficiently specific for implementers.
    Remediation: Add an explicit list of files that must be updated when TARGET_BRANCH is removed.

  • [adr-status-mismatch] docs/ADRs/0047-agent-driven-branch-targeting.md — AGENTS.md requires that when an ADR has status Accepted, docs/architecture.md and related problem docs must be updated in the same PR. If the status is changed to Accepted (as the invalid-status finding recommends), this PR must also update docs/architecture.md.
    Remediation: When setting status to Accepted, include docs/architecture.md updates in the same PR.

Low

  • [revert-claim-unverified] docs/ADRs/0047-agent-driven-branch-targeting.md — The PR body claims "Reverts the previous workflow-level fix in favor of the ADR approach." However, reusable-code.yml on main still has TARGET_BRANCH: main hardcoded at line 177. No prior fix appears to have been merged.

  • [incomplete-context] docs/ADRs/0047-agent-driven-branch-targeting.md — The ADR does not acknowledge that the code-implementation skill already has dynamic branch detection fallback (git rev-parse --abbrev-ref origin/HEAD) when TARGET_BRANCH is not set (SKILL.md line 181). The problem may be partially addressable by simply removing the hardcoded env var.

  • [edge-case] docs/ADRs/0047-agent-driven-branch-targeting.md:113 — The policy gate does not specify what happens when the agent's chosen branch passes the allowlist but does not exist in the remote repository. gh pr create --base <nonexistent> would fail at PR creation time.

Previous run (13)

Review

Findings

Medium

Low

  • [injection] .github/workflows/reusable-code.yml:161 — When branch name validation fails, the unvalidated TARGET value is interpolated into a ::error:: workflow command. The risk is mitigated by head -1 and \S+ grep preventing newline injection, but :: sequences could corrupt the annotation. Consider using plain echo instead of ::error:: since the step already exits with code 1.

  • [logic-error] .github/workflows/reusable-code.yml:140 — The --branch regex (?<=--branch\s)\S+ matches only one whitespace after --branch, and head -1 limits parsing to the first line. This is acceptable as the contract for a new feature, but worth noting for documentation.

  • [error-handling] .github/workflows/reusable-code.yml:148 — The gh api fallback uses || echo '' (empty string) while reusable-fix.yml uses || echo 'main'. The inconsistency is intentional — empty string enables the ::warning:: message in the else branch — but the differing patterns across workflows may confuse future contributors.

  • [edge-case] .github/workflows/reusable-code.yml:157 — The branch name validation regex ^[a-zA-Z0-9._/-]+$ rejects valid git branch names containing #, @, or other special characters. This is a deliberate security-defensive choice but may block legitimate branch names in some organizations.

@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.

Comment thread .github/workflows/reusable-code.yml Outdated
Comment thread .github/workflows/reusable-code.yml Outdated
Comment thread .github/workflows/reusable-code.yml Outdated
Comment thread .github/workflows/reusable-code.yml Outdated
@fullsend-ai-review fullsend-ai-review Bot added the requires-manual-review Review requires human judgment label Jun 16, 2026
@ralphbean

Copy link
Copy Markdown
Member

FYI, we talked in slack about re-doing this so that it doesn't add more business logic to the gh workflows.

@Marcusk19 Marcusk19 changed the title fix(#2345): resolve TARGET_BRANCH dynamically in code agent docs(#2345): ADR 0047 — agent-driven branch targeting for code agent Jun 17, 2026
@Marcusk19

Copy link
Copy Markdown
Contributor Author

updated the PR to drop the changes to the workflow file and instead propose a new ADR for addressing this

@fullsend-ai-review

fullsend-ai-review Bot commented Jun 17, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 1:42 PM UTC · Completed 1:54 PM UTC
Commit: f0f032e · View workflow run →

@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.

Comment thread docs/ADRs/0047-agent-driven-branch-targeting.md Outdated
Comment thread docs/ADRs/0053-agent-driven-branch-targeting.md
Comment thread docs/ADRs/0053-agent-driven-branch-targeting.md
Comment thread docs/ADRs/0053-agent-driven-branch-targeting.md
@fullsend-ai-review fullsend-ai-review Bot removed the requires-manual-review Review requires human judgment label Jun 17, 2026
@github-actions

Copy link
Copy Markdown

E2E tests did not run

E2E tests run automatically for org/repo members and collaborators on pull requests.

For other contributors, a maintainer must add the ok-to-test label after the latest push.

See E2E testing guide for details.

@fullsend-ai-review

fullsend-ai-review Bot commented Jun 17, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 2:19 PM UTC · Completed 2:37 PM UTC
Commit: cf39acb · View workflow run →

@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.

Comment thread docs/ADRs/0047-agent-driven-branch-targeting.md Outdated
Comment thread internal/scaffold/fullsend-repo/scripts/post-code.sh
Comment thread docs/ADRs/0053-agent-driven-branch-targeting.md
Comment thread internal/scaffold/fullsend-repo/harness/code.yaml

@ralphbean ralphbean 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.

A few things to sort out — see inline comments. One thing I can't comment inline: internal/scaffold/scaffold_test.go:653 expects TARGET_BRANCH in code.yaml's runner_env, so that test will break with the new key names.

Comment thread internal/scaffold/fullsend-repo/scripts/post-code.sh Outdated
Comment thread docs/ADRs/0047-agent-driven-branch-targeting.md Outdated

If a `TARGET_BRANCH` environment variable is set, use it. Otherwise, determine
the default branch:
Determine the correct target branch from the issue context. If the issue

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.

[moderate] The post-script validates the agent's branch choice against CODE_ALLOWED_TARGET_BRANCHES, but the skill instructions don't mention that constraint. If the agent picks a branch not in the allowlist, the post-script exits with an error and the agent won't know why. Worth mentioning the allowlist here so the agent can fall back to the default branch gracefully.

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.

I don't think the agent needs to know about it, then it could try to implement the solution against a branch that shouldn't, just because it is the "next best branch I could implement this change to".

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.

If the agent will read the variable, then I think it should exit early if there are any conflicts.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm inclined to agree - the expected behavior in my head should be if someone instructs the agent to use a missing branch from the allowlist it will raise an error instead of falling back a PR against main

@fullsend-ai-review

fullsend-ai-review Bot commented Jun 18, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 2:05 PM UTC · Completed 2:26 PM UTC
Commit: 5c42ded · View workflow run →

@ralphbean ralphbean 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.

LGTM. One non-blocking note inline.


Write this output early (during planning, after determining the target
branch) so it is available even if the agent hits a timeout or error later.
The post-script validates this against the repo's allowed branches.

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.

[nit] Other agents call fullsend-check-output after writing their structured output. Probably fine to skip here since the commit is the primary artifact and the post-script handles missing/malformed output gracefully — just noting the schema isn't validated at runtime.

@fullsend-ai-review fullsend-ai-review Bot added the requires-manual-review Review requires human judgment label Jun 18, 2026
@fullsend-ai-review

fullsend-ai-review Bot commented Jun 18, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 6:21 PM UTC · Completed 6:37 PM UTC
Commit: e4bd467 · View workflow run →

@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.

Comment thread internal/scaffold/fullsend-repo/harness/code.yaml
Comment thread docs/ADRs/0053-agent-driven-branch-targeting.md
Comment thread internal/scaffold/fullsend-repo/scripts/post-code.sh
Comment thread internal/scaffold/fullsend-repo/harness/code.yaml
Comment thread internal/scaffold/fullsend-repo/scripts/post-code.sh
Comment thread internal/scaffold/fullsend-repo/scripts/post-code.sh
@fullsend-ai-review fullsend-ai-review Bot added component/harness Agent harness, config, and skills loading agent/code Code agent component/ci CI pipelines and checks component/docs User-facing documentation and removed requires-manual-review Review requires human judgment labels Jun 18, 2026
@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

Site preview

Preview: https://c4b67406-site.fullsend-ai.workers.dev

Commit: 22fe71f4718e1bebe468bee0f2b588d2593f515d

@Marcusk19
Marcusk19 force-pushed the fix/dynamic-target-branch branch from e4bd467 to 2e96f9c Compare June 22, 2026 13:18
@fullsend-ai-review

fullsend-ai-review Bot commented Jun 22, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 1:22 PM UTC · Completed 1:39 PM UTC
Commit: 2e96f9c · View workflow run →

…ueue)

Signed-off-by: Marcus Kok <mkok@redhat.com>
…tream)

Signed-off-by: Marcus Kok <mkok@redhat.com>
@Marcusk19
Marcusk19 force-pushed the fix/dynamic-target-branch branch from af03ca7 to e6ecc12 Compare June 22, 2026 19:39
@Marcusk19 Marcusk19 changed the title docs(#2345): ADR 0052 — agent-driven branch targeting for code agent docs(#2345): ADR 0053 — agent-driven branch targeting for code agent Jun 22, 2026
@fullsend-ai-review

fullsend-ai-review Bot commented Jun 22, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 7:42 PM UTC · Completed 7:56 PM UTC
Commit: e6ecc12 · View workflow run →

@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.

# These are expanded from the runner environment and NEVER enter the sandbox.
runner_env:
TARGET_BRANCH: "${TARGET_BRANCH}"
CODE_ALLOWED_TARGET_BRANCHES: "${CODE_ALLOWED_TARGET_BRANCHES}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium] breaking-env-contract

Removal of TARGET_BRANCH from runner_env breaks enrolled repos with customized code.yaml files that still reference ${TARGET_BRANCH}. ValidateRunnerEnvWith in harness.go checks os.LookupEnv for all ${VAR} references, so a customized harness containing TARGET_BRANCH will fail validation because the workflow no longer provides this variable. ADR 0053 documents this as a consequence with concrete before/after YAML, but does not provide automated detection or a deprecation period.

Suggested fix: Add detection in fullsend admin install --upgrade to scan customized dirs for TARGET_BRANCH references. Consider a deprecation period where both variables are provided.

fi
done
if [ -n "${RESULT_FILE}" ]; then
AGENT_TARGET="$(jq -r '.target_branch // empty' "${RESULT_FILE}" 2>/dev/null || true)"

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] edge-case

Comma-separated allowlist matching does not handle whitespace in entries. When CODE_ALLOWED_TARGET_BRANCHES is set to 'main, develop' (with a space), the grep -qF check will fail for 'develop' because ', develop,' does not match ',develop,'.

@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment and removed requires-manual-review Review requires human judgment labels Jun 22, 2026
Assisted-by: Claude claude-opus-4-6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Jun 22, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 8:35 PM UTC · Completed 8:51 PM UTC
Commit: 22fe71f · View workflow run →

@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.

# These are expanded from the runner environment and NEVER enter the sandbox.
runner_env:
TARGET_BRANCH: "${TARGET_BRANCH}"
CODE_ALLOWED_TARGET_BRANCHES: "${CODE_ALLOWED_TARGET_BRANCHES}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium] breaking-env-contract

Removal of TARGET_BRANCH from runner_env breaks enrolled repos with customized code.yaml files that still reference ${TARGET_BRANCH}. ValidateRunnerEnvWith checks os.LookupEnv for all ${VAR} references. ADR 0053 documents this consequence but provides no automated detection or deprecation period.

fi
done
if [ -n "${RESULT_FILE}" ]; then
AGENT_TARGET="$(jq -r '.target_branch // empty' "${RESULT_FILE}" 2>/dev/null || true)"

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] edge-case

The comma-separated allowlist matching does not handle whitespace in entries. When CODE_ALLOWED_TARGET_BRANCHES has spaces after commas, the grep -qF check will fail for those entries.

@fullsend-ai-review fullsend-ai-review Bot removed the requires-manual-review Review requires human judgment label Jun 22, 2026
@ralphbean ralphbean self-assigned this Jun 22, 2026
Merged via the queue into fullsend-ai:main with commit f8e0bcc Jun 22, 2026
10 of 11 checks passed
@fullsend-ai-retro

fullsend-ai-retro Bot commented Jun 22, 2026

Copy link
Copy Markdown

🤖 Finished Retro · ✅ Success · Started 9:01 PM UTC · Completed 9:10 PM UTC
Commit: 22fe71f · View workflow run →

@fullsend-ai-retro

Copy link
Copy Markdown

Retro: PR #2346 — ADR 0053 agent-driven branch targeting

Timeline

This human-authored PR (by Marcusk19) proposed ADR 0053 over 6 days (June 16–22). It started as a workflow-level fix, was refactored to an ADR-based approach after Slack discussion, and went through 10+ review bot cycles and 2 human review rounds before merging.

What went well

  • The review bot caught a real ADR number collision (an existing ADR 0049 on main) that would have caused a merge conflict.
  • The review bot correctly identified that CODE_ALLOWED_TARGET_BRANCHES as a ${...} reference in runner_env would fail ValidateRunnerEnvWith since the workflow didn't define it.
  • Human reviewer (ralphbean) caught a critical runtime bug: gh api was called before GH_TOKEN was exported, which would silently fail on private repos — the exact bug the ADR was trying to fix.
  • The design discussion between reviewers (ralphbean, rh-hemartin) about whether the agent should know about the allowlist produced a better design.

What could go better

The dominant issue on this PR was review noise: the bot ran 10+ full review cycles on a ~270-line documentation PR, repeatedly surfacing the same findings:

  1. ADR status "Proposed" flagged as invalid — raised at [high] severity across 3 separate review cycles (June 17 twice, then again later). Valid finding, but repeated.
  2. Same injection concern in post-code.sh — flagged in 4+ review cycles with nearly identical text.
  3. ADR comment reference mismatch ("ADR 0047" in a code comment when the file was numbered differently) — flagged 3+ times as the ADR number changed.
  4. Final bot CHANGES_REQUESTED at 20:51 UTC — posted 5 minutes before the human merged at 20:56, effectively ignored.

This pattern consumed significant tokens (10+ full reviews of a docs PR) and trained the human to ignore bot reviews.

Existing issues that cover these improvements

All major improvement opportunities identified are already tracked in the backlog:

  • Finding deduplication across review cycles: #1013, #956, #1500
  • Bot overriding human approval with stale findings: #1922
  • Review cycle churn detection: #2111
  • Verdict calibration for medium/low findings on human PRs: #2115, #2333
  • ADR linter CI gap on this specific PR: #2396

No new proposals filed — the backlog already covers the improvements this retro would recommend. Prioritizing #1013 (finding dedup) and #1922 (don't override human approval) would have the highest impact on workflows like this one.

jbpratt pushed a commit to quay/.fullsend that referenced this pull request Jun 23, 2026
The v0 tag (= v0.18.0, released June 16) still hardcodes
TARGET_BRANCH: main in reusable-code.yml. Repos with a
non-main default branch (e.g. quay-operator uses master)
fail at PR creation because `gh pr create --base main`
targets a branch that doesn't exist.

fullsend-ai/fullsend#2346 (merged June 22) replaced the
hardcoded TARGET_BRANCH with agent-driven branch detection
(ADR 0053), but this hasn't been released yet.

Pin to @main temporarily to pick up the fix. Revert to @v0
once v0.19.0 is released and the v0 tag moves forward.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ifireball pushed a commit to ifireball/fullsend that referenced this pull request Jun 24, 2026
…-branch

docs(fullsend-ai#2345): ADR 0053 — agent-driven branch targeting for code agent
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent/code Code agent component/ci CI pipelines and checks component/docs User-facing documentation component/harness Agent harness, config, and skills loading

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Code agent hardcodes TARGET_BRANCH to main, breaking repos with non-main default branches

3 participants