Skip to content

Commit e6ffdea

Browse files
committed
refactor(harness): migrate fix agent to env.runner/env.sandbox (ADR 0055)
Move fix agent's harness configuration from legacy runner_env to the unified env schema (env.runner + env.sandbox). Move simple passthrough vars and hardcoded config values from fix-agent.env host file into env.sandbox in the harness YAML, keeping only the shell conditional (GIT_SSL_CAINFO) in the .env file. Update scaffold integration tests to check combined RunnerEnv + Env.Runner maps. Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
1 parent dc93e9a commit e6ffdea

3 files changed

Lines changed: 39 additions & 69 deletions

File tree

internal/harness/scaffold_integration_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,9 +287,9 @@ func TestLoadRaw_GeneratedWrapperFormat(t *testing.T) {
287287
}
288288

289289
// TestResolveForge_ScaffoldRunnerEnvMerge verifies that forge resolution
290-
// produces the expected merged runner_env for each scaffold template, with
291-
// both top-level (platform-neutral) and forge.github (platform-specific)
292-
// keys present in the final merged state.
290+
// produces the expected merged env.runner (or legacy runner_env) for each
291+
// scaffold template, with both top-level (platform-neutral) and
292+
// forge.github (platform-specific) keys present in the final merged state.
293293
func TestResolveForge_ScaffoldRunnerEnvMerge(t *testing.T) {
294294
dir := t.TempDir()
295295
harnessDir := extractScaffoldHarnessDir(t, dir)

internal/scaffold/fullsend-repo/env/fix-agent.env

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,3 @@
1-
export PR_NUMBER="${PR_NUMBER}"
2-
export REPO_FULL_NAME="${REPO_FULL_NAME}"
3-
export TRIGGER_SOURCE="${TRIGGER_SOURCE}"
4-
export HUMAN_INSTRUCTION="${HUMAN_INSTRUCTION}"
5-
export FIX_ITERATION="${FIX_ITERATION}"
6-
7-
# GH_TOKEN in the sandbox is a READ-ONLY scoped app installation token
8-
# (contents:read, issues:read, pull_requests:read). Set by
9-
# setup-agent-env.sh from FIX_GH_TOKEN. This token CANNOT push code
10-
# or create PRs — the read-only scope is the actual enforcement layer.
11-
# The separate write-enabled PUSH_TOKEN (runner_env) never enters the sandbox.
12-
export GH_TOKEN="${GH_TOKEN}"
13-
14-
# Author name is "fullsend-fix" (not "fullsend-code") so fix-agent
15-
# commits are distinguishable for iteration counting. Both agents share
16-
# the same GitHub App (coder role), so GIT_BOT_EMAIL resolves to the
17-
# same bot noreply address. This makes the Probot DCO app auto-exempt
18-
# agent commits (author.type === "Bot").
19-
export GIT_AUTHOR_NAME="fullsend-fix"
20-
export GIT_AUTHOR_EMAIL="${GIT_BOT_EMAIL}"
21-
export GIT_COMMITTER_NAME="fullsend-fix"
22-
export GIT_COMMITTER_EMAIL="${GIT_BOT_EMAIL}"
23-
24-
# Retry budget — the agent re-runs secret scan + tests on failure.
25-
# Pre-commit is capped at 2 runs total (not per retry).
26-
export MAX_RETRIES=1
27-
28-
# Hard timeout for the sandbox session in seconds. Must match
29-
# timeout_minutes in harness/fix.yaml.
30-
export TIMEOUT_SECONDS=1500
31-
32-
# Strategy escalation: after this many fix iterations, the agent should
33-
# try a fundamentally different approach.
34-
export STRATEGY_ESCALATION_THRESHOLD=3
35-
36-
# Iteration caps: bot-triggered runs (review→fix loop) have a tighter cap
37-
# than human-triggered runs (/fix commands). When the iteration count
38-
# approaches the bot cap, the 'needs-human' label is added and a human can
39-
# still direct the agent with /fix up to ITERATION_CAP_HUMAN total iterations
40-
# (bot + human combined).
41-
export ITERATION_CAP=5
42-
export ITERATION_CAP_HUMAN=10
43-
44-
# Go toolchain — PATH is set in the sandbox image via Containerfile ENV.
45-
# Do NOT set PATH here: this file uses expand: true (harness host_files), so
46-
# ${PATH} would be replaced with the GitHub Actions runner's PATH by
47-
# os.ExpandEnv, clobbering /sandbox/workspace/bin and breaking sandbox-local
48-
# binaries. See code-agent.env lines 27-33 for the full explanation.
49-
export GOPATH="/sandbox/go"
50-
export GOMODCACHE="/sandbox/go/pkg/mod"
51-
521
# SSL certs — same workaround as code agent for OpenShell TLS termination.
532
if [ -f /etc/openshell-tls/ca-bundle.pem ]; then
543
export GIT_SSL_CAINFO=/etc/openshell-tls/ca-bundle.pem

internal/scaffold/fullsend-repo/harness/fix.yaml

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,25 +42,46 @@ host_files:
4242
skills:
4343
- skills/fix-review
4444

45-
runner_env:
46-
TARGET_BRANCH: "${TARGET_BRANCH}"
47-
TRIGGER_SOURCE: "${TRIGGER_SOURCE}"
48-
HUMAN_INSTRUCTION: "${HUMAN_INSTRUCTION}"
49-
FIX_ITERATION: "${FIX_ITERATION}"
50-
REVIEW_BODY_FILE: "${REVIEW_BODY_FILE}"
51-
PRE_AGENT_HEAD: "${PRE_AGENT_HEAD}"
52-
FULLSEND_OUTPUT_SCHEMA: ${FULLSEND_DIR}/schemas/fix-result.schema.json
53-
FULLSEND_OUTPUT_FILE: fix-result.json
45+
env:
46+
runner:
47+
TARGET_BRANCH: "${TARGET_BRANCH}"
48+
TRIGGER_SOURCE: "${TRIGGER_SOURCE}"
49+
HUMAN_INSTRUCTION: "${HUMAN_INSTRUCTION}"
50+
FIX_ITERATION: "${FIX_ITERATION}"
51+
REVIEW_BODY_FILE: "${REVIEW_BODY_FILE}"
52+
PRE_AGENT_HEAD: "${PRE_AGENT_HEAD}"
53+
FULLSEND_OUTPUT_SCHEMA: ${FULLSEND_DIR}/schemas/fix-result.schema.json
54+
FULLSEND_OUTPUT_FILE: fix-result.json
55+
sandbox:
56+
MAX_RETRIES: "1"
57+
TIMEOUT_SECONDS: "1500"
58+
STRATEGY_ESCALATION_THRESHOLD: "3"
59+
ITERATION_CAP: "5"
60+
ITERATION_CAP_HUMAN: "10"
61+
GOPATH: "/sandbox/go"
62+
GOMODCACHE: "/sandbox/go/pkg/mod"
5463

5564
timeout_minutes: 25
5665

5766
forge:
5867
github:
5968
pre_script: scripts/pre-fix.sh
6069
post_script: scripts/post-fix.sh
61-
runner_env:
62-
PUSH_TOKEN: "${PUSH_TOKEN}"
63-
PUSH_TOKEN_SOURCE: "${PUSH_TOKEN_SOURCE}"
64-
REPO_FULL_NAME: "${REPO_FULL_NAME}"
65-
PR_NUMBER: "${PR_NUMBER}"
66-
REPO_DIR: "${GITHUB_WORKSPACE}/target-repo"
70+
env:
71+
runner:
72+
PUSH_TOKEN: "${PUSH_TOKEN}"
73+
PUSH_TOKEN_SOURCE: "${PUSH_TOKEN_SOURCE}"
74+
REPO_FULL_NAME: "${REPO_FULL_NAME}"
75+
PR_NUMBER: "${PR_NUMBER}"
76+
REPO_DIR: "${GITHUB_WORKSPACE}/target-repo"
77+
sandbox:
78+
PR_NUMBER: "${PR_NUMBER}"
79+
REPO_FULL_NAME: "${REPO_FULL_NAME}"
80+
TRIGGER_SOURCE: "${TRIGGER_SOURCE}"
81+
HUMAN_INSTRUCTION: "${HUMAN_INSTRUCTION}"
82+
FIX_ITERATION: "${FIX_ITERATION}"
83+
GH_TOKEN: "${GH_TOKEN}"
84+
GIT_AUTHOR_NAME: "fullsend-fix"
85+
GIT_AUTHOR_EMAIL: "${GIT_BOT_EMAIL}"
86+
GIT_COMMITTER_NAME: "fullsend-fix"
87+
GIT_COMMITTER_EMAIL: "${GIT_BOT_EMAIL}"

0 commit comments

Comments
 (0)