Skip to content

feat(run): controlled scenario system_prompt (fixes uncontrolled-prompt A/B bias)#17

Closed
jahala wants to merge 2 commits into
masterfrom
jahala/run-config-fixes
Closed

feat(run): controlled scenario system_prompt (fixes uncontrolled-prompt A/B bias)#17
jahala wants to merge 2 commits into
masterfrom
jahala/run-config-fixes

Conversation

@jahala

@jahala jahala commented Jun 23, 2026

Copy link
Copy Markdown
Owner

Why

copeca's A/B promise is "hold everything fixed, vary one thing." But it inherited the agent CLI's full default system prompt (which promotes the native Read/Grep/Glob tools) — an uncontrolled variable. Any tool-under-test that competes with native tools was systematically under-adopted.

Empirically (this branch's investigation): the same tilth + Sonnet + version that tilth's own lean-prompt harness measured cheaper, copeca measured costlier, purely because copeca's agent used tilth ~30% vs tilth's ~100%. Matching the system prompt flips adoption.

What

Add Scenario.system_prompt — a fixed prompt threaded to every arm (baseline + experimental) via the runner's --system-prompt, replacing the CLI default so the prompt is a controlled, held-constant condition.

  • config/models.py: Scenario.system_prompt field (documented).
  • orchestration/run.py: thread scenario.system_promptrun_singlebuild_command, with {cwd} → per-run worktree substitution.
  • tests: system prompt reaches build_command on every arm; NoneNone (CLI default kept — fully back-compatible).

Validity

Verified offline that baseline and experimental arms build byte-identical commands except the experimental's --mcp-config. Local CI green: ruff format --check + ruff check + 885 passed.

(Net diff is the system_prompt feature only; the branch's earlier timeout/append-prompt commit already landed on master.)

🤖 Generated with Claude Code

jahala and others added 2 commits June 23, 2026 11:05
…_prompt

FIX-TIMEOUT: the agent-subprocess kill timeout was wired to the CLI --timeout
flag (default 300), so a scenario's timeout_seconds (e.g. 600) was silently
ignored — two tilth runs on ripgrep were killed at 300s though full-sonnet set
600. The scenario runner factory now uses scenario.timeout_seconds; single-run
keeps the --timeout flag.

PROMPT-1: add Mode.append_system_prompt — a DISCLOSED per-mode instruction so a
tool can be measured as it's actually deployed (tools ship with usage guidance,
like the operator's global CLAUDE.md). claude gets --append-system-prompt;
codex/gemini prepend it to the prompt. The text is recorded as
`mode_append_system_prompt` in every JSONL record so the A/B asymmetry is never
hidden. The local tilth.yaml now nudges "prefer tilth_search/tilth_read over
Grep/Read" to address low adoption (only 14/44 non-control tasks used tilth in
the full-sonnet run).

882 tests green; ruff clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…cross arms)

copeca inherited the agent CLI's full default system prompt (which promotes
the native Read/Grep/Glob tools), so any tool-under-test that competes with
native tools was systematically under-adopted — the system prompt was an
UNCONTROLLED variable, breaking the "hold everything fixed, vary one thing"
guarantee. Empirically: the same tilth+sonnet+version that tilth's own
(lean-prompt) harness measured cheaper, copeca measured costlier, because its
agent used tilth ~30% vs tilth's ~100%.

Add Scenario.system_prompt: a fixed prompt threaded to EVERY arm (baseline +
experimental) via the runner's --system-prompt, REPLACING the CLI default so
the prompt is a controlled, held-constant condition. "{cwd}" is substituted
with the per-run worktree path. None keeps the CLI's own default (prior
behavior, fully back-compatible).

- config/models.py: Scenario.system_prompt field (documented)
- orchestration/run.py: thread scenario.system_prompt -> run_single ->
  build_command, with {cwd} substitution
- tests: system_prompt reaches build_command on every arm; None => None

Verified offline: baseline and experimental arms build byte-identical
commands except the experimental's --mcp-config.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jahala

jahala commented Jun 23, 2026

Copy link
Copy Markdown
Owner Author

Superseded by #18 — clean branch off current master. The old branch carried already-merged commit dfb27f5 (timeout+append-prompt landed separately), producing a phantom merge conflict.

@jahala jahala closed this Jun 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant