ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s

This commit is contained in:
2026-08-20 13:12:50 +00:00
commit b119135836
10275 changed files with 3284984 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
!output/
output/*
!output/release_manifest.json
!output/rejected_manifest.json
@@ -0,0 +1,6 @@
FROM python:3.12-alpine@sha256:6d43704baacd1bfbe7c295d7f13079d5d8104ed33568873133f8fc69980419df
COPY sandbox_runner.py /opt/self-modifying-agent/sandbox_runner.py
USER 65534:65534
ENTRYPOINT ["python", "-I", "/opt/self-modifying-agent/sandbox_runner.py"]
@@ -0,0 +1,3 @@
**
!Dockerfile.sandbox
!sandbox_runner.py
+57
View File
@@ -0,0 +1,57 @@
# 实验 9-6:由失败轨迹触发 Agent 自我修改
本项目演示实验 9-6 的 Agent 自我修改:生产轨迹显示同一个 `retryable=false` 错误仍被连续调用时,系统应修改 Agent 的重试与熔断控制代码,而不是只在 Prompt 中追加一句“不要重复调用”。
机制单元测试与真实验收是两条不同路径:
```bash
python -m pytest -q test_evolution.py
python run_experiment_9_6.py \
--provider ark --model doubao-seed-1-6-250615 --seed 8501
```
待验证代码验证需要 Docker。首次运行会从锁定摘要的 Python 3.12 Alpine
基础镜像自动构建内容寻址的本地沙箱镜像;也可以通过
`SELF_MODIFY_SANDBOX_IMAGE` 指定预先审核并构建好的镜像。待验证代码只在一次性
容器中执行:容器禁用网络和 IPC、使用只读根文件系统和非 root 用户、丢弃全部
Linux capabilities、禁止提权,并限制 CPU、内存、进程数、文件描述符、临时空间、
输出大小和墙钟时间。超时、OOM、Docker 不可用或协议输出异常都会关闭失败,不能
进入 Canary。
`python demo.py` 仍保留为单提案教学入口,不能单独关闭真实实验。`run_experiment_9_6.py` 才是验收入口:它先保留一个会禁用所有临时错误重试的已拒绝提案,把具体失败原因提供给真实 Coding Agent,再让确定性生成器和真实 Coding Agent 经过同一组模型外门槛。
如需改用 OpenAI 直连:
```bash
# 从仓库根目录开始:使用共享的第 8 章环境
uv sync --locked --python 3.12 --extra ch8
# Apple Silicon macOS 需要 macOS 14+(锁文件中的 bitsandbytes wheel 要求);
# 更早的 macOS 请使用下方单项目兼容路径。
# 切换目录前先激活环境:
# macOS/Linux:
source .venv/bin/activate
# Windows PowerShell: .\.venv\Scripts\Activate.ps1
# Windows cmd: .venv\Scripts\activate.bat
# 未安装 uv 时可用 pip 兜底:
# python -m pip install -e ".[ch8]"
cd chapter8/self-modifying-agent
# 迁移期间仍支持单项目兼容路径:
# python -m pip install -r requirements.txt
export OPENAI_API_KEY=your_api_key_here
python run_experiment_9_6.py --provider openai --model gpt-4o-mini
```
真实模式使用 OpenAI 兼容的 Chat Completions API 读取失败诊断和稳定源码,返回完整代码提案。模型输出仍只能写入 `validation/<run>/candidates/` 隔离目录;静态编译、失败重放、旧任务回归、发布决定与回滚版本全部由模型外部代码执行。若 LLM 生成了看似合理但破坏旧重试行为的补丁,命令会明确返回 `reject_candidate`
实验从 `failure_trajectories.json` 聚合重复故障。只有同一模式在多条轨迹中得到支持才形成修改请求;诊断模块将根因定位到 `stable/retry_policy.py`。提案生成器从稳定源码产生最小 diff,但只写入 `output/candidate/`,不会覆盖正在运行的稳定版本。
验证阶段先在宿主机做不执行源码的编译和 AST 预筛,再在 Docker 安全边界内检查公开函数签名、原失败轨迹、首次永久错误熔断、临时超时恢复、旧阈值回归、影子 Canary、回滚制品和行为指标。AST 拒绝列表只是快速纵深防御,不被视作执行不可信 Python 的安全边界。所有检查(包括 `sandbox_execution`)通过才生成 `release_to_canary`,绝不直接发布生产;否则返回 `reject_candidate``release_manifest.json` 记录失败簇、逐条来源轨迹及哈希、根因、目标组件与文件、影响预测、代码 diff、潜在回退、全部检查、提案哈希和回滚哈希。生成前后还会比较稳定代码、失败轨迹和沙箱验证器的 SHA-256,证明 Coding Agent 没有越权修改可信根。
真实运行的原始请求、原始响应、响应 ID、Token、延迟、请求/响应哈希和不含凭据的后端元数据保存在 `validation/<run>/evidence.json``validation/latest.json` 指向最近一次完整证据。当前仓库内的 [OpenRouter/GPT-5.6-sol 沙箱规范运行](validation/real_20260802T043954Z/evidence.json)使用 839 输入 Token、392 输出 Token、1,231 总 Token,供应商报告成本为 0.015955 美元;确定性提案与真实 LLM 提案均为 `release_to_canary`,且包含 `sandbox_execution` 在内的全部门槛通过。故障调用均值从基线 3.5 降为 1,临时故障恢复率保持 1.0,旧任务回归数为 0;负对照按预期被拒绝。
确定性补丁只用于可复现对照;真实验收必须包含真实 Coding Agent 的 API 回执。提案分支、失败重放、旧任务回归、灰度和回滚协议不交给生成补丁的模型自行批准。稳定代码、审计日志和发布验证器属于可信根,不在普通自我修改权限之内。
@@ -0,0 +1,205 @@
"""Fail-closed Docker boundary for model-generated policy code."""
from __future__ import annotations
from functools import lru_cache
import hashlib
import json
import os
from pathlib import Path
import subprocess
import threading
from typing import Any, Iterable
import uuid
ROOT = Path(__file__).resolve().parent
DOCKERFILE = ROOT / "Dockerfile.sandbox"
RUNNER = ROOT / "sandbox_runner.py"
DEFAULT_TIMEOUT_SECONDS = 8.0
MAX_REQUEST_BYTES = 1024 * 1024
MAX_OUTPUT_BYTES = 1024 * 1024
MAX_SOURCE_BYTES = 256 * 1024
class SandboxError(RuntimeError):
"""The candidate sandbox could not produce a trusted response."""
def _default_image() -> str:
digest = hashlib.sha256(DOCKERFILE.read_bytes() + RUNNER.read_bytes()).hexdigest()[:12]
return f"ai-agent-book/self-modifying-agent-sandbox:{digest}"
def sandbox_image() -> str:
"""Return an operator-supplied image or the content-addressed local image."""
return os.environ.get("SELF_MODIFY_SANDBOX_IMAGE", _default_image())
@lru_cache(maxsize=None)
def _ensure_image(image: str) -> None:
try:
inspect_result = subprocess.run(
["docker", "image", "inspect", image],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
timeout=10,
check=False,
)
except (FileNotFoundError, subprocess.TimeoutExpired) as exc:
raise SandboxError("Docker is required for candidate evaluation") from exc
if inspect_result.returncode == 0:
return
if os.environ.get("SELF_MODIFY_SANDBOX_IMAGE"):
raise SandboxError(f"Configured sandbox image is unavailable: {image}")
try:
build = subprocess.run(
[
"docker", "build", "--file", str(DOCKERFILE),
"--tag", image, str(ROOT),
],
stdout=subprocess.DEVNULL,
stderr=subprocess.PIPE,
text=True,
timeout=180,
check=False,
)
except (FileNotFoundError, subprocess.TimeoutExpired) as exc:
raise SandboxError("Docker is required to build the candidate sandbox") from exc
if build.returncode != 0:
detail = build.stderr[-2000:].strip()
raise SandboxError(f"Could not build candidate sandbox: {detail}")
def _docker_command(image: str, name: str) -> list[str]:
return [
"docker", "run", "--rm", "--interactive", "--name", name,
"--hostname", "candidate-sandbox",
"--network", "none",
"--ipc", "none",
"--read-only",
"--cap-drop", "ALL",
"--security-opt", "no-new-privileges:true",
"--user", "65534:65534",
"--pids-limit", "16",
"--memory", "64m",
"--memory-swap", "64m",
"--cpus", "0.5",
"--ulimit", "cpu=2:2",
"--ulimit", "nofile=64:64",
"--ulimit", "core=0:0",
"--tmpfs", "/tmp:rw,noexec,nosuid,nodev,size=16m,mode=1777",
"--workdir", "/tmp",
"--log-driver", "none",
"--env", "PYTHONDONTWRITEBYTECODE=1",
image,
]
def _bounded_reader(stream: Any, destination: bytearray, overflow: list[bool]) -> None:
while chunk := stream.read(8192):
remaining = MAX_OUTPUT_BYTES - len(destination)
if remaining > 0:
destination.extend(chunk[:remaining])
if len(chunk) > remaining:
overflow[0] = True
def _remove_container(name: str) -> None:
try:
subprocess.run(
["docker", "rm", "--force", name],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
timeout=10,
check=False,
)
except (FileNotFoundError, subprocess.TimeoutExpired):
pass
def run_in_sandbox(
action: str,
source: str,
trajectories: Iterable[dict[str, Any]],
*,
stable_source: str | None = None,
timeout_seconds: float = DEFAULT_TIMEOUT_SECONDS,
) -> dict[str, Any]:
"""Evaluate source in a disposable, resource-limited Docker container."""
try:
if len(source.encode("utf-8")) > MAX_SOURCE_BYTES:
raise SandboxError("Candidate source exceeds 256 KiB")
if stable_source is not None and len(stable_source.encode("utf-8")) > MAX_SOURCE_BYTES:
raise SandboxError("Stable source exceeds 256 KiB")
request = json.dumps({
"action": action,
"source": source,
"trajectories": list(trajectories),
"stable_source": stable_source,
}).encode("utf-8")
except (TypeError, UnicodeError, ValueError) as exc:
raise SandboxError("Candidate sandbox request is not valid JSON data") from exc
if len(request) > MAX_REQUEST_BYTES:
raise SandboxError("Candidate sandbox request exceeds 1 MiB")
image = sandbox_image()
_ensure_image(image)
name = f"agent-candidate-{uuid.uuid4().hex}"
try:
process = subprocess.Popen(
_docker_command(image, name),
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
except FileNotFoundError as exc:
raise SandboxError("Docker is required for candidate evaluation") from exc
stdout = bytearray()
stderr = bytearray()
stdout_overflow = [False]
stderr_overflow = [False]
stdout_thread = threading.Thread(
target=_bounded_reader,
args=(process.stdout, stdout, stdout_overflow),
daemon=True,
)
stderr_thread = threading.Thread(
target=_bounded_reader,
args=(process.stderr, stderr, stderr_overflow),
daemon=True,
)
stdout_thread.start()
stderr_thread.start()
assert process.stdin is not None
try:
process.stdin.write(request)
process.stdin.close()
returncode = process.wait(timeout=timeout_seconds)
except (OSError, subprocess.TimeoutExpired) as exc:
_remove_container(name)
process.kill()
process.wait()
if isinstance(exc, subprocess.TimeoutExpired):
raise SandboxError("Candidate evaluation exceeded the wall-clock limit") from exc
raise SandboxError("Candidate sandbox closed its input unexpectedly") from exc
finally:
stdout_thread.join(timeout=1)
stderr_thread.join(timeout=1)
if stdout_overflow[0] or stderr_overflow[0]:
raise SandboxError("Candidate sandbox output exceeded 1 MiB")
if returncode != 0:
detail = stderr.decode("utf-8", errors="replace").strip()[-1000:]
raise SandboxError(f"Candidate sandbox exited with {returncode}: {detail}")
try:
response = json.loads(stdout.decode("utf-8"))
except (UnicodeDecodeError, json.JSONDecodeError) as exc:
raise SandboxError("Candidate sandbox returned an invalid response") from exc
if not isinstance(response, dict) or response.get("ok") is not True:
raise SandboxError("Candidate sandbox rejected the evaluation request")
result = response.get("result")
if not isinstance(result, dict):
raise SandboxError("Candidate sandbox response has no result object")
return result
+50
View File
@@ -0,0 +1,50 @@
"""Run the complete offline self-modification release flow."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
from evolution import diagnose, generate_candidate, release_manifest, validate_candidate, write_candidate
ROOT = Path(__file__).parent
def main() -> None:
parser = argparse.ArgumentParser(description="Experiment 9-6 self-modification pipeline")
parser.add_argument("--generator", choices=("deterministic", "llm"), default="deterministic")
parser.add_argument("--model", help="real LLM model; defaults to LLM_MODEL or gpt-5.6")
args = parser.parse_args()
trajectories = json.loads((ROOT / "failure_trajectories.json").read_text(encoding="utf-8"))
stable_path = ROOT / "stable" / "retry_policy.py"
stable_source = stable_path.read_text(encoding="utf-8")
diagnosis = diagnose(trajectories)
if args.generator == "llm":
from llm_generator import generate_with_openai
candidate = generate_with_openai(stable_source, diagnosis, args.model)
else:
candidate = generate_candidate(stable_source, diagnosis)
checks = validate_candidate(candidate["source"], trajectories, stable_source)
manifest = release_manifest(stable_source, candidate, diagnosis, checks)
write_candidate(candidate["source"], ROOT / "output" / "candidate" / "retry_policy.py")
(ROOT / "output" / "release_manifest.json").write_text(
json.dumps(manifest, ensure_ascii=False, indent=2), encoding="utf-8"
)
print(f"Experiment 9-6: trajectory-triggered self-modification (generator={args.generator})\n")
print("diagnosed target:", diagnosis["target"])
print("source cases:", ", ".join(diagnosis["source_case_ids"]))
print("\nCandidate diff:\n")
print(candidate["diff"])
print("checks:", checks)
print("decision:", manifest["decision"])
print("stable file unchanged:", stable_path.read_text(encoding="utf-8") == stable_source)
print("rollback version:", manifest["rollback_version"])
if __name__ == "__main__":
main()
@@ -0,0 +1,7 @@
# Default real campaign (Volcengine Ark OpenAI-compatible API)
ARK_API_KEY=your_api_key_here
ARK_MODEL=doubao-seed-1-6-250615
# Optional alternatives
OPENAI_API_KEY=your_api_key_here
OPENROUTER_API_KEY=your_api_key_here
+322
View File
@@ -0,0 +1,322 @@
"""Auditable self-modification and trusted release gates for Experiment 9-6."""
from __future__ import annotations
import ast
from collections import defaultdict
import difflib
import hashlib
from pathlib import Path
from typing import Any, Dict, Iterable
from candidate_sandbox import MAX_SOURCE_BYTES, SandboxError, run_in_sandbox
OLD_CODES = 'NON_RETRYABLE_CODES = {"AUTH_DENIED", "INVALID_ARGUMENT"}'
NEW_CODES = 'NON_RETRYABLE_CODES = {"AUTH_DENIED", "INVALID_ARGUMENT", "PAYMENT_DECLINED"}'
OLD_RETRY = '''def should_retry(error_code, retryable, attempt):
"""Return whether another tool call should be attempted."""
return attempt < MAX_RETRIES
'''
NEW_RETRY = '''def should_retry(error_code, retryable, attempt):
"""Return whether another tool call should be attempted."""
if not retryable or error_code in NON_RETRYABLE_CODES:
return False
return attempt < MAX_RETRIES
'''
OLD_BREAKER = '''def should_open_circuit(consecutive_failures, *, error_code="", retryable=True):
"""Open after repeated failures."""
return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD
'''
NEW_BREAKER = '''def should_open_circuit(consecutive_failures, *, error_code="", retryable=True):
"""Open immediately for permanent errors; otherwise use the threshold."""
if not retryable or error_code in NON_RETRYABLE_CODES:
return consecutive_failures >= 1
return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD
'''
CHECK_NAMES = (
"static_compile",
"security_scan",
"sandbox_execution",
"public_api_compatible",
"failure_replay",
"nonretryable_circuit",
"temporary_recovery",
"old_task_regression",
"canary_ready",
"rollback_ready",
)
def sha256_text(source: str) -> str:
return hashlib.sha256(source.encode("utf-8")).hexdigest()
def _short_sha(source: str) -> str:
return sha256_text(source)[:12]
def diagnose(trajectories: Iterable[Dict[str, Any]]) -> Dict[str, Any]:
trajectories = list(trajectories)
repeated: Dict[tuple[str, str], list[Dict[str, Any]]] = defaultdict(list)
for item in trajectories:
if item.get("outcome") == "failure" and not item.get("retryable", True) and item.get("attempts", 0) > 1:
repeated[(item.get("tool", ""), item.get("error_code", ""))].append(item)
patterns = []
for (tool, error_code), items in repeated.items():
if len(items) >= 2:
patterns.append({
"cluster_id": f"{tool}:{error_code}",
"tool": tool,
"error_code": error_code,
"source_case_ids": [item["id"] for item in items],
"cross_trajectory_support": len(items),
"total_redundant_calls": sum(item["attempts"] - 1 for item in items),
})
if not patterns:
return {
"change_required": False,
"target": None,
"source_case_ids": [],
"reason": "No repeated non-retryable failure pattern has enough support.",
}
source_ids = sorted({case_id for pattern in patterns for case_id in pattern["source_case_ids"]})
sources = [
{
"id": item["id"],
"trajectory_sha256": sha256_text(repr(sorted(item.items()))),
"evidence": item.get("evidence"),
}
for item in trajectories if item.get("id") in source_ids
]
return {
"change_required": True,
"target": "stable/retry_policy.py",
"target_component": "retry_and_circuit_breaker_control",
"source_case_ids": source_ids,
"source_trajectories": sources,
"patterns": patterns,
"reason": (
"The deterministic control policy ignores retryable=false and does not open the circuit "
"for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt."
),
"change_contract": {
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure",
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change",
],
},
}
def _replace_once(source: str, old: str, new: str) -> str:
if source.count(old) != 1:
raise ValueError("Candidate patch no longer matches exactly one stable-code region")
return source.replace(old, new, 1)
def candidate_from_source(
stable_source: str,
candidate_source: str,
*,
impact_prediction: Dict[str, Any] | None = None,
generator_metadata: Dict[str, Any] | None = None,
) -> Dict[str, Any]:
"""Package generated source and provenance as a reviewable candidate."""
diff = "".join(difflib.unified_diff(
stable_source.splitlines(keepends=True),
candidate_source.splitlines(keepends=True),
fromfile="stable/retry_policy.py",
tofile="candidate/retry_policy.py",
))
added = sum(line.startswith("+") and not line.startswith("+++") for line in diff.splitlines())
deleted = sum(line.startswith("-") and not line.startswith("---") for line in diff.splitlines())
return {
"source": candidate_source,
"diff": diff,
"changed": candidate_source != stable_source,
"impact_prediction": impact_prediction or {},
"generator_metadata": generator_metadata or {},
"source_sha256": sha256_text(candidate_source),
"patch_size": {"added_lines": added, "deleted_lines": deleted, "changed_lines": added + deleted},
}
def generate_candidate(stable_source: str, diagnosis: Dict[str, Any]) -> Dict[str, Any]:
"""Generate the deterministic comparison candidate without touching stable."""
if not diagnosis.get("change_required"):
return candidate_from_source(stable_source, stable_source)
candidate = _replace_once(stable_source, OLD_CODES, NEW_CODES)
candidate = _replace_once(candidate, OLD_RETRY, NEW_RETRY)
candidate = _replace_once(candidate, OLD_BREAKER, NEW_BREAKER)
candidate = candidate.replace('VERSION = "1.0.0"', 'VERSION = "1.1.0-candidate"', 1)
return candidate_from_source(
stable_source,
candidate,
impact_prediction={
"non_retryable_calls": {"before": "up to 4", "after": 1},
"temporary_timeout_recovery_rate": {"before": 1.0, "after": 1.0},
},
generator_metadata={"generator": "deterministic", "model": None, "api_calls": 0},
)
def generate_rejected_control(stable_source: str, diagnosis: Dict[str, Any]) -> Dict[str, Any]:
"""Historical-looking bad patch: fixes the incident by disabling all retries."""
candidate = _replace_once(stable_source, OLD_RETRY, '''def should_retry(error_code, retryable, attempt):
"""Incorrect over-broad fix retained as a rejected candidate."""
return False
''')
candidate = _replace_once(candidate, OLD_BREAKER, NEW_BREAKER)
candidate = candidate.replace('VERSION = "1.0.0"', 'VERSION = "1.0.1-rejected"', 1)
return candidate_from_source(
stable_source,
candidate,
impact_prediction={
"non_retryable_calls": {"after": 1},
"temporary_timeout_recovery_rate": {"after": 0.0},
},
generator_metadata={"generator": "negative_control", "api_calls": 0},
)
def _safe_ast(source: str) -> bool:
"""Apply a fast defense-in-depth filter before sandboxed execution."""
tree = ast.parse(source)
forbidden_calls = {"eval", "exec", "compile", "open", "__import__"}
return not any(
isinstance(node, (ast.Import, ast.ImportFrom))
or (isinstance(node, ast.Call) and isinstance(node.func, ast.Name) and node.func.id in forbidden_calls)
for node in ast.walk(tree)
)
def validate_candidate(
candidate_source: str,
trajectories: Iterable[Dict[str, Any]],
stable_source: str | None = None,
) -> Dict[str, bool]:
"""Run release gates with candidate execution confined to Docker."""
checks = {name: False for name in CHECK_NAMES}
try:
oversized = len(candidate_source.encode("utf-8")) > MAX_SOURCE_BYTES
except UnicodeError:
return checks
if oversized:
return checks
try:
# Compilation and the AST scan do not execute the source. The scan is a
# fast prefilter; the container, not this deny-list, is the security boundary.
compile(candidate_source, "candidate/retry_policy.py", "exec")
checks["static_compile"] = True
checks["security_scan"] = _safe_ast(candidate_source)
if not checks["security_scan"]:
return checks
except Exception:
return checks
try:
result = run_in_sandbox(
"validate",
candidate_source,
trajectories,
stable_source=stable_source,
)
except SandboxError:
return checks
sandbox_checks = result.get("checks")
if not isinstance(sandbox_checks, dict):
return checks
checks["sandbox_execution"] = True
for name in CHECK_NAMES:
if name not in {"static_compile", "security_scan", "sandbox_execution"}:
checks[name] = sandbox_checks.get(name) is True
return checks
def behavior_metrics(candidate_source: str, trajectories: Iterable[Dict[str, Any]]) -> Dict[str, Any]:
"""Measure candidate behavior inside the same locked-down sandbox."""
try:
result = run_in_sandbox("metrics", candidate_source, trajectories)
except SandboxError:
return {
"mean_nonretryable_calls": None,
"temporary_error_recovery_rate": None,
"old_task_regressions": None,
"evaluation_failed": True,
}
metrics = result.get("metrics")
if not isinstance(metrics, dict):
return {
"mean_nonretryable_calls": None,
"temporary_error_recovery_rate": None,
"old_task_regressions": None,
"evaluation_failed": True,
}
return metrics
def release_manifest(
stable_source: str,
candidate: Dict[str, Any],
diagnosis: Dict[str, Any],
checks: Dict[str, bool],
*,
provenance: Dict[str, Any] | None = None,
) -> Dict[str, Any]:
accepted = candidate.get("changed", False) and bool(checks) and all(checks.values())
failed = [name for name, passed in checks.items() if not passed]
contract = diagnosis.get("change_contract", {})
return {
"artifact_type": "agent_control_code_patch",
"failure_cluster": diagnosis.get("patterns", []),
"source_trajectories": diagnosis.get("source_trajectories", []),
"inferred_root_cause": diagnosis.get("reason"),
"target_component": diagnosis.get("target_component"),
"target_file": diagnosis.get("target"),
"code_diff": candidate.get("diff", ""),
"impact_prediction": candidate.get("impact_prediction", {}),
"expected_fix": contract.get("expected_fix", []),
"potential_regressions": contract.get("potential_regressions", []),
"stable_version": _short_sha(stable_source),
"stable_sha256": sha256_text(stable_source),
"candidate_version": _short_sha(candidate.get("source", stable_source)),
"candidate_sha256": sha256_text(candidate.get("source", stable_source)),
"rollback_version": _short_sha(stable_source),
"rollback_sha256": sha256_text(stable_source),
# Compatibility field retained for readers of the earlier demo.
"diff": candidate.get("diff", ""),
"patch_size": candidate.get("patch_size", {}),
"checks": checks,
"failed_checks": failed,
"canary_gate": {
"eligible": accepted,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression",
},
"rollback_gate": {
"artifact_hash_matches_stable": checks.get("rollback_ready", False),
"rollback_version": _short_sha(stable_source),
},
"provenance": provenance or candidate.get("generator_metadata", {}),
"decision": "release_to_canary" if accepted else "reject_candidate",
"rejection_reason": None if accepted else (
"candidate did not change stable source" if not candidate.get("changed")
else "failed gates: " + ", ".join(failed)
),
}
def write_candidate(candidate_source: str, path: Path) -> None:
"""Write only to a candidate artifact path, never over the stable module."""
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(candidate_source, encoding="utf-8")
@@ -0,0 +1,29 @@
[
{
"id": "run-payment-001",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"retryable": false,
"attempts": 4,
"outcome": "failure",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"retryable": false,
"attempts": 3,
"outcome": "failure",
"evidence": "A second task repeated the identical non-retryable call three times."
},
{
"id": "run-timeout-001",
"tool": "inventory_lookup",
"error_code": "TEMPORARY_TIMEOUT",
"retryable": true,
"attempts": 2,
"outcome": "success",
"evidence": "A temporary timeout succeeded on the second retry."
}
]
@@ -0,0 +1,133 @@
"""Real API Coding Agent used by the Experiment 9-6 campaign."""
from __future__ import annotations
import hashlib
import json
import os
import re
import time
from typing import Any, Dict
from openai import OpenAI
from evolution import candidate_from_source
def _extract_json(text: str) -> dict[str, Any]:
cleaned = re.sub(r"^```(?:json)?\s*|\s*```$", "", text.strip(), flags=re.I)
try:
return json.loads(cleaned)
except json.JSONDecodeError:
match = re.search(r"\{.*\}", cleaned, re.S)
if not match:
raise
return json.loads(match.group(0))
def _client(provider: str) -> tuple[OpenAI, dict[str, Any]]:
if provider == "openrouter":
key = os.getenv("OPENROUTER_API_KEY")
if not key:
raise RuntimeError("OPENROUTER_API_KEY is required")
base = "https://openrouter.ai/api/v1"
return OpenAI(api_key=key, base_url=base), {
"provider": provider, "endpoint": base + "/chat/completions", "credential_env": "OPENROUTER_API_KEY"
}
if provider == "ark":
key = os.getenv("ARK_API_KEY")
if not key:
raise RuntimeError("ARK_API_KEY is required")
base = "https://ark.cn-beijing.volces.com/api/v3"
return OpenAI(api_key=key, base_url=base), {
"provider": provider, "endpoint": base + "/chat/completions", "credential_env": "ARK_API_KEY"
}
key = os.getenv("OPENAI_API_KEY")
if not key:
raise RuntimeError("OPENAI_API_KEY is required")
return OpenAI(api_key=key), {
"provider": provider, "endpoint": "https://api.openai.com/v1/chat/completions", "credential_env": "OPENAI_API_KEY"
}
def generate_with_openai(
stable_source: str,
diagnosis: Dict[str, Any],
model: str | None = None,
*,
provider: str = "openrouter",
seed: int = 8501,
rejected_history: list[dict[str, Any]] | None = None,
) -> Dict[str, Any]:
client, backend = _client(provider)
selected_model = model or (
os.getenv("ARK_MODEL", "doubao-seed-1-6-250615") if provider == "ark"
else ("openai/gpt-4o-mini" if provider == "openrouter" else "gpt-4o-mini")
)
prompt = f"""You are the Coding Agent in a controlled self-modification pipeline.
Modify only the supplied retry-policy module. Preserve both public function
signatures and retry behavior for temporary failures. Permanent failures
(retryable=false or a listed permanent code) must not be retried and must open
the circuit on the first occurrence. Update VERSION to a candidate version.
Do not import modules, access files, or alter validation/release logic.
Before the source, predict the intended impact. Return JSON only:
{{"impact_prediction": {{"non_retryable_calls": {{"before": "up to 4", "after": 1}},
"temporary_timeout_recovery_rate": {{"before": 1.0, "after": 1.0}}}},
"source": "the complete Python module"}}
Failure diagnosis:
{json.dumps(diagnosis, ensure_ascii=False, indent=2)}
Previously rejected candidates (do not repeat their failure):
{json.dumps(rejected_history or [], ensure_ascii=False, indent=2)}
Stable module:
{stable_source}
"""
request = {
"model": selected_model,
"messages": [{"role": "user", "content": prompt}],
"temperature": 0,
"seed": seed,
"max_tokens": 1400,
"response_format": {"type": "json_object"},
}
started = time.perf_counter()
response = client.chat.completions.create(**request)
elapsed = time.perf_counter() - started
raw = response.model_dump(mode="json", exclude_none=True)
payload = _extract_json(response.choices[0].message.content or "")
source = str(payload.get("source", ""))
if not source.endswith("\n"):
source += "\n"
usage = raw.get("usage") or {}
cost = usage.get("cost")
receipt = {
"backend": {**backend, "model": selected_model, "credential_value_recorded": False},
"request": request,
"response": raw,
"request_sha256": hashlib.sha256(json.dumps(request, sort_keys=True).encode()).hexdigest(),
"response_sha256": hashlib.sha256(json.dumps(raw, sort_keys=True).encode()).hexdigest(),
"elapsed_seconds": round(elapsed, 6),
"usage": {
"prompt_tokens": int(usage.get("prompt_tokens") or 0),
"completion_tokens": int(usage.get("completion_tokens") or 0),
"total_tokens": int(usage.get("total_tokens") or 0),
"provider_reported_cost_usd": float(cost) if cost is not None else None,
"cost_qualification": (
"provider-native usage.cost" if cost is not None
else "provider did not expose monetary cost; no price was guessed"
),
},
}
return candidate_from_source(
stable_source,
source,
impact_prediction=payload.get("impact_prediction") or {},
generator_metadata={
"generator": "real_llm_coding_agent", "model": selected_model,
"provider": provider, "seed": seed, "api_calls": 1, "receipt": receipt,
},
)
@@ -0,0 +1,94 @@
{
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,18 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rejected\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n \n \n def should_retry(error_code, retryable, attempt):\n- \"\"\"Return whether another tool call should be attempted.\"\"\"\n- return attempt < MAX_RETRIES\n+ \"\"\"Incorrect over-broad fix retained as a rejected candidate.\"\"\"\n+ return False\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"after": 1
},
"temporary_timeout_recovery_rate": {
"after": 0.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "824bbfb244a7",
"candidate_sha256": "824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,18 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rejected\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n \n \n def should_retry(error_code, retryable, attempt):\n- \"\"\"Return whether another tool call should be attempted.\"\"\"\n- return attempt < MAX_RETRIES\n+ \"\"\"Incorrect over-broad fix retained as a rejected candidate.\"\"\"\n+ return False\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 6,
"deleted_lines": 4,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"security_scan": true,
"sandbox_execution": true,
"public_api_compatible": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": false,
"old_task_regression": false,
"canary_ready": false,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [
"temporary_recovery",
"old_task_regression",
"canary_ready"
],
"canary_gate": {
"eligible": false,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "negative_control",
"api_calls": 0
},
"decision": "reject_candidate",
"rejection_reason": "failed gates: temporary_recovery, old_task_regression, canary_ready"
}
@@ -0,0 +1,180 @@
{
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,6 +1,6 @@\n-\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n+\"\"\"Candidate version 1.0.1-rc.1 with permanent-failure handling.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rc.1\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n@@ -8,9 +8,13 @@\n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent failures or after repeated temporary failures.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"before": "up to 4",
"after": 1
},
"temporary_timeout_recovery_rate": {
"before": 1.0,
"after": 1.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "d6e79810003e",
"candidate_sha256": "d6e79810003e7d5f3e8d43ace0688e38033b08a4752bb0dfb9260d9bbe976b8f",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,6 +1,6 @@\n-\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n+\"\"\"Candidate version 1.0.1-rc.1 with permanent-failure handling.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rc.1\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n@@ -8,9 +8,13 @@\n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent failures or after repeated temporary failures.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 7,
"deleted_lines": 3,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"security_scan": true,
"sandbox_execution": true,
"public_api_compatible": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": true,
"old_task_regression": true,
"canary_ready": true,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [],
"canary_gate": {
"eligible": true,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "real_llm_coding_agent",
"model": "openai/gpt-5.6-sol",
"provider": "openrouter",
"seed": 8501,
"api_calls": 1,
"receipt": {
"backend": {
"provider": "openrouter",
"endpoint": "https://openrouter.ai/api/v1/chat/completions",
"credential_env": "OPENROUTER_API_KEY",
"model": "openai/gpt-5.6-sol",
"credential_value_recorded": false
},
"request": {
"model": "openai/gpt-5.6-sol",
"messages": [
{
"role": "user",
"content": "You are the Coding Agent in a controlled self-modification pipeline.\n\nModify only the supplied retry-policy module. Preserve both public function\nsignatures and retry behavior for temporary failures. Permanent failures\n(retryable=false or a listed permanent code) must not be retried and must open\nthe circuit on the first occurrence. Update VERSION to a candidate version.\nDo not import modules, access files, or alter validation/release logic.\n\nBefore the source, predict the intended impact. Return JSON only:\n{\"impact_prediction\": {\"non_retryable_calls\": {\"before\": \"up to 4\", \"after\": 1},\n\"temporary_timeout_recovery_rate\": {\"before\": 1.0, \"after\": 1.0}},\n\"source\": \"the complete Python module\"}\n\nFailure diagnosis:\n{\n \"change_required\": true,\n \"target\": \"stable/retry_policy.py\",\n \"target_component\": \"retry_and_circuit_breaker_control\",\n \"source_case_ids\": [\n \"run-payment-001\",\n \"run-payment-002\"\n ],\n \"source_trajectories\": [\n {\n \"id\": \"run-payment-001\",\n \"trajectory_sha256\": \"4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008\",\n \"evidence\": \"The same declined payment was submitted four times.\"\n },\n {\n \"id\": \"run-payment-002\",\n \"trajectory_sha256\": \"6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59\",\n \"evidence\": \"A second task repeated the identical non-retryable call three times.\"\n }\n ],\n \"patterns\": [\n {\n \"cluster_id\": \"charge_card:PAYMENT_DECLINED\",\n \"tool\": \"charge_card\",\n \"error_code\": \"PAYMENT_DECLINED\",\n \"source_case_ids\": [\n \"run-payment-001\",\n \"run-payment-002\"\n ],\n \"cross_trajectory_support\": 2,\n \"total_redundant_calls\": 5\n }\n ],\n \"reason\": \"The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.\",\n \"change_contract\": {\n \"expected_fix\": [\n \"non-retryable tool-call attempts fall to one\",\n \"the circuit opens on the first permanent failure\"\n ],\n \"potential_regressions\": [\n \"temporary timeouts stop retrying\",\n \"the five-failure circuit threshold changes for retryable errors\",\n \"public function signatures change\"\n ]\n }\n}\n\nPreviously rejected candidates (do not repeat their failure):\n[\n {\n \"candidate_sha256\": \"824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2\",\n \"failed_checks\": [\n \"temporary_recovery\",\n \"old_task_regression\",\n \"canary_ready\"\n ],\n \"rejection_reason\": \"failed gates: temporary_recovery, old_task_regression, canary_ready\",\n \"failure\": \"disabled temporary-timeout retries\"\n }\n]\n\nStable module:\n\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n\nVERSION = \"1.0.0\"\nMAX_RETRIES = 3\nCIRCUIT_BREAKER_THRESHOLD = 5\nNON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n\n\ndef should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n return attempt < MAX_RETRIES\n\n\ndef should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n \"\"\"Open after repeated failures.\"\"\"\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n\n"
}
],
"temperature": 0,
"seed": 8501,
"max_tokens": 1400,
"response_format": {
"type": "json_object"
}
},
"response": {
"id": "gen-1785645586-58eflec0vxlXmqNTlbkd",
"choices": [
{
"finish_reason": "stop",
"index": 0,
"message": {
"content": "{\"impact_prediction\":{\"non_retryable_calls\":{\"before\":\"up to 4\",\"after\":1},\"temporary_timeout_recovery_rate\":{\"before\":1.0,\"after\":1.0}},\"source\":\"\\\"\\\"\\\"Candidate version 1.0.1-rc.1 with permanent-failure handling.\\\"\\\"\\\"\\n\\nVERSION = \\\"1.0.1-rc.1\\\"\\nMAX_RETRIES = 3\\nCIRCUIT_BREAKER_THRESHOLD = 5\\nNON_RETRYABLE_CODES = {\\\"AUTH_DENIED\\\", \\\"INVALID_ARGUMENT\\\"}\\n\\n\\ndef should_retry(error_code, retryable, attempt):\\n \\\"\\\"\\\"Return whether another tool call should be attempted.\\\"\\\"\\\"\\n if not retryable or error_code in NON_RETRYABLE_CODES:\\n return False\\n return attempt < MAX_RETRIES\\n\\n\\ndef should_open_circuit(consecutive_failures, *, error_code=\\\"\\\", retryable=True):\\n \\\"\\\"\\\"Open immediately for permanent failures or after repeated temporary failures.\\\"\\\"\\\"\\n if not retryable or error_code in NON_RETRYABLE_CODES:\\n return consecutive_failures >= 1\\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\\n\"}",
"role": "assistant",
"reasoning_details": [
{
"type": "reasoning.encrypted",
"data": "gAAAAABqbsoVfzLT_630yuZzHKyd8nnXw_G6aqojKdjAmzVDbLd4Xn-Q3mIKe2go0qV-MzGTWKLAI49dpBvB7Rh_5pD2V7g9Lo20b0upq1QQnrlwSgTTkNNIU42VP09tK7BlainxGC3VjVQzoiDnzW1ycnev5uExeR6RMeYeK4OycCtSm432sFdjGobCDAkD63hztrlRR9LbpO5F_N-r9FE6XK9__6rPfpVxwssCnzw6UrJSIrAnY78EnxrZ5Brr_x7TS1DRWkKycysVRmdyH7lialKB5-VQqHVYnzGIDRmInx2z8Eb33a0oxFKoZ60wm4Dt51u3B4ZigQuSnm8qaL0C3e6Sx1CcMjqgkvAveoDqvPiRe2Jn99gGD1Zb2a4QuzpWFJoPBw0wP-5Ftr_9oeiXXIrC-iV6WcqW60nWo3T8QoE8AyL5xPhgkYOXTsWxB6eE8qhUcdfUkPI6Jb5WzJJV6aBYPE8VtUOt0a-kpKSs7VoHqBXZLKb6XBUJuRA1kNfD9-878znM_o0HLa-zeXAh0o5sRU3tm8JUFM2wTPC4vIW9j6MBneAnSAgPP5-ecZ8zNcfJwX8tGq6pv8m7t8fNw6hBFhweTz0H6nfP40ew75rl20hlSwzZpvhxNrqQ7sDEgHSS_pSeMEyy_3Q_3gJjRII-63s5oFCV6KA4J-3y6rTq8B8nBWCrmC6t6Wr154B8duIsKEj5XkwqJwJqVJ0ve0Zn1ajrnoT5U9koJ4gr8QQHjGGzeB8iWKYlXDj7U3DRnfFpDi2W9ITie15t9KGl4vgwLqGpC4W3Tw0ler9B1iI8RI4guTstB-P3kk1AL3Wy23w5NOZpvGtAFHmq0tTT2p7pevH_1vreX8VMrXpnR4TtRXS_ozgbJhg7SzikZYlL43F_6mpmJxxg5FvTaj_J2QEV-sXNu0HkYIk7SarA5ULcDflz05fperzFaKpc6DdXtar9Mufjhn24mX1a8799OAZbgS9h3vaFa0z-7cBUTfplDVVydBNxteka07DevlG9fxTQCi9KjhOhqMH3oadsDbiufIp2YeGz3bocIBTIhPVVUoL9ywJW7kwVIfDFUV_hONXVKfhjWjH-Q0O3BCPn76nmUnyDlZrrggLqm5YDLvulyRZzspRVryr4IcbOSC4tK3n8s4-v6zNsnPtszq7sSNyxoTqryCQlrifvFcYOZQw4Cc0CHiKwojD7vQsjy1q4m3If6IfRXDbK4kOdkajkOSj-ir9kNRu1r04fb6eMbIRZYmbkfoUkoT17fJT5ruSinGmvKs8B4MS8896hpzIXLaxmd_4rdg0j4byhJjvQHiIjVDVdc3icZT6RAuwGuv2VlkoH6gD4UsJTQY7TTzDCs96-add1yczyk9Az2B74qXLQgstAy3ubGDhM-QjmEMhU6fULqriEbJZSk-u-HYPVJ3CtJSHXFnviF3ur6FRQr1bvk4s0lrksXPOPmtR3Gg26UiPQET_JwsvafY_ttLJ2wbudPzhGSijztaphFjmnFWkH53xLNRMACNPi_fXuTXwcoSwIc0M_pa2MVooxFAlDsiNYhlyKfgYY9aB77RAmqfHx1movlyjgWJlQm1vvcngw3VxYHoG_kGu4fFQn5Kd2hC5rbrd4a4v3lPCzQkAKGTDqqsjYyH_H0lg4RkVYo-n_iGNWRlUI5blONowfxTXn4WS5oP7QGajw0WFbPI6FOcv3ISK8CJYCC_fjrtJoOia2OC1rVRzAqr1EuxWH6H_W9gQl0dae0CZUC_XTC8kZGvcKEC7hBz-u3OdRi4iycAYOPxlzMffE",
"format": "openai-responses-v1",
"id": "rs_09bdf9a0a95f7f05016a6eca1367a8819ebed6d613bbe9886e",
"index": 0
}
]
},
"native_finish_reason": "completed"
}
],
"created": 1785645586,
"model": "openai/gpt-5.6-sol",
"object": "chat.completion",
"service_tier": "default",
"usage": {
"completion_tokens": 392,
"prompt_tokens": 839,
"total_tokens": 1231,
"completion_tokens_details": {
"audio_tokens": 0,
"reasoning_tokens": 128,
"image_tokens": 0
},
"prompt_tokens_details": {
"audio_tokens": 0,
"cached_tokens": 0,
"cache_write_tokens": 0,
"video_tokens": 0
},
"cost": 0.015955,
"is_byok": false,
"cost_details": {
"upstream_inference_cost": 0.015955,
"upstream_inference_prompt_cost": 0.004195,
"upstream_inference_completions_cost": 0.01176
}
},
"provider": "OpenAI"
},
"request_sha256": "80938ad7618b7a10cbf6a441221678a0e08a3acd88e03a9277b5b48c767b37b9",
"response_sha256": "0547761669dd89448a523da688652d900c055c104d208c20681a0055e19feeb3",
"elapsed_seconds": 4.693797,
"usage": {
"prompt_tokens": 839,
"completion_tokens": 392,
"total_tokens": 1231,
"provider_reported_cost_usd": 0.015955,
"cost_qualification": "provider-native usage.cost"
}
}
},
"decision": "release_to_canary",
"rejection_reason": null
}
@@ -0,0 +1,2 @@
openai>=1.68.0
python-dotenv>=1.0.0
@@ -0,0 +1,247 @@
#!/usr/bin/env python3
"""Run the real Coding-Agent self-modification campaign for Experiment 9-6."""
from __future__ import annotations
import argparse
from datetime import datetime, timezone
import hashlib
import json
from pathlib import Path
import shutil
from typing import Any
from candidate_sandbox import sandbox_image
from evolution import (
behavior_metrics,
diagnose,
generate_candidate,
generate_rejected_control,
release_manifest,
sha256_text,
validate_candidate,
write_candidate,
)
from llm_generator import generate_with_openai
ROOT = Path(__file__).resolve().parent
def _sha_file(path: Path) -> str:
return hashlib.sha256(path.read_bytes()).hexdigest()
def _manifest_fields_complete(manifest: dict[str, Any]) -> bool:
required = {
"failure_cluster", "source_trajectories", "inferred_root_cause",
"target_component", "target_file", "code_diff", "impact_prediction",
"expected_fix", "potential_regressions", "checks", "candidate_version",
"rollback_version", "provenance", "decision",
}
return required.issubset(manifest) and all(manifest.get(key) is not None for key in required)
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--provider", choices=("ark", "openrouter", "openai"), default="ark")
parser.add_argument("--model", default="doubao-seed-1-6-250615")
parser.add_argument("--seed", type=int, default=8501)
parser.add_argument("--output-dir", type=Path)
args = parser.parse_args()
stable_path = ROOT / "stable" / "retry_policy.py"
trajectories_path = ROOT / "failure_trajectories.json"
trusted_paths = {
"evolution.py": ROOT / "evolution.py",
"candidate_sandbox.py": ROOT / "candidate_sandbox.py",
"sandbox_runner.py": ROOT / "sandbox_runner.py",
"Dockerfile.sandbox": ROOT / "Dockerfile.sandbox",
}
stable_source = stable_path.read_text(encoding="utf-8")
trajectories = json.loads(trajectories_path.read_text(encoding="utf-8"))
immutable_before = {
"stable/retry_policy.py": _sha_file(stable_path),
"failure_trajectories.json": _sha_file(trajectories_path),
**{name: _sha_file(path) for name, path in trusted_paths.items()},
}
diagnosis = diagnose(trajectories)
# The rejected control is evaluated first so its concrete failure can be
# supplied to the real Coding Agent as bounded historical context.
rejected = generate_rejected_control(stable_source, diagnosis)
rejected_checks = validate_candidate(rejected["source"], trajectories, stable_source)
rejected_manifest = release_manifest(stable_source, rejected, diagnosis, rejected_checks)
rejected_history = [{
"candidate_sha256": rejected["source_sha256"],
"failed_checks": rejected_manifest["failed_checks"],
"rejection_reason": rejected_manifest["rejection_reason"],
"failure": "disabled temporary-timeout retries",
}]
deterministic = generate_candidate(stable_source, diagnosis)
llm = generate_with_openai(
stable_source,
diagnosis,
args.model,
provider=args.provider,
seed=args.seed,
rejected_history=rejected_history,
)
immutable_after_generation = {
"stable/retry_policy.py": _sha_file(stable_path),
"failure_trajectories.json": _sha_file(trajectories_path),
**{name: _sha_file(path) for name, path in trusted_paths.items()},
}
protected_unchanged = immutable_before == immutable_after_generation
candidates = {
"deterministic": deterministic,
"real_llm": llm,
"rejected_control": rejected,
}
manifests = {}
metrics = {"stable_buggy_baseline": behavior_metrics(stable_source, trajectories)}
for name, candidate in candidates.items():
checks = validate_candidate(candidate["source"], trajectories, stable_source)
checks["protected_surfaces_unchanged"] = protected_unchanged
manifests[name] = release_manifest(
stable_source,
candidate,
diagnosis,
checks,
provenance=candidate.get("generator_metadata", {}),
)
metrics[name] = behavior_metrics(candidate["source"], trajectories)
stamp = datetime.now(timezone.utc).strftime("real_%Y%m%dT%H%M%SZ")
output_dir = args.output_dir or ROOT / "validation" / stamp
output_dir.mkdir(parents=True, exist_ok=False)
for name, candidate in candidates.items():
write_candidate(candidate["source"], output_dir / "candidates" / name / "retry_policy.py")
(output_dir / f"{name}_manifest.json").write_text(
json.dumps(manifests[name], ensure_ascii=False, indent=2), encoding="utf-8"
)
decisions = [manifest["decision"] for manifest in manifests.values()]
accepted_count = decisions.count("release_to_canary")
comparison = {
name: {
"decision": manifests[name]["decision"],
"checks": manifests[name]["checks"],
"patch_size": candidate["patch_size"],
"behavior": metrics[name],
}
for name, candidate in candidates.items()
}
llm_receipt = llm["generator_metadata"]["receipt"]
gates = {
"cross_trajectory_support_met": diagnosis["patterns"][0]["cross_trajectory_support"] >= 2,
"root_cause_targets_control_code": diagnosis["target"] == "stable/retry_policy.py",
"real_coding_model_called": (
llm["generator_metadata"].get("api_calls") == 1
and bool(llm_receipt["response"].get("id"))
),
"impact_prediction_precedes_validation": bool(llm.get("impact_prediction")),
"all_candidates_isolated": stable_path.read_text(encoding="utf-8") == stable_source,
"trusted_surfaces_unchanged": protected_unchanged,
"same_release_gate_for_both_generators": (
set(manifests["deterministic"]["checks"]) == set(manifests["real_llm"]["checks"])
),
"deterministic_candidate_release_to_canary": manifests["deterministic"]["decision"] == "release_to_canary",
"real_llm_candidate_release_to_canary": manifests["real_llm"]["decision"] == "release_to_canary",
"known_bad_candidate_rejected_and_retained": (
manifests["rejected_control"]["decision"] == "reject_candidate"
and bool(manifests["rejected_control"]["rejection_reason"])
),
"failure_replay_reduces_calls": (
metrics["real_llm"]["mean_nonretryable_calls"] == 1.0
and metrics["stable_buggy_baseline"]["mean_nonretryable_calls"] > 1.0
),
"temporary_recovery_preserved": metrics["real_llm"]["temporary_error_recovery_rate"] == 1.0,
"old_task_regression_zero": metrics["real_llm"]["old_task_regressions"] == 0,
"canary_only_not_production": all(
manifest["decision"] in {"release_to_canary", "reject_candidate"} for manifest in manifests.values()
),
"rollback_hash_pinned_to_stable": all(
manifest["rollback_sha256"] == sha256_text(stable_source) for manifest in manifests.values()
),
"release_manifest_fields_complete": all(_manifest_fields_complete(item) for item in manifests.values()),
}
report = {
"experiment": "9-6",
"executed_at": datetime.now(timezone.utc).isoformat(),
"execution_mode": "real_api_coding_agent_plus_model_external_release_harness",
"provider": args.provider,
"model": args.model,
"seed": args.seed,
"input_artifacts": {
"stable_sha256": immutable_before["stable/retry_policy.py"],
"trajectory_sha256": immutable_before["failure_trajectories.json"],
"validator_sha256_before_generation": immutable_before["evolution.py"],
"validator_sha256_after_generation": immutable_after_generation["evolution.py"],
"trusted_surface_sha256_before": {
name: immutable_before[name] for name in trusted_paths
},
"trusted_surface_sha256_after": {
name: immutable_after_generation[name] for name in trusted_paths
},
},
"candidate_sandbox": {
"image": sandbox_image(),
"network": "none",
"root_filesystem": "read_only",
"user": "65534:65534",
"memory": "64m",
"cpus": 0.5,
"wall_clock_timeout_seconds": 8.0,
},
"diagnosis": diagnosis,
"rejected_history_given_to_coding_agent": rejected_history,
"behavior_metrics": metrics,
"comparison": comparison,
"manifests": manifests,
"raw_api_receipts": [llm_receipt],
"cost": llm_receipt["usage"],
"candidate_acceptance_rate": accepted_count / len(candidates),
"gates": gates,
"accepted": all(gates.values()),
}
evidence_path = output_dir / "evidence.json"
evidence_path.write_text(json.dumps(report, ensure_ascii=False, indent=2), encoding="utf-8")
evidence_sha = _sha_file(evidence_path)
(output_dir / "evidence.sha256").write_text(
evidence_sha + " evidence.json\n", encoding="utf-8"
)
(output_dir / "artifact_hashes.json").write_text(json.dumps({
str(path.relative_to(output_dir)): _sha_file(path)
for path in sorted(output_dir.rglob("*.py"))
}, indent=2), encoding="utf-8")
# Canonical, credential-free evidence and the manuscript-required manifest.
canonical = ROOT / "validation" / "latest.json"
canonical.parent.mkdir(exist_ok=True)
shutil.copyfile(evidence_path, canonical)
(ROOT / "validation" / "latest.sha256").write_text(
evidence_sha + " latest.json\n", encoding="utf-8"
)
(ROOT / "output").mkdir(exist_ok=True)
(ROOT / "output" / "release_manifest.json").write_text(
json.dumps(manifests["real_llm"], ensure_ascii=False, indent=2), encoding="utf-8"
)
(ROOT / "output" / "rejected_manifest.json").write_text(
json.dumps(manifests["rejected_control"], ensure_ascii=False, indent=2), encoding="utf-8"
)
print(json.dumps({
"evidence": str(evidence_path.relative_to(ROOT)),
"evidence_sha256": evidence_sha,
"accepted": report["accepted"],
"decisions": {name: item["decision"] for name, item in manifests.items()},
"metrics": metrics,
"cost": report["cost"],
}, ensure_ascii=False, indent=2))
return 0 if report["accepted"] else 1
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,161 @@
"""Container entrypoint. Never import this module in the trusted host process."""
from __future__ import annotations
from contextlib import redirect_stderr, redirect_stdout
import inspect
import json
import sys
from typing import Any
MAX_REQUEST_BYTES = 1024 * 1024
SANDBOX_CHECKS = (
"public_api_compatible",
"failure_replay",
"nonretryable_circuit",
"temporary_recovery",
"old_task_regression",
"canary_ready",
"rollback_ready",
)
class _NullWriter:
def write(self, value: str) -> int:
return len(value)
def flush(self) -> None:
pass
def _namespace(source: str) -> dict[str, Any]:
namespace: dict[str, Any] = {}
exec(compile(source, "candidate/retry_policy.py", "exec"), namespace)
return namespace
def _temporary_recovery(namespace: dict[str, Any]) -> bool:
return bool(
namespace["should_retry"]("TEMPORARY_TIMEOUT", True, 0)
and namespace["should_retry"]("TEMPORARY_TIMEOUT", True, 1)
)
def _validate(payload: dict[str, Any]) -> dict[str, bool]:
checks = {name: False for name in SANDBOX_CHECKS}
try:
namespace = _namespace(payload["source"])
except Exception:
return checks
if not callable(namespace.get("should_retry")) or not callable(
namespace.get("should_open_circuit")
):
return checks
try:
checks["public_api_compatible"] = (
str(inspect.signature(namespace["should_retry"])) == "(error_code, retryable, attempt)"
and str(inspect.signature(namespace["should_open_circuit"]))
== "(consecutive_failures, *, error_code='', retryable=True)"
)
except (TypeError, ValueError):
return checks
if not checks["public_api_compatible"]:
return checks
try:
failures = [
item for item in payload["trajectories"] if item.get("outcome") == "failure"
]
checks["failure_replay"] = bool(failures) and all(
not namespace["should_retry"](item["error_code"], item["retryable"], attempt)
for item in failures for attempt in range(item["attempts"])
)
checks["nonretryable_circuit"] = bool(failures) and all(
namespace["should_open_circuit"](
1, error_code=item["error_code"], retryable=item["retryable"]
)
for item in failures
)
checks["temporary_recovery"] = _temporary_recovery(namespace)
checks["old_task_regression"] = all((
namespace["should_retry"]("TEMPORARY_TIMEOUT", True, 0),
namespace["should_retry"]("TEMPORARY_TIMEOUT", True, 2),
not namespace["should_retry"]("TEMPORARY_TIMEOUT", True, 3),
not namespace["should_open_circuit"](
4, error_code="TEMPORARY_TIMEOUT", retryable=True
),
namespace["should_open_circuit"](
5, error_code="TEMPORARY_TIMEOUT", retryable=True
),
))
checks["canary_ready"] = all((
not namespace["should_retry"]("AUTH_DENIED", True, 0),
namespace["should_open_circuit"](
1, error_code="AUTH_DENIED", retryable=True
),
_temporary_recovery(namespace),
))
except Exception:
return checks
stable_source = payload.get("stable_source")
if stable_source is None:
checks["rollback_ready"] = True
else:
try:
rollback = _namespace(stable_source)
checks["rollback_ready"] = bool(
rollback.get("VERSION") == "1.0.0"
and rollback["should_retry"]("TEMPORARY_TIMEOUT", True, 0)
and not rollback["should_retry"]("TEMPORARY_TIMEOUT", True, 3)
)
except Exception:
checks["rollback_ready"] = False
return checks
def _metrics(payload: dict[str, Any]) -> dict[str, Any]:
namespace = _namespace(payload["source"])
failures = [item for item in payload["trajectories"] if item.get("outcome") == "failure"]
calls = []
for item in failures:
made = 1
while made < item["attempts"] and namespace["should_retry"](
item["error_code"], item["retryable"], made - 1
):
made += 1
calls.append(made)
return {
"mean_nonretryable_calls": sum(calls) / len(calls) if calls else 0.0,
"temporary_error_recovery_rate": float(_temporary_recovery(namespace)),
"old_task_regressions": 0 if all((
namespace["should_retry"]("TEMPORARY_TIMEOUT", True, 0),
not namespace["should_retry"]("TEMPORARY_TIMEOUT", True, 3),
)) else 1,
}
def main() -> int:
raw = sys.stdin.buffer.read(MAX_REQUEST_BYTES + 1)
if len(raw) > MAX_REQUEST_BYTES:
return 2
try:
payload = json.loads(raw)
action = payload["action"]
with redirect_stdout(_NullWriter()), redirect_stderr(_NullWriter()):
if action == "validate":
result = {"checks": _validate(payload)}
elif action == "metrics":
result = {"metrics": _metrics(payload)}
else:
return 2
except (Exception, SystemExit):
return 1
sys.stdout.write(json.dumps({"ok": True, "result": result}, separators=(",", ":")))
return 0
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,16 @@
"""Stable version 1.0.0. It intentionally contains the reproduced bug."""
VERSION = "1.0.0"
MAX_RETRIES = 3
CIRCUIT_BREAKER_THRESHOLD = 5
NON_RETRYABLE_CODES = {"AUTH_DENIED", "INVALID_ARGUMENT"}
def should_retry(error_code, retryable, attempt):
"""Return whether another tool call should be attempted."""
return attempt < MAX_RETRIES
def should_open_circuit(consecutive_failures, *, error_code="", retryable=True):
"""Open after repeated failures."""
return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD
@@ -0,0 +1,44 @@
import unittest
from unittest.mock import patch
from candidate_sandbox import MAX_SOURCE_BYTES, SandboxError, _docker_command, run_in_sandbox
class CandidateSandboxConfigurationTest(unittest.TestCase):
def test_docker_command_enforces_isolation_and_resource_limits(self):
command = _docker_command("sandbox:test", "candidate-test")
rendered = " ".join(command)
for expected in (
"--network none",
"--ipc none",
"--read-only",
"--cap-drop ALL",
"--security-opt no-new-privileges:true",
"--user 65534:65534",
"--pids-limit 16",
"--memory 64m",
"--memory-swap 64m",
"--cpus 0.5",
"--ulimit cpu=2:2",
"--log-driver none",
):
with self.subTest(expected=expected):
self.assertIn(expected, rendered)
self.assertNotIn("--volume", command)
self.assertNotIn("--mount", command)
def test_oversized_source_is_rejected_before_docker_starts(self):
with patch("candidate_sandbox._ensure_image") as ensure_image:
with self.assertRaisesRegex(SandboxError, "exceeds 256 KiB"):
run_in_sandbox("validate", "x" * (MAX_SOURCE_BYTES + 1), [])
ensure_image.assert_not_called()
def test_malformed_unicode_is_rejected_before_docker_starts(self):
with patch("candidate_sandbox._ensure_image") as ensure_image:
with self.assertRaisesRegex(SandboxError, "not valid JSON data"):
run_in_sandbox("validate", "\ud800", [])
ensure_image.assert_not_called()
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,154 @@
import json
import tempfile
import unittest
from pathlib import Path
import uuid
from evolution import (
behavior_metrics, diagnose, generate_candidate, generate_rejected_control,
release_manifest, validate_candidate,
)
ROOT = Path(__file__).parent
class SelfModificationTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.trajectories = json.loads((ROOT / "failure_trajectories.json").read_text(encoding="utf-8"))
cls.stable = (ROOT / "stable" / "retry_policy.py").read_text(encoding="utf-8")
cls.diagnosis = diagnose(cls.trajectories)
cls.candidate = generate_candidate(cls.stable, cls.diagnosis)
def test_diagnosis_selects_control_code_not_prompt(self):
self.assertTrue(self.diagnosis["change_required"])
self.assertEqual("stable/retry_policy.py", self.diagnosis["target"])
self.assertNotIn("prompt", self.diagnosis["target"])
self.assertEqual(2, len(self.diagnosis["source_case_ids"]))
def test_candidate_stops_permanent_error_and_keeps_temporary_retry(self):
checks = validate_candidate(self.candidate["source"], self.trajectories)
self.assertTrue(all(checks.values()))
self.assertIn("if not retryable", self.candidate["source"])
self.assertIn("PAYMENT_DECLINED", self.candidate["source"])
def test_behavior_metrics_are_evaluated_in_sandbox(self):
metrics = behavior_metrics(self.candidate["source"], self.trajectories)
self.assertEqual(1.0, metrics["mean_nonretryable_calls"])
self.assertEqual(1.0, metrics["temporary_error_recovery_rate"])
self.assertEqual(0, metrics["old_task_regressions"])
def test_release_manifest_keeps_rollback_and_stable_source(self):
checks = validate_candidate(self.candidate["source"], self.trajectories)
manifest = release_manifest(self.stable, self.candidate, self.diagnosis, checks)
self.assertEqual("release_to_canary", manifest["decision"])
self.assertEqual(manifest["stable_version"], manifest["rollback_version"])
self.assertIn('VERSION = "1.0.0"', self.stable)
def test_regression_failure_rejects_candidate(self):
checks = {"static_compile": True, "failure_replay": True, "old_task_regression": False}
manifest = release_manifest(self.stable, self.candidate, self.diagnosis, checks)
self.assertEqual("reject_candidate", manifest["decision"])
def test_bad_fix_is_retained_with_concrete_rejection_reason(self):
candidate = generate_rejected_control(self.stable, self.diagnosis)
checks = validate_candidate(candidate["source"], self.trajectories, self.stable)
manifest = release_manifest(self.stable, candidate, self.diagnosis, checks)
self.assertEqual("reject_candidate", manifest["decision"])
self.assertIn("temporary_recovery", manifest["failed_checks"])
self.assertTrue(manifest["rejection_reason"])
def test_manifest_contains_change_contract_canary_and_rollback(self):
checks = validate_candidate(self.candidate["source"], self.trajectories, self.stable)
manifest = release_manifest(self.stable, self.candidate, self.diagnosis, checks)
self.assertTrue(manifest["failure_cluster"])
self.assertTrue(manifest["source_trajectories"])
self.assertEqual("retry_and_circuit_breaker_control", manifest["target_component"])
self.assertTrue(manifest["expected_fix"])
self.assertTrue(manifest["potential_regressions"])
self.assertTrue(manifest["canary_gate"]["eligible"])
self.assertEqual(manifest["stable_sha256"], manifest["rollback_sha256"])
def test_degenerate_candidate_is_rejected_without_crashing(self):
# A syntactically valid but degenerate source (e.g. an empty LLM reply)
# compiles yet defines neither public function; validate_candidate must
# reject it cleanly, not raise KeyError from the behavior gates.
for source in ("\n", "# only a comment\n"):
checks = validate_candidate(source, self.trajectories)
self.assertFalse(all(checks.values()))
self.assertFalse(checks["failure_replay"])
checks = validate_candidate("\ud800", self.trajectories)
self.assertFalse(all(checks.values()))
def test_candidate_exception_is_rejected_without_crashing(self):
source = self.candidate["source"].replace(
' """Return whether another tool call should be attempted."""',
' raise RuntimeError("candidate failed")',
1,
)
checks = validate_candidate(source, self.trajectories)
self.assertTrue(checks["public_api_compatible"])
self.assertFalse(checks["failure_replay"])
def test_unsafe_candidate_is_not_executed_during_validation(self):
# The security scan must run before the candidate is exec()'d, so a
# source flagged unsafe never runs its module-level side effects.
with tempfile.TemporaryDirectory() as directory:
marker = Path(directory) / "marker"
unsafe = (
"import pathlib\n"
f"pathlib.Path({str(marker)!r}).write_text('ran')\n"
"def should_retry(error_code, retryable, attempt):\n return False\n"
"def should_open_circuit(consecutive_failures, *, error_code='', retryable=True):\n"
" return True\n"
)
checks = validate_candidate(unsafe, self.trajectories)
self.assertFalse(checks["security_scan"])
self.assertFalse(marker.exists())
def test_builtins_open_bypass_is_confined_to_container(self):
marker = Path(tempfile.gettempdir()) / f"agent-sandbox-{uuid.uuid4().hex}"
source = (
f'__builtins__["open"]({str(marker)!r}, "w").write("sandboxed")\n'
+ self.candidate["source"]
)
try:
checks = validate_candidate(source, self.trajectories, self.stable)
# This intentionally demonstrates why the AST scan is not the boundary.
self.assertTrue(checks["security_scan"])
self.assertTrue(checks["sandbox_execution"])
self.assertTrue(all(checks.values()))
self.assertFalse(marker.exists())
finally:
marker.unlink(missing_ok=True)
def test_nonterminating_candidate_fails_closed(self):
checks = validate_candidate("while True:\n pass\n", self.trajectories)
self.assertTrue(checks["static_compile"])
self.assertTrue(checks["security_scan"])
self.assertFalse(checks["sandbox_execution"])
self.assertFalse(all(checks.values()))
def test_candidate_has_no_network_access(self):
network_probe = (
'_socket = __builtins__["__import__"]("socket").socket()\n'
'_network_available = _socket.connect_ex(("1.1.1.1", 53)) == 0\n'
"_socket.close()\n"
)
source = (network_probe + self.candidate["source"]).replace(
" if not retryable or error_code in NON_RETRYABLE_CODES:",
" if _network_available:\n"
' raise RuntimeError("sandbox unexpectedly has network access")\n'
" if not retryable or error_code in NON_RETRYABLE_CODES:",
1,
)
checks = validate_candidate(source, self.trajectories, self.stable)
self.assertTrue(checks["security_scan"])
self.assertTrue(checks["sandbox_execution"])
self.assertTrue(all(checks.values()))
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,25 @@
import hashlib
import json
from pathlib import Path
ROOT = Path(__file__).parent
def test_canonical_real_coding_agent_evidence_closes_all_gates():
evidence = json.loads((ROOT / "validation" / "latest.json").read_text(encoding="utf-8"))
expected_sha = (ROOT / "validation" / "latest.sha256").read_text(encoding="utf-8").split()[0]
assert expected_sha == hashlib.sha256((ROOT / "validation" / "latest.json").read_bytes()).hexdigest()
assert evidence["execution_mode"] == "real_api_coding_agent_plus_model_external_release_harness"
assert evidence["accepted"] is True
assert all(evidence["gates"].values())
assert evidence["manifests"]["real_llm"]["decision"] == "release_to_canary"
assert evidence["manifests"]["deterministic"]["decision"] == "release_to_canary"
assert evidence["manifests"]["rejected_control"]["decision"] == "reject_candidate"
assert evidence["behavior_metrics"]["stable_buggy_baseline"]["mean_nonretryable_calls"] == 3.5
assert evidence["behavior_metrics"]["real_llm"]["mean_nonretryable_calls"] == 1.0
assert evidence["raw_api_receipts"][0]["response"]["id"]
stable = (ROOT / "stable" / "retry_policy.py").read_bytes()
assert evidence["input_artifacts"]["stable_sha256"] == hashlib.sha256(stable).hexdigest()
assert evidence["cost"]["total_tokens"] > 0
assert evidence["cost"]["provider_reported_cost_usd"] is None
@@ -0,0 +1,678 @@
{
"experiment": "9-6",
"executed_at": "2026-08-02T04:39:54.499339+00:00",
"execution_mode": "real_api_coding_agent_plus_model_external_release_harness",
"provider": "openrouter",
"model": "openai/gpt-5.6-sol",
"seed": 8501,
"input_artifacts": {
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"trajectory_sha256": "1e4664c40e99a5fcba2e9462226d7c32b611c573be9f9ba479ed2d26f844b0c2",
"validator_sha256_before_generation": "8c354d347b9d5423568205ebe7a5905dd580955756238674d648b9e00e2f6bd5",
"validator_sha256_after_generation": "8c354d347b9d5423568205ebe7a5905dd580955756238674d648b9e00e2f6bd5",
"trusted_surface_sha256_before": {
"evolution.py": "8c354d347b9d5423568205ebe7a5905dd580955756238674d648b9e00e2f6bd5",
"candidate_sandbox.py": "0fdd0576479c86482d8944050c2dc8a4d92c9eb696abaff4982bf1ad8b072fb8",
"sandbox_runner.py": "bc971dfa909758152ccad386096841dd30a68f4621be6c8d9650a51d2e8c46eb",
"Dockerfile.sandbox": "8c71105f404373a92cdd5923a894b05e1358ab42873d08d3d349a9fd3d2a1ade"
},
"trusted_surface_sha256_after": {
"evolution.py": "8c354d347b9d5423568205ebe7a5905dd580955756238674d648b9e00e2f6bd5",
"candidate_sandbox.py": "0fdd0576479c86482d8944050c2dc8a4d92c9eb696abaff4982bf1ad8b072fb8",
"sandbox_runner.py": "bc971dfa909758152ccad386096841dd30a68f4621be6c8d9650a51d2e8c46eb",
"Dockerfile.sandbox": "8c71105f404373a92cdd5923a894b05e1358ab42873d08d3d349a9fd3d2a1ade"
}
},
"candidate_sandbox": {
"image": "ai-agent-book/self-modifying-agent-sandbox:2548a1de2baf",
"network": "none",
"root_filesystem": "read_only",
"user": "65534:65534",
"memory": "64m",
"cpus": 0.5,
"wall_clock_timeout_seconds": 8.0
},
"diagnosis": {
"change_required": true,
"target": "stable/retry_policy.py",
"target_component": "retry_and_circuit_breaker_control",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"patterns": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"reason": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"change_contract": {
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
]
}
},
"rejected_history_given_to_coding_agent": [
{
"candidate_sha256": "824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2",
"failed_checks": [
"temporary_recovery",
"old_task_regression",
"canary_ready"
],
"rejection_reason": "failed gates: temporary_recovery, old_task_regression, canary_ready",
"failure": "disabled temporary-timeout retries"
}
],
"behavior_metrics": {
"stable_buggy_baseline": {
"mean_nonretryable_calls": 3.5,
"temporary_error_recovery_rate": 1.0,
"old_task_regressions": 0
},
"deterministic": {
"mean_nonretryable_calls": 1.0,
"temporary_error_recovery_rate": 1.0,
"old_task_regressions": 0
},
"real_llm": {
"mean_nonretryable_calls": 1.0,
"temporary_error_recovery_rate": 1.0,
"old_task_regressions": 0
},
"rejected_control": {
"mean_nonretryable_calls": 1.0,
"temporary_error_recovery_rate": 0.0,
"old_task_regressions": 1
}
},
"comparison": {
"deterministic": {
"decision": "release_to_canary",
"checks": {
"static_compile": true,
"security_scan": true,
"sandbox_execution": true,
"public_api_compatible": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": true,
"old_task_regression": true,
"canary_ready": true,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"patch_size": {
"added_lines": 7,
"deleted_lines": 3,
"changed_lines": 10
},
"behavior": {
"mean_nonretryable_calls": 1.0,
"temporary_error_recovery_rate": 1.0,
"old_task_regressions": 0
}
},
"real_llm": {
"decision": "release_to_canary",
"checks": {
"static_compile": true,
"security_scan": true,
"sandbox_execution": true,
"public_api_compatible": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": true,
"old_task_regression": true,
"canary_ready": true,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"patch_size": {
"added_lines": 7,
"deleted_lines": 3,
"changed_lines": 10
},
"behavior": {
"mean_nonretryable_calls": 1.0,
"temporary_error_recovery_rate": 1.0,
"old_task_regressions": 0
}
},
"rejected_control": {
"decision": "reject_candidate",
"checks": {
"static_compile": true,
"security_scan": true,
"sandbox_execution": true,
"public_api_compatible": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": false,
"old_task_regression": false,
"canary_ready": false,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"patch_size": {
"added_lines": 6,
"deleted_lines": 4,
"changed_lines": 10
},
"behavior": {
"mean_nonretryable_calls": 1.0,
"temporary_error_recovery_rate": 0.0,
"old_task_regressions": 1
}
}
},
"manifests": {
"deterministic": {
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,20 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.1.0-candidate\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n-NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n+NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\", \"PAYMENT_DECLINED\"}\n \n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"before": "up to 4",
"after": 1
},
"temporary_timeout_recovery_rate": {
"before": 1.0,
"after": 1.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "b0fb4d1caf96",
"candidate_sha256": "b0fb4d1caf96c7aca16fc53d1dcf518345ea1a5b0aef9b60168f24534acf552c",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,20 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.1.0-candidate\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n-NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n+NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\", \"PAYMENT_DECLINED\"}\n \n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 7,
"deleted_lines": 3,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"security_scan": true,
"sandbox_execution": true,
"public_api_compatible": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": true,
"old_task_regression": true,
"canary_ready": true,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [],
"canary_gate": {
"eligible": true,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "deterministic",
"model": null,
"api_calls": 0
},
"decision": "release_to_canary",
"rejection_reason": null
},
"real_llm": {
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,6 +1,6 @@\n-\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n+\"\"\"Candidate version 1.0.1-rc.1 with permanent-failure handling.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rc.1\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n@@ -8,9 +8,13 @@\n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent failures or after repeated temporary failures.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"before": "up to 4",
"after": 1
},
"temporary_timeout_recovery_rate": {
"before": 1.0,
"after": 1.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "d6e79810003e",
"candidate_sha256": "d6e79810003e7d5f3e8d43ace0688e38033b08a4752bb0dfb9260d9bbe976b8f",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,6 +1,6 @@\n-\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n+\"\"\"Candidate version 1.0.1-rc.1 with permanent-failure handling.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rc.1\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n@@ -8,9 +8,13 @@\n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent failures or after repeated temporary failures.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 7,
"deleted_lines": 3,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"security_scan": true,
"sandbox_execution": true,
"public_api_compatible": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": true,
"old_task_regression": true,
"canary_ready": true,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [],
"canary_gate": {
"eligible": true,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "real_llm_coding_agent",
"model": "openai/gpt-5.6-sol",
"provider": "openrouter",
"seed": 8501,
"api_calls": 1,
"receipt": {
"backend": {
"provider": "openrouter",
"endpoint": "https://openrouter.ai/api/v1/chat/completions",
"credential_env": "OPENROUTER_API_KEY",
"model": "openai/gpt-5.6-sol",
"credential_value_recorded": false
},
"request": {
"model": "openai/gpt-5.6-sol",
"messages": [
{
"role": "user",
"content": "You are the Coding Agent in a controlled self-modification pipeline.\n\nModify only the supplied retry-policy module. Preserve both public function\nsignatures and retry behavior for temporary failures. Permanent failures\n(retryable=false or a listed permanent code) must not be retried and must open\nthe circuit on the first occurrence. Update VERSION to a candidate version.\nDo not import modules, access files, or alter validation/release logic.\n\nBefore the source, predict the intended impact. Return JSON only:\n{\"impact_prediction\": {\"non_retryable_calls\": {\"before\": \"up to 4\", \"after\": 1},\n\"temporary_timeout_recovery_rate\": {\"before\": 1.0, \"after\": 1.0}},\n\"source\": \"the complete Python module\"}\n\nFailure diagnosis:\n{\n \"change_required\": true,\n \"target\": \"stable/retry_policy.py\",\n \"target_component\": \"retry_and_circuit_breaker_control\",\n \"source_case_ids\": [\n \"run-payment-001\",\n \"run-payment-002\"\n ],\n \"source_trajectories\": [\n {\n \"id\": \"run-payment-001\",\n \"trajectory_sha256\": \"4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008\",\n \"evidence\": \"The same declined payment was submitted four times.\"\n },\n {\n \"id\": \"run-payment-002\",\n \"trajectory_sha256\": \"6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59\",\n \"evidence\": \"A second task repeated the identical non-retryable call three times.\"\n }\n ],\n \"patterns\": [\n {\n \"cluster_id\": \"charge_card:PAYMENT_DECLINED\",\n \"tool\": \"charge_card\",\n \"error_code\": \"PAYMENT_DECLINED\",\n \"source_case_ids\": [\n \"run-payment-001\",\n \"run-payment-002\"\n ],\n \"cross_trajectory_support\": 2,\n \"total_redundant_calls\": 5\n }\n ],\n \"reason\": \"The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.\",\n \"change_contract\": {\n \"expected_fix\": [\n \"non-retryable tool-call attempts fall to one\",\n \"the circuit opens on the first permanent failure\"\n ],\n \"potential_regressions\": [\n \"temporary timeouts stop retrying\",\n \"the five-failure circuit threshold changes for retryable errors\",\n \"public function signatures change\"\n ]\n }\n}\n\nPreviously rejected candidates (do not repeat their failure):\n[\n {\n \"candidate_sha256\": \"824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2\",\n \"failed_checks\": [\n \"temporary_recovery\",\n \"old_task_regression\",\n \"canary_ready\"\n ],\n \"rejection_reason\": \"failed gates: temporary_recovery, old_task_regression, canary_ready\",\n \"failure\": \"disabled temporary-timeout retries\"\n }\n]\n\nStable module:\n\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n\nVERSION = \"1.0.0\"\nMAX_RETRIES = 3\nCIRCUIT_BREAKER_THRESHOLD = 5\nNON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n\n\ndef should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n return attempt < MAX_RETRIES\n\n\ndef should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n \"\"\"Open after repeated failures.\"\"\"\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n\n"
}
],
"temperature": 0,
"seed": 8501,
"max_tokens": 1400,
"response_format": {
"type": "json_object"
}
},
"response": {
"id": "gen-1785645586-58eflec0vxlXmqNTlbkd",
"choices": [
{
"finish_reason": "stop",
"index": 0,
"message": {
"content": "{\"impact_prediction\":{\"non_retryable_calls\":{\"before\":\"up to 4\",\"after\":1},\"temporary_timeout_recovery_rate\":{\"before\":1.0,\"after\":1.0}},\"source\":\"\\\"\\\"\\\"Candidate version 1.0.1-rc.1 with permanent-failure handling.\\\"\\\"\\\"\\n\\nVERSION = \\\"1.0.1-rc.1\\\"\\nMAX_RETRIES = 3\\nCIRCUIT_BREAKER_THRESHOLD = 5\\nNON_RETRYABLE_CODES = {\\\"AUTH_DENIED\\\", \\\"INVALID_ARGUMENT\\\"}\\n\\n\\ndef should_retry(error_code, retryable, attempt):\\n \\\"\\\"\\\"Return whether another tool call should be attempted.\\\"\\\"\\\"\\n if not retryable or error_code in NON_RETRYABLE_CODES:\\n return False\\n return attempt < MAX_RETRIES\\n\\n\\ndef should_open_circuit(consecutive_failures, *, error_code=\\\"\\\", retryable=True):\\n \\\"\\\"\\\"Open immediately for permanent failures or after repeated temporary failures.\\\"\\\"\\\"\\n if not retryable or error_code in NON_RETRYABLE_CODES:\\n return consecutive_failures >= 1\\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\\n\"}",
"role": "assistant",
"reasoning_details": [
{
"type": "reasoning.encrypted",
"data": "gAAAAABqbsoVfzLT_630yuZzHKyd8nnXw_G6aqojKdjAmzVDbLd4Xn-Q3mIKe2go0qV-MzGTWKLAI49dpBvB7Rh_5pD2V7g9Lo20b0upq1QQnrlwSgTTkNNIU42VP09tK7BlainxGC3VjVQzoiDnzW1ycnev5uExeR6RMeYeK4OycCtSm432sFdjGobCDAkD63hztrlRR9LbpO5F_N-r9FE6XK9__6rPfpVxwssCnzw6UrJSIrAnY78EnxrZ5Brr_x7TS1DRWkKycysVRmdyH7lialKB5-VQqHVYnzGIDRmInx2z8Eb33a0oxFKoZ60wm4Dt51u3B4ZigQuSnm8qaL0C3e6Sx1CcMjqgkvAveoDqvPiRe2Jn99gGD1Zb2a4QuzpWFJoPBw0wP-5Ftr_9oeiXXIrC-iV6WcqW60nWo3T8QoE8AyL5xPhgkYOXTsWxB6eE8qhUcdfUkPI6Jb5WzJJV6aBYPE8VtUOt0a-kpKSs7VoHqBXZLKb6XBUJuRA1kNfD9-878znM_o0HLa-zeXAh0o5sRU3tm8JUFM2wTPC4vIW9j6MBneAnSAgPP5-ecZ8zNcfJwX8tGq6pv8m7t8fNw6hBFhweTz0H6nfP40ew75rl20hlSwzZpvhxNrqQ7sDEgHSS_pSeMEyy_3Q_3gJjRII-63s5oFCV6KA4J-3y6rTq8B8nBWCrmC6t6Wr154B8duIsKEj5XkwqJwJqVJ0ve0Zn1ajrnoT5U9koJ4gr8QQHjGGzeB8iWKYlXDj7U3DRnfFpDi2W9ITie15t9KGl4vgwLqGpC4W3Tw0ler9B1iI8RI4guTstB-P3kk1AL3Wy23w5NOZpvGtAFHmq0tTT2p7pevH_1vreX8VMrXpnR4TtRXS_ozgbJhg7SzikZYlL43F_6mpmJxxg5FvTaj_J2QEV-sXNu0HkYIk7SarA5ULcDflz05fperzFaKpc6DdXtar9Mufjhn24mX1a8799OAZbgS9h3vaFa0z-7cBUTfplDVVydBNxteka07DevlG9fxTQCi9KjhOhqMH3oadsDbiufIp2YeGz3bocIBTIhPVVUoL9ywJW7kwVIfDFUV_hONXVKfhjWjH-Q0O3BCPn76nmUnyDlZrrggLqm5YDLvulyRZzspRVryr4IcbOSC4tK3n8s4-v6zNsnPtszq7sSNyxoTqryCQlrifvFcYOZQw4Cc0CHiKwojD7vQsjy1q4m3If6IfRXDbK4kOdkajkOSj-ir9kNRu1r04fb6eMbIRZYmbkfoUkoT17fJT5ruSinGmvKs8B4MS8896hpzIXLaxmd_4rdg0j4byhJjvQHiIjVDVdc3icZT6RAuwGuv2VlkoH6gD4UsJTQY7TTzDCs96-add1yczyk9Az2B74qXLQgstAy3ubGDhM-QjmEMhU6fULqriEbJZSk-u-HYPVJ3CtJSHXFnviF3ur6FRQr1bvk4s0lrksXPOPmtR3Gg26UiPQET_JwsvafY_ttLJ2wbudPzhGSijztaphFjmnFWkH53xLNRMACNPi_fXuTXwcoSwIc0M_pa2MVooxFAlDsiNYhlyKfgYY9aB77RAmqfHx1movlyjgWJlQm1vvcngw3VxYHoG_kGu4fFQn5Kd2hC5rbrd4a4v3lPCzQkAKGTDqqsjYyH_H0lg4RkVYo-n_iGNWRlUI5blONowfxTXn4WS5oP7QGajw0WFbPI6FOcv3ISK8CJYCC_fjrtJoOia2OC1rVRzAqr1EuxWH6H_W9gQl0dae0CZUC_XTC8kZGvcKEC7hBz-u3OdRi4iycAYOPxlzMffE",
"format": "openai-responses-v1",
"id": "rs_09bdf9a0a95f7f05016a6eca1367a8819ebed6d613bbe9886e",
"index": 0
}
]
},
"native_finish_reason": "completed"
}
],
"created": 1785645586,
"model": "openai/gpt-5.6-sol",
"object": "chat.completion",
"service_tier": "default",
"usage": {
"completion_tokens": 392,
"prompt_tokens": 839,
"total_tokens": 1231,
"completion_tokens_details": {
"audio_tokens": 0,
"reasoning_tokens": 128,
"image_tokens": 0
},
"prompt_tokens_details": {
"audio_tokens": 0,
"cached_tokens": 0,
"cache_write_tokens": 0,
"video_tokens": 0
},
"cost": 0.015955,
"is_byok": false,
"cost_details": {
"upstream_inference_cost": 0.015955,
"upstream_inference_prompt_cost": 0.004195,
"upstream_inference_completions_cost": 0.01176
}
},
"provider": "OpenAI"
},
"request_sha256": "80938ad7618b7a10cbf6a441221678a0e08a3acd88e03a9277b5b48c767b37b9",
"response_sha256": "0547761669dd89448a523da688652d900c055c104d208c20681a0055e19feeb3",
"elapsed_seconds": 4.693797,
"usage": {
"prompt_tokens": 839,
"completion_tokens": 392,
"total_tokens": 1231,
"provider_reported_cost_usd": 0.015955,
"cost_qualification": "provider-native usage.cost"
}
}
},
"decision": "release_to_canary",
"rejection_reason": null
},
"rejected_control": {
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,18 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rejected\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n \n \n def should_retry(error_code, retryable, attempt):\n- \"\"\"Return whether another tool call should be attempted.\"\"\"\n- return attempt < MAX_RETRIES\n+ \"\"\"Incorrect over-broad fix retained as a rejected candidate.\"\"\"\n+ return False\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"after": 1
},
"temporary_timeout_recovery_rate": {
"after": 0.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "824bbfb244a7",
"candidate_sha256": "824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,18 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rejected\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n \n \n def should_retry(error_code, retryable, attempt):\n- \"\"\"Return whether another tool call should be attempted.\"\"\"\n- return attempt < MAX_RETRIES\n+ \"\"\"Incorrect over-broad fix retained as a rejected candidate.\"\"\"\n+ return False\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 6,
"deleted_lines": 4,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"security_scan": true,
"sandbox_execution": true,
"public_api_compatible": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": false,
"old_task_regression": false,
"canary_ready": false,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [
"temporary_recovery",
"old_task_regression",
"canary_ready"
],
"canary_gate": {
"eligible": false,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "negative_control",
"api_calls": 0
},
"decision": "reject_candidate",
"rejection_reason": "failed gates: temporary_recovery, old_task_regression, canary_ready"
}
},
"raw_api_receipts": [
{
"backend": {
"provider": "openrouter",
"endpoint": "https://openrouter.ai/api/v1/chat/completions",
"credential_env": "OPENROUTER_API_KEY",
"model": "openai/gpt-5.6-sol",
"credential_value_recorded": false
},
"request": {
"model": "openai/gpt-5.6-sol",
"messages": [
{
"role": "user",
"content": "You are the Coding Agent in a controlled self-modification pipeline.\n\nModify only the supplied retry-policy module. Preserve both public function\nsignatures and retry behavior for temporary failures. Permanent failures\n(retryable=false or a listed permanent code) must not be retried and must open\nthe circuit on the first occurrence. Update VERSION to a candidate version.\nDo not import modules, access files, or alter validation/release logic.\n\nBefore the source, predict the intended impact. Return JSON only:\n{\"impact_prediction\": {\"non_retryable_calls\": {\"before\": \"up to 4\", \"after\": 1},\n\"temporary_timeout_recovery_rate\": {\"before\": 1.0, \"after\": 1.0}},\n\"source\": \"the complete Python module\"}\n\nFailure diagnosis:\n{\n \"change_required\": true,\n \"target\": \"stable/retry_policy.py\",\n \"target_component\": \"retry_and_circuit_breaker_control\",\n \"source_case_ids\": [\n \"run-payment-001\",\n \"run-payment-002\"\n ],\n \"source_trajectories\": [\n {\n \"id\": \"run-payment-001\",\n \"trajectory_sha256\": \"4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008\",\n \"evidence\": \"The same declined payment was submitted four times.\"\n },\n {\n \"id\": \"run-payment-002\",\n \"trajectory_sha256\": \"6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59\",\n \"evidence\": \"A second task repeated the identical non-retryable call three times.\"\n }\n ],\n \"patterns\": [\n {\n \"cluster_id\": \"charge_card:PAYMENT_DECLINED\",\n \"tool\": \"charge_card\",\n \"error_code\": \"PAYMENT_DECLINED\",\n \"source_case_ids\": [\n \"run-payment-001\",\n \"run-payment-002\"\n ],\n \"cross_trajectory_support\": 2,\n \"total_redundant_calls\": 5\n }\n ],\n \"reason\": \"The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.\",\n \"change_contract\": {\n \"expected_fix\": [\n \"non-retryable tool-call attempts fall to one\",\n \"the circuit opens on the first permanent failure\"\n ],\n \"potential_regressions\": [\n \"temporary timeouts stop retrying\",\n \"the five-failure circuit threshold changes for retryable errors\",\n \"public function signatures change\"\n ]\n }\n}\n\nPreviously rejected candidates (do not repeat their failure):\n[\n {\n \"candidate_sha256\": \"824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2\",\n \"failed_checks\": [\n \"temporary_recovery\",\n \"old_task_regression\",\n \"canary_ready\"\n ],\n \"rejection_reason\": \"failed gates: temporary_recovery, old_task_regression, canary_ready\",\n \"failure\": \"disabled temporary-timeout retries\"\n }\n]\n\nStable module:\n\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n\nVERSION = \"1.0.0\"\nMAX_RETRIES = 3\nCIRCUIT_BREAKER_THRESHOLD = 5\nNON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n\n\ndef should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n return attempt < MAX_RETRIES\n\n\ndef should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n \"\"\"Open after repeated failures.\"\"\"\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n\n"
}
],
"temperature": 0,
"seed": 8501,
"max_tokens": 1400,
"response_format": {
"type": "json_object"
}
},
"response": {
"id": "gen-1785645586-58eflec0vxlXmqNTlbkd",
"choices": [
{
"finish_reason": "stop",
"index": 0,
"message": {
"content": "{\"impact_prediction\":{\"non_retryable_calls\":{\"before\":\"up to 4\",\"after\":1},\"temporary_timeout_recovery_rate\":{\"before\":1.0,\"after\":1.0}},\"source\":\"\\\"\\\"\\\"Candidate version 1.0.1-rc.1 with permanent-failure handling.\\\"\\\"\\\"\\n\\nVERSION = \\\"1.0.1-rc.1\\\"\\nMAX_RETRIES = 3\\nCIRCUIT_BREAKER_THRESHOLD = 5\\nNON_RETRYABLE_CODES = {\\\"AUTH_DENIED\\\", \\\"INVALID_ARGUMENT\\\"}\\n\\n\\ndef should_retry(error_code, retryable, attempt):\\n \\\"\\\"\\\"Return whether another tool call should be attempted.\\\"\\\"\\\"\\n if not retryable or error_code in NON_RETRYABLE_CODES:\\n return False\\n return attempt < MAX_RETRIES\\n\\n\\ndef should_open_circuit(consecutive_failures, *, error_code=\\\"\\\", retryable=True):\\n \\\"\\\"\\\"Open immediately for permanent failures or after repeated temporary failures.\\\"\\\"\\\"\\n if not retryable or error_code in NON_RETRYABLE_CODES:\\n return consecutive_failures >= 1\\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\\n\"}",
"role": "assistant",
"reasoning_details": [
{
"type": "reasoning.encrypted",
"data": "gAAAAABqbsoVfzLT_630yuZzHKyd8nnXw_G6aqojKdjAmzVDbLd4Xn-Q3mIKe2go0qV-MzGTWKLAI49dpBvB7Rh_5pD2V7g9Lo20b0upq1QQnrlwSgTTkNNIU42VP09tK7BlainxGC3VjVQzoiDnzW1ycnev5uExeR6RMeYeK4OycCtSm432sFdjGobCDAkD63hztrlRR9LbpO5F_N-r9FE6XK9__6rPfpVxwssCnzw6UrJSIrAnY78EnxrZ5Brr_x7TS1DRWkKycysVRmdyH7lialKB5-VQqHVYnzGIDRmInx2z8Eb33a0oxFKoZ60wm4Dt51u3B4ZigQuSnm8qaL0C3e6Sx1CcMjqgkvAveoDqvPiRe2Jn99gGD1Zb2a4QuzpWFJoPBw0wP-5Ftr_9oeiXXIrC-iV6WcqW60nWo3T8QoE8AyL5xPhgkYOXTsWxB6eE8qhUcdfUkPI6Jb5WzJJV6aBYPE8VtUOt0a-kpKSs7VoHqBXZLKb6XBUJuRA1kNfD9-878znM_o0HLa-zeXAh0o5sRU3tm8JUFM2wTPC4vIW9j6MBneAnSAgPP5-ecZ8zNcfJwX8tGq6pv8m7t8fNw6hBFhweTz0H6nfP40ew75rl20hlSwzZpvhxNrqQ7sDEgHSS_pSeMEyy_3Q_3gJjRII-63s5oFCV6KA4J-3y6rTq8B8nBWCrmC6t6Wr154B8duIsKEj5XkwqJwJqVJ0ve0Zn1ajrnoT5U9koJ4gr8QQHjGGzeB8iWKYlXDj7U3DRnfFpDi2W9ITie15t9KGl4vgwLqGpC4W3Tw0ler9B1iI8RI4guTstB-P3kk1AL3Wy23w5NOZpvGtAFHmq0tTT2p7pevH_1vreX8VMrXpnR4TtRXS_ozgbJhg7SzikZYlL43F_6mpmJxxg5FvTaj_J2QEV-sXNu0HkYIk7SarA5ULcDflz05fperzFaKpc6DdXtar9Mufjhn24mX1a8799OAZbgS9h3vaFa0z-7cBUTfplDVVydBNxteka07DevlG9fxTQCi9KjhOhqMH3oadsDbiufIp2YeGz3bocIBTIhPVVUoL9ywJW7kwVIfDFUV_hONXVKfhjWjH-Q0O3BCPn76nmUnyDlZrrggLqm5YDLvulyRZzspRVryr4IcbOSC4tK3n8s4-v6zNsnPtszq7sSNyxoTqryCQlrifvFcYOZQw4Cc0CHiKwojD7vQsjy1q4m3If6IfRXDbK4kOdkajkOSj-ir9kNRu1r04fb6eMbIRZYmbkfoUkoT17fJT5ruSinGmvKs8B4MS8896hpzIXLaxmd_4rdg0j4byhJjvQHiIjVDVdc3icZT6RAuwGuv2VlkoH6gD4UsJTQY7TTzDCs96-add1yczyk9Az2B74qXLQgstAy3ubGDhM-QjmEMhU6fULqriEbJZSk-u-HYPVJ3CtJSHXFnviF3ur6FRQr1bvk4s0lrksXPOPmtR3Gg26UiPQET_JwsvafY_ttLJ2wbudPzhGSijztaphFjmnFWkH53xLNRMACNPi_fXuTXwcoSwIc0M_pa2MVooxFAlDsiNYhlyKfgYY9aB77RAmqfHx1movlyjgWJlQm1vvcngw3VxYHoG_kGu4fFQn5Kd2hC5rbrd4a4v3lPCzQkAKGTDqqsjYyH_H0lg4RkVYo-n_iGNWRlUI5blONowfxTXn4WS5oP7QGajw0WFbPI6FOcv3ISK8CJYCC_fjrtJoOia2OC1rVRzAqr1EuxWH6H_W9gQl0dae0CZUC_XTC8kZGvcKEC7hBz-u3OdRi4iycAYOPxlzMffE",
"format": "openai-responses-v1",
"id": "rs_09bdf9a0a95f7f05016a6eca1367a8819ebed6d613bbe9886e",
"index": 0
}
]
},
"native_finish_reason": "completed"
}
],
"created": 1785645586,
"model": "openai/gpt-5.6-sol",
"object": "chat.completion",
"service_tier": "default",
"usage": {
"completion_tokens": 392,
"prompt_tokens": 839,
"total_tokens": 1231,
"completion_tokens_details": {
"audio_tokens": 0,
"reasoning_tokens": 128,
"image_tokens": 0
},
"prompt_tokens_details": {
"audio_tokens": 0,
"cached_tokens": 0,
"cache_write_tokens": 0,
"video_tokens": 0
},
"cost": 0.015955,
"is_byok": false,
"cost_details": {
"upstream_inference_cost": 0.015955,
"upstream_inference_prompt_cost": 0.004195,
"upstream_inference_completions_cost": 0.01176
}
},
"provider": "OpenAI"
},
"request_sha256": "80938ad7618b7a10cbf6a441221678a0e08a3acd88e03a9277b5b48c767b37b9",
"response_sha256": "0547761669dd89448a523da688652d900c055c104d208c20681a0055e19feeb3",
"elapsed_seconds": 4.693797,
"usage": {
"prompt_tokens": 839,
"completion_tokens": 392,
"total_tokens": 1231,
"provider_reported_cost_usd": 0.015955,
"cost_qualification": "provider-native usage.cost"
}
}
],
"cost": {
"prompt_tokens": 839,
"completion_tokens": 392,
"total_tokens": 1231,
"provider_reported_cost_usd": 0.015955,
"cost_qualification": "provider-native usage.cost"
},
"candidate_acceptance_rate": 0.6666666666666666,
"gates": {
"cross_trajectory_support_met": true,
"root_cause_targets_control_code": true,
"real_coding_model_called": true,
"impact_prediction_precedes_validation": true,
"all_candidates_isolated": true,
"trusted_surfaces_unchanged": true,
"same_release_gate_for_both_generators": true,
"deterministic_candidate_release_to_canary": true,
"real_llm_candidate_release_to_canary": true,
"known_bad_candidate_rejected_and_retained": true,
"failure_replay_reduces_calls": true,
"temporary_recovery_preserved": true,
"old_task_regression_zero": true,
"canary_only_not_production": true,
"rollback_hash_pinned_to_stable": true,
"release_manifest_fields_complete": true
},
"accepted": true
}
@@ -0,0 +1 @@
761ed7dc4a5ad5b5d97c05a83f6b66c6c2003fc6ee20cc53a699a54c0c8eb020 latest.json
@@ -0,0 +1,5 @@
{
"candidates/deterministic/retry_policy.py": "b0fb4d1caf96c7aca16fc53d1dcf518345ea1a5b0aef9b60168f24534acf552c",
"candidates/real_llm/retry_policy.py": "801604c8b4ebe0611dc0d78c4b0131736341bcac990df6ad817607b8486d402b",
"candidates/rejected_control/retry_policy.py": "824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2"
}
@@ -0,0 +1,20 @@
"""Stable version 1.0.0. It intentionally contains the reproduced bug."""
VERSION = "1.1.0-candidate"
MAX_RETRIES = 3
CIRCUIT_BREAKER_THRESHOLD = 5
NON_RETRYABLE_CODES = {"AUTH_DENIED", "INVALID_ARGUMENT", "PAYMENT_DECLINED"}
def should_retry(error_code, retryable, attempt):
"""Return whether another tool call should be attempted."""
if not retryable or error_code in NON_RETRYABLE_CODES:
return False
return attempt < MAX_RETRIES
def should_open_circuit(consecutive_failures, *, error_code="", retryable=True):
"""Open immediately for permanent errors; otherwise use the threshold."""
if not retryable or error_code in NON_RETRYABLE_CODES:
return consecutive_failures >= 1
return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD
@@ -0,0 +1,18 @@
VERSION = "1.0.1"
MAX_RETRIES = 3
CIRCUIT_BREAKER_THRESHOLD = 5
NON_RETRYABLE_CODES = {"AUTH_DENIED", "INVALID_ARGUMENT", "PAYMENT_DECLINED"}
def should_retry(error_code, retryable, attempt):
"""Return whether another tool call should be attempted."""
if not retryable or error_code in NON_RETRYABLE_CODES:
return False
return attempt < MAX_RETRIES
def should_open_circuit(consecutive_failures, *, error_code="", retryable=True):
"""Open after repeated failures."""
if not retryable or error_code in NON_RETRYABLE_CODES:
return consecutive_failures >= 1
return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD
@@ -0,0 +1,18 @@
"""Stable version 1.0.0. It intentionally contains the reproduced bug."""
VERSION = "1.0.1-rejected"
MAX_RETRIES = 3
CIRCUIT_BREAKER_THRESHOLD = 5
NON_RETRYABLE_CODES = {"AUTH_DENIED", "INVALID_ARGUMENT"}
def should_retry(error_code, retryable, attempt):
"""Incorrect over-broad fix retained as a rejected candidate."""
return False
def should_open_circuit(consecutive_failures, *, error_code="", retryable=True):
"""Open immediately for permanent errors; otherwise use the threshold."""
if not retryable or error_code in NON_RETRYABLE_CODES:
return consecutive_failures >= 1
return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD
@@ -0,0 +1,92 @@
{
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,20 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.1.0-candidate\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n-NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n+NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\", \"PAYMENT_DECLINED\"}\n \n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"before": "up to 4",
"after": 1
},
"temporary_timeout_recovery_rate": {
"before": 1.0,
"after": 1.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "b0fb4d1caf96",
"candidate_sha256": "b0fb4d1caf96c7aca16fc53d1dcf518345ea1a5b0aef9b60168f24534acf552c",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,20 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.1.0-candidate\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n-NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n+NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\", \"PAYMENT_DECLINED\"}\n \n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 7,
"deleted_lines": 3,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"public_api_compatible": true,
"security_scan": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": true,
"old_task_regression": true,
"canary_ready": true,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [],
"canary_gate": {
"eligible": true,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "deterministic",
"model": null,
"api_calls": 0
},
"decision": "release_to_canary",
"rejection_reason": null
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,93 @@
{
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,18 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rejected\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n \n \n def should_retry(error_code, retryable, attempt):\n- \"\"\"Return whether another tool call should be attempted.\"\"\"\n- return attempt < MAX_RETRIES\n+ \"\"\"Incorrect over-broad fix retained as a rejected candidate.\"\"\"\n+ return False\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"after": 1
},
"temporary_timeout_recovery_rate": {
"after": 0.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "824bbfb244a7",
"candidate_sha256": "824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,18 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rejected\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n \n \n def should_retry(error_code, retryable, attempt):\n- \"\"\"Return whether another tool call should be attempted.\"\"\"\n- return attempt < MAX_RETRIES\n+ \"\"\"Incorrect over-broad fix retained as a rejected candidate.\"\"\"\n+ return False\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 6,
"deleted_lines": 4,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"public_api_compatible": true,
"security_scan": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": false,
"old_task_regression": false,
"canary_ready": false,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [
"temporary_recovery",
"old_task_regression",
"canary_ready"
],
"canary_gate": {
"eligible": false,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "negative_control",
"api_calls": 0
},
"decision": "reject_candidate",
"rejection_reason": "failed gates: temporary_recovery, old_task_regression, canary_ready"
}
@@ -0,0 +1,5 @@
{
"candidates/deterministic/retry_policy.py": "b0fb4d1caf96c7aca16fc53d1dcf518345ea1a5b0aef9b60168f24534acf552c",
"candidates/real_llm/retry_policy.py": "801604c8b4ebe0611dc0d78c4b0131736341bcac990df6ad817607b8486d402b",
"candidates/rejected_control/retry_policy.py": "824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2"
}
@@ -0,0 +1,20 @@
"""Stable version 1.0.0. It intentionally contains the reproduced bug."""
VERSION = "1.1.0-candidate"
MAX_RETRIES = 3
CIRCUIT_BREAKER_THRESHOLD = 5
NON_RETRYABLE_CODES = {"AUTH_DENIED", "INVALID_ARGUMENT", "PAYMENT_DECLINED"}
def should_retry(error_code, retryable, attempt):
"""Return whether another tool call should be attempted."""
if not retryable or error_code in NON_RETRYABLE_CODES:
return False
return attempt < MAX_RETRIES
def should_open_circuit(consecutive_failures, *, error_code="", retryable=True):
"""Open immediately for permanent errors; otherwise use the threshold."""
if not retryable or error_code in NON_RETRYABLE_CODES:
return consecutive_failures >= 1
return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD
@@ -0,0 +1,18 @@
VERSION = "1.0.1"
MAX_RETRIES = 3
CIRCUIT_BREAKER_THRESHOLD = 5
NON_RETRYABLE_CODES = {"AUTH_DENIED", "INVALID_ARGUMENT", "PAYMENT_DECLINED"}
def should_retry(error_code, retryable, attempt):
"""Return whether another tool call should be attempted."""
if not retryable or error_code in NON_RETRYABLE_CODES:
return False
return attempt < MAX_RETRIES
def should_open_circuit(consecutive_failures, *, error_code="", retryable=True):
"""Open after repeated failures."""
if not retryable or error_code in NON_RETRYABLE_CODES:
return consecutive_failures >= 1
return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD
@@ -0,0 +1,18 @@
"""Stable version 1.0.0. It intentionally contains the reproduced bug."""
VERSION = "1.0.1-rejected"
MAX_RETRIES = 3
CIRCUIT_BREAKER_THRESHOLD = 5
NON_RETRYABLE_CODES = {"AUTH_DENIED", "INVALID_ARGUMENT"}
def should_retry(error_code, retryable, attempt):
"""Incorrect over-broad fix retained as a rejected candidate."""
return False
def should_open_circuit(consecutive_failures, *, error_code="", retryable=True):
"""Open immediately for permanent errors; otherwise use the threshold."""
if not retryable or error_code in NON_RETRYABLE_CODES:
return consecutive_failures >= 1
return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD
@@ -0,0 +1,92 @@
{
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,20 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.1.0-candidate\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n-NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n+NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\", \"PAYMENT_DECLINED\"}\n \n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"before": "up to 4",
"after": 1
},
"temporary_timeout_recovery_rate": {
"before": 1.0,
"after": 1.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "b0fb4d1caf96",
"candidate_sha256": "b0fb4d1caf96c7aca16fc53d1dcf518345ea1a5b0aef9b60168f24534acf552c",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,20 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.1.0-candidate\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n-NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n+NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\", \"PAYMENT_DECLINED\"}\n \n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 7,
"deleted_lines": 3,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"public_api_compatible": true,
"security_scan": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": true,
"old_task_regression": true,
"canary_ready": true,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [],
"canary_gate": {
"eligible": true,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "deterministic",
"model": null,
"api_calls": 0
},
"decision": "release_to_canary",
"rejection_reason": null
}
@@ -0,0 +1,607 @@
{
"experiment": "9-6",
"executed_at": "2026-07-29T17:11:18.156685+00:00",
"execution_mode": "real_api_coding_agent_plus_model_external_release_harness",
"provider": "ark",
"model": "doubao-seed-1-6-250615",
"seed": 8501,
"input_artifacts": {
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"trajectory_sha256": "1e4664c40e99a5fcba2e9462226d7c32b611c573be9f9ba479ed2d26f844b0c2",
"validator_sha256_before_generation": "d2e6835ae7add5f85e7a9f6784b503798d008d19fa25eca5532c190685d13548",
"validator_sha256_after_generation": "d2e6835ae7add5f85e7a9f6784b503798d008d19fa25eca5532c190685d13548"
},
"diagnosis": {
"change_required": true,
"target": "stable/retry_policy.py",
"target_component": "retry_and_circuit_breaker_control",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"patterns": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"reason": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"change_contract": {
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
]
}
},
"rejected_history_given_to_coding_agent": [
{
"candidate_sha256": "824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2",
"failed_checks": [
"temporary_recovery",
"old_task_regression",
"canary_ready"
],
"rejection_reason": "failed gates: temporary_recovery, old_task_regression, canary_ready",
"failure": "disabled temporary-timeout retries"
}
],
"behavior_metrics": {
"stable_buggy_baseline": {
"mean_nonretryable_calls": 3.5,
"temporary_error_recovery_rate": 1.0,
"old_task_regressions": 0
},
"deterministic": {
"mean_nonretryable_calls": 1.0,
"temporary_error_recovery_rate": 1.0,
"old_task_regressions": 0
},
"real_llm": {
"mean_nonretryable_calls": 1.0,
"temporary_error_recovery_rate": 1.0,
"old_task_regressions": 0
},
"rejected_control": {
"mean_nonretryable_calls": 1.0,
"temporary_error_recovery_rate": 0.0,
"old_task_regressions": 1
}
},
"comparison": {
"deterministic": {
"decision": "release_to_canary",
"checks": {
"static_compile": true,
"public_api_compatible": true,
"security_scan": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": true,
"old_task_regression": true,
"canary_ready": true,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"patch_size": {
"added_lines": 7,
"deleted_lines": 3,
"changed_lines": 10
},
"behavior": {
"mean_nonretryable_calls": 1.0,
"temporary_error_recovery_rate": 1.0,
"old_task_regressions": 0
}
},
"real_llm": {
"decision": "release_to_canary",
"checks": {
"static_compile": true,
"public_api_compatible": true,
"security_scan": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": true,
"old_task_regression": true,
"canary_ready": true,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"patch_size": {
"added_lines": 6,
"deleted_lines": 4,
"changed_lines": 10
},
"behavior": {
"mean_nonretryable_calls": 1.0,
"temporary_error_recovery_rate": 1.0,
"old_task_regressions": 0
}
},
"rejected_control": {
"decision": "reject_candidate",
"checks": {
"static_compile": true,
"public_api_compatible": true,
"security_scan": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": false,
"old_task_regression": false,
"canary_ready": false,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"patch_size": {
"added_lines": 6,
"deleted_lines": 4,
"changed_lines": 10
},
"behavior": {
"mean_nonretryable_calls": 1.0,
"temporary_error_recovery_rate": 0.0,
"old_task_regressions": 1
}
}
},
"manifests": {
"deterministic": {
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,20 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.1.0-candidate\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n-NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n+NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\", \"PAYMENT_DECLINED\"}\n \n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"before": "up to 4",
"after": 1
},
"temporary_timeout_recovery_rate": {
"before": 1.0,
"after": 1.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "b0fb4d1caf96",
"candidate_sha256": "b0fb4d1caf96c7aca16fc53d1dcf518345ea1a5b0aef9b60168f24534acf552c",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,20 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.1.0-candidate\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n-NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n+NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\", \"PAYMENT_DECLINED\"}\n \n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 7,
"deleted_lines": 3,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"public_api_compatible": true,
"security_scan": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": true,
"old_task_regression": true,
"canary_ready": true,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [],
"canary_gate": {
"eligible": true,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "deterministic",
"model": null,
"api_calls": 0
},
"decision": "release_to_canary",
"rejection_reason": null
},
"real_llm": {
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,18 @@\n-\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n-\n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n-NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n+NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\", \"PAYMENT_DECLINED\"}\n \n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n \"\"\"Open after repeated failures.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"before": "up to 4",
"after": 1
},
"temporary_timeout_recovery_rate": {
"before": 1.0,
"after": 1.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "801604c8b4eb",
"candidate_sha256": "801604c8b4ebe0611dc0d78c4b0131736341bcac990df6ad817607b8486d402b",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,18 @@\n-\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n-\n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n-NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n+NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\", \"PAYMENT_DECLINED\"}\n \n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n \"\"\"Open after repeated failures.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 6,
"deleted_lines": 4,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"public_api_compatible": true,
"security_scan": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": true,
"old_task_regression": true,
"canary_ready": true,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [],
"canary_gate": {
"eligible": true,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "real_llm_coding_agent",
"model": "doubao-seed-1-6-250615",
"provider": "ark",
"seed": 8501,
"api_calls": 1,
"receipt": {
"backend": {
"provider": "ark",
"endpoint": "https://ark.cn-beijing.volces.com/api/v3/chat/completions",
"credential_env": "ARK_API_KEY",
"model": "doubao-seed-1-6-250615",
"credential_value_recorded": false
},
"request": {
"model": "doubao-seed-1-6-250615",
"messages": [
{
"role": "user",
"content": "You are the Coding Agent in a controlled self-modification pipeline.\n\nModify only the supplied retry-policy module. Preserve both public function\nsignatures and retry behavior for temporary failures. Permanent failures\n(retryable=false or a listed permanent code) must not be retried and must open\nthe circuit on the first occurrence. Update VERSION to a candidate version.\nDo not import modules, access files, or alter validation/release logic.\n\nBefore the source, predict the intended impact. Return JSON only:\n{\"impact_prediction\": {\"non_retryable_calls\": {\"before\": \"up to 4\", \"after\": 1},\n\"temporary_timeout_recovery_rate\": {\"before\": 1.0, \"after\": 1.0}},\n\"source\": \"the complete Python module\"}\n\nFailure diagnosis:\n{\n \"change_required\": true,\n \"target\": \"stable/retry_policy.py\",\n \"target_component\": \"retry_and_circuit_breaker_control\",\n \"source_case_ids\": [\n \"run-payment-001\",\n \"run-payment-002\"\n ],\n \"source_trajectories\": [\n {\n \"id\": \"run-payment-001\",\n \"trajectory_sha256\": \"4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008\",\n \"evidence\": \"The same declined payment was submitted four times.\"\n },\n {\n \"id\": \"run-payment-002\",\n \"trajectory_sha256\": \"6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59\",\n \"evidence\": \"A second task repeated the identical non-retryable call three times.\"\n }\n ],\n \"patterns\": [\n {\n \"cluster_id\": \"charge_card:PAYMENT_DECLINED\",\n \"tool\": \"charge_card\",\n \"error_code\": \"PAYMENT_DECLINED\",\n \"source_case_ids\": [\n \"run-payment-001\",\n \"run-payment-002\"\n ],\n \"cross_trajectory_support\": 2,\n \"total_redundant_calls\": 5\n }\n ],\n \"reason\": \"The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.\",\n \"change_contract\": {\n \"expected_fix\": [\n \"non-retryable tool-call attempts fall to one\",\n \"the circuit opens on the first permanent failure\"\n ],\n \"potential_regressions\": [\n \"temporary timeouts stop retrying\",\n \"the five-failure circuit threshold changes for retryable errors\",\n \"public function signatures change\"\n ]\n }\n}\n\nPreviously rejected candidates (do not repeat their failure):\n[\n {\n \"candidate_sha256\": \"824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2\",\n \"failed_checks\": [\n \"temporary_recovery\",\n \"old_task_regression\",\n \"canary_ready\"\n ],\n \"rejection_reason\": \"failed gates: temporary_recovery, old_task_regression, canary_ready\",\n \"failure\": \"disabled temporary-timeout retries\"\n }\n]\n\nStable module:\n\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n\nVERSION = \"1.0.0\"\nMAX_RETRIES = 3\nCIRCUIT_BREAKER_THRESHOLD = 5\nNON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n\n\ndef should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n return attempt < MAX_RETRIES\n\n\ndef should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n \"\"\"Open after repeated failures.\"\"\"\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n\n"
}
],
"temperature": 0,
"seed": 8501,
"max_tokens": 1400,
"response_format": {
"type": "json_object"
}
},
"response": {
"id": "0217853450409166bc656bbd49cfaee971fadc31892ba5b3aa2b5",
"choices": [
{
"finish_reason": "stop",
"index": 0,
"message": {
"content": "{\"impact_prediction\": {\"non_retryable_calls\": {\"before\": \"up to 4\", \"after\": 1}, \"temporary_timeout_recovery_rate\": {\"before\": 1.0, \"after\": 1.0}}, \"source\": \"VERSION = \\\"1.0.1\\\"\\nMAX_RETRIES = 3\\nCIRCUIT_BREAKER_THRESHOLD = 5\\nNON_RETRYABLE_CODES = {\\\"AUTH_DENIED\\\", \\\"INVALID_ARGUMENT\\\", \\\"PAYMENT_DECLINED\\\"}\\n\\n\\ndef should_retry(error_code, retryable, attempt):\\n \\\"\\\"\\\"Return whether another tool call should be attempted.\\\"\\\"\\\"\\n if not retryable or error_code in NON_RETRYABLE_CODES:\\n return False\\n return attempt < MAX_RETRIES\\n\\n\\ndef should_open_circuit(consecutive_failures, *, error_code=\\\"\\\", retryable=True):\\n \\\"\\\"\\\"Open after repeated failures.\\\"\\\"\\\"\\n if not retryable or error_code in NON_RETRYABLE_CODES:\\n return consecutive_failures >= 1\\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\"}",
"role": "assistant",
"reasoning_content": "Okay, let's tackle this problem. The user wants me to modify the retry-policy module to fix the issue where non-retryable errors are being retried multiple times, and the circuit isn't opening on the first permanent failure. \n\nFirst, I need to understand the current behavior. From the failure diagnosis, the problem is that even when an error is non-retryable (retryable=false) or has a permanent error code, the retry policy is still allowing retries. For example, in the cases provided, PAYMENT_DECLINED errors were retried multiple times, leading to redundant calls.\n\nLooking at the existing code:\n\nThe should_retry function currently checks if the attempt is less than MAX_RETRIES (which is 3). So even if the error is non-retryable, it would retry up to 3 times, leading to 4 total attempts (initial + 3 retries). That's why in the examples, there were 4 and 3 calls respectively.\n\nThe should_open_circuit function opens the circuit only after consecutive_failures reach CIRCUIT_BREAKER_THRESHOLD (5), regardless of the error type. So permanent failures aren't triggering the circuit to open immediately.\n\nThe change needs to ensure that non-retryable errors (either retryable=false or in NON_RETRYABLE_CODES) are not retried. So should_retry should return False in those cases. Also, when such an error occurs, the circuit should open on the first occurrence.\n\nSo modifying should_retry:\n\nOriginal: return attempt < MAX_RETRIES\n\nNew logic: Only retry if retryable is True, the error_code is not in NON_RETRYABLE_CODES, and attempt < MAX_RETRIES.\n\nWait, the parameters for should_retry are error_code, retryable, attempt. So the function should check if retryable is False, then return False. Also, if error_code is in NON_RETRYABLE_CODES, return False. Otherwise, check if attempt < MAX_RETRIES.\n\nSo the should_retry function should be:\n\ndef should_retry(error_code, retryable, attempt):\n if not retryable or error_code in NON_RETRYABLE_CODES:\n return False\n return attempt < MAX_RETRIES\n\nThat way, if either retryable is False or the error code is non-retryable, it won't retry. So the initial attempt is 1, and no retries, so total 1 call. Which fixes the first part of the problem.\n\nFor the circuit breaker: should_open_circuit needs to open on the first permanent failure. So if the error is non-retryable (retryable=False or error_code in NON_RETRYABLE_CODES), then consecutive_failures >=1 should trigger the circuit. But how does the current function get the error info? The parameters are consecutive_failures, and keyword args error_code and retryable.\n\nSo modifying should_open_circuit:\n\nOriginal: return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n\nNew logic: If the error is a permanent failure (retryable=False or error_code in NON_RETRYABLE_CODES), then open the circuit if consecutive_failures >=1. Otherwise, use the existing threshold of 5.\n\nSo:\n\ndef should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n if not retryable or error_code in NON_RETRYABLE_CODES:\n return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n\nThis way, for permanent errors, even one failure opens the circuit. For temporary ones, it still takes 5.\n\nAlso, the VERSION needs to be updated. The original is 1.0.0, so maybe 1.0.1 or 1.1.0. Since it's a bug fix, 1.0.1 makes sense.\n\nPutting it all together:\n\nUpdate VERSION to \"1.0.1\".\n\nModify should_retry to check retryable and error_code.\n\nModify should_open_circuit to check for permanent errors and open on first failure.\n\nTesting for possible regressions: The problem mentions that temporary timeouts should still retry. So if a temporary error (retryable=True and not in NON_RETRYABLE_CODES) occurs, the retries should still happen. The original MAX_RETRIES is 3, so 4 attempts total. The new code preserves that, so temporary_timeout_recovery_rate remains 1.0.\n\nSo the impact prediction would be non_retryable_calls before up to 4 (initial + 3 retries), after 1. Temporary timeout recovery rate remains 1.0.\n\nThus, the JSON impact prediction is as specified.\n\nNow, the source code with these changes.\n"
}
}
],
"created": 1785345078,
"model": "doubao-seed-1-6-250615",
"object": "chat.completion",
"service_tier": "default",
"usage": {
"completion_tokens": 1276,
"prompt_tokens": 1128,
"total_tokens": 2404,
"completion_tokens_details": {
"reasoning_tokens": 1019
},
"prompt_tokens_details": {
"cached_tokens": 0
}
}
},
"request_sha256": "fe5695eec21fe9f9674035f307d8e5f6bfacafa244a8184eb734188d6be405af",
"response_sha256": "ba47b7677546e460af60eac62f20d263c5fbb4432fdffc40cc00ad01d6f6f034",
"elapsed_seconds": 37.571053,
"usage": {
"prompt_tokens": 1128,
"completion_tokens": 1276,
"total_tokens": 2404,
"provider_reported_cost_usd": null,
"cost_qualification": "provider did not expose monetary cost; no price was guessed"
}
}
},
"decision": "release_to_canary",
"rejection_reason": null
},
"rejected_control": {
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,18 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rejected\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n \n \n def should_retry(error_code, retryable, attempt):\n- \"\"\"Return whether another tool call should be attempted.\"\"\"\n- return attempt < MAX_RETRIES\n+ \"\"\"Incorrect over-broad fix retained as a rejected candidate.\"\"\"\n+ return False\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"after": 1
},
"temporary_timeout_recovery_rate": {
"after": 0.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "824bbfb244a7",
"candidate_sha256": "824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,18 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rejected\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n \n \n def should_retry(error_code, retryable, attempt):\n- \"\"\"Return whether another tool call should be attempted.\"\"\"\n- return attempt < MAX_RETRIES\n+ \"\"\"Incorrect over-broad fix retained as a rejected candidate.\"\"\"\n+ return False\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 6,
"deleted_lines": 4,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"public_api_compatible": true,
"security_scan": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": false,
"old_task_regression": false,
"canary_ready": false,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [
"temporary_recovery",
"old_task_regression",
"canary_ready"
],
"canary_gate": {
"eligible": false,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "negative_control",
"api_calls": 0
},
"decision": "reject_candidate",
"rejection_reason": "failed gates: temporary_recovery, old_task_regression, canary_ready"
}
},
"raw_api_receipts": [
{
"backend": {
"provider": "ark",
"endpoint": "https://ark.cn-beijing.volces.com/api/v3/chat/completions",
"credential_env": "ARK_API_KEY",
"model": "doubao-seed-1-6-250615",
"credential_value_recorded": false
},
"request": {
"model": "doubao-seed-1-6-250615",
"messages": [
{
"role": "user",
"content": "You are the Coding Agent in a controlled self-modification pipeline.\n\nModify only the supplied retry-policy module. Preserve both public function\nsignatures and retry behavior for temporary failures. Permanent failures\n(retryable=false or a listed permanent code) must not be retried and must open\nthe circuit on the first occurrence. Update VERSION to a candidate version.\nDo not import modules, access files, or alter validation/release logic.\n\nBefore the source, predict the intended impact. Return JSON only:\n{\"impact_prediction\": {\"non_retryable_calls\": {\"before\": \"up to 4\", \"after\": 1},\n\"temporary_timeout_recovery_rate\": {\"before\": 1.0, \"after\": 1.0}},\n\"source\": \"the complete Python module\"}\n\nFailure diagnosis:\n{\n \"change_required\": true,\n \"target\": \"stable/retry_policy.py\",\n \"target_component\": \"retry_and_circuit_breaker_control\",\n \"source_case_ids\": [\n \"run-payment-001\",\n \"run-payment-002\"\n ],\n \"source_trajectories\": [\n {\n \"id\": \"run-payment-001\",\n \"trajectory_sha256\": \"4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008\",\n \"evidence\": \"The same declined payment was submitted four times.\"\n },\n {\n \"id\": \"run-payment-002\",\n \"trajectory_sha256\": \"6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59\",\n \"evidence\": \"A second task repeated the identical non-retryable call three times.\"\n }\n ],\n \"patterns\": [\n {\n \"cluster_id\": \"charge_card:PAYMENT_DECLINED\",\n \"tool\": \"charge_card\",\n \"error_code\": \"PAYMENT_DECLINED\",\n \"source_case_ids\": [\n \"run-payment-001\",\n \"run-payment-002\"\n ],\n \"cross_trajectory_support\": 2,\n \"total_redundant_calls\": 5\n }\n ],\n \"reason\": \"The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.\",\n \"change_contract\": {\n \"expected_fix\": [\n \"non-retryable tool-call attempts fall to one\",\n \"the circuit opens on the first permanent failure\"\n ],\n \"potential_regressions\": [\n \"temporary timeouts stop retrying\",\n \"the five-failure circuit threshold changes for retryable errors\",\n \"public function signatures change\"\n ]\n }\n}\n\nPreviously rejected candidates (do not repeat their failure):\n[\n {\n \"candidate_sha256\": \"824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2\",\n \"failed_checks\": [\n \"temporary_recovery\",\n \"old_task_regression\",\n \"canary_ready\"\n ],\n \"rejection_reason\": \"failed gates: temporary_recovery, old_task_regression, canary_ready\",\n \"failure\": \"disabled temporary-timeout retries\"\n }\n]\n\nStable module:\n\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n\nVERSION = \"1.0.0\"\nMAX_RETRIES = 3\nCIRCUIT_BREAKER_THRESHOLD = 5\nNON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n\n\ndef should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n return attempt < MAX_RETRIES\n\n\ndef should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n \"\"\"Open after repeated failures.\"\"\"\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n\n"
}
],
"temperature": 0,
"seed": 8501,
"max_tokens": 1400,
"response_format": {
"type": "json_object"
}
},
"response": {
"id": "0217853450409166bc656bbd49cfaee971fadc31892ba5b3aa2b5",
"choices": [
{
"finish_reason": "stop",
"index": 0,
"message": {
"content": "{\"impact_prediction\": {\"non_retryable_calls\": {\"before\": \"up to 4\", \"after\": 1}, \"temporary_timeout_recovery_rate\": {\"before\": 1.0, \"after\": 1.0}}, \"source\": \"VERSION = \\\"1.0.1\\\"\\nMAX_RETRIES = 3\\nCIRCUIT_BREAKER_THRESHOLD = 5\\nNON_RETRYABLE_CODES = {\\\"AUTH_DENIED\\\", \\\"INVALID_ARGUMENT\\\", \\\"PAYMENT_DECLINED\\\"}\\n\\n\\ndef should_retry(error_code, retryable, attempt):\\n \\\"\\\"\\\"Return whether another tool call should be attempted.\\\"\\\"\\\"\\n if not retryable or error_code in NON_RETRYABLE_CODES:\\n return False\\n return attempt < MAX_RETRIES\\n\\n\\ndef should_open_circuit(consecutive_failures, *, error_code=\\\"\\\", retryable=True):\\n \\\"\\\"\\\"Open after repeated failures.\\\"\\\"\\\"\\n if not retryable or error_code in NON_RETRYABLE_CODES:\\n return consecutive_failures >= 1\\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\"}",
"role": "assistant",
"reasoning_content": "Okay, let's tackle this problem. The user wants me to modify the retry-policy module to fix the issue where non-retryable errors are being retried multiple times, and the circuit isn't opening on the first permanent failure. \n\nFirst, I need to understand the current behavior. From the failure diagnosis, the problem is that even when an error is non-retryable (retryable=false) or has a permanent error code, the retry policy is still allowing retries. For example, in the cases provided, PAYMENT_DECLINED errors were retried multiple times, leading to redundant calls.\n\nLooking at the existing code:\n\nThe should_retry function currently checks if the attempt is less than MAX_RETRIES (which is 3). So even if the error is non-retryable, it would retry up to 3 times, leading to 4 total attempts (initial + 3 retries). That's why in the examples, there were 4 and 3 calls respectively.\n\nThe should_open_circuit function opens the circuit only after consecutive_failures reach CIRCUIT_BREAKER_THRESHOLD (5), regardless of the error type. So permanent failures aren't triggering the circuit to open immediately.\n\nThe change needs to ensure that non-retryable errors (either retryable=false or in NON_RETRYABLE_CODES) are not retried. So should_retry should return False in those cases. Also, when such an error occurs, the circuit should open on the first occurrence.\n\nSo modifying should_retry:\n\nOriginal: return attempt < MAX_RETRIES\n\nNew logic: Only retry if retryable is True, the error_code is not in NON_RETRYABLE_CODES, and attempt < MAX_RETRIES.\n\nWait, the parameters for should_retry are error_code, retryable, attempt. So the function should check if retryable is False, then return False. Also, if error_code is in NON_RETRYABLE_CODES, return False. Otherwise, check if attempt < MAX_RETRIES.\n\nSo the should_retry function should be:\n\ndef should_retry(error_code, retryable, attempt):\n if not retryable or error_code in NON_RETRYABLE_CODES:\n return False\n return attempt < MAX_RETRIES\n\nThat way, if either retryable is False or the error code is non-retryable, it won't retry. So the initial attempt is 1, and no retries, so total 1 call. Which fixes the first part of the problem.\n\nFor the circuit breaker: should_open_circuit needs to open on the first permanent failure. So if the error is non-retryable (retryable=False or error_code in NON_RETRYABLE_CODES), then consecutive_failures >=1 should trigger the circuit. But how does the current function get the error info? The parameters are consecutive_failures, and keyword args error_code and retryable.\n\nSo modifying should_open_circuit:\n\nOriginal: return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n\nNew logic: If the error is a permanent failure (retryable=False or error_code in NON_RETRYABLE_CODES), then open the circuit if consecutive_failures >=1. Otherwise, use the existing threshold of 5.\n\nSo:\n\ndef should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n if not retryable or error_code in NON_RETRYABLE_CODES:\n return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n\nThis way, for permanent errors, even one failure opens the circuit. For temporary ones, it still takes 5.\n\nAlso, the VERSION needs to be updated. The original is 1.0.0, so maybe 1.0.1 or 1.1.0. Since it's a bug fix, 1.0.1 makes sense.\n\nPutting it all together:\n\nUpdate VERSION to \"1.0.1\".\n\nModify should_retry to check retryable and error_code.\n\nModify should_open_circuit to check for permanent errors and open on first failure.\n\nTesting for possible regressions: The problem mentions that temporary timeouts should still retry. So if a temporary error (retryable=True and not in NON_RETRYABLE_CODES) occurs, the retries should still happen. The original MAX_RETRIES is 3, so 4 attempts total. The new code preserves that, so temporary_timeout_recovery_rate remains 1.0.\n\nSo the impact prediction would be non_retryable_calls before up to 4 (initial + 3 retries), after 1. Temporary timeout recovery rate remains 1.0.\n\nThus, the JSON impact prediction is as specified.\n\nNow, the source code with these changes.\n"
}
}
],
"created": 1785345078,
"model": "doubao-seed-1-6-250615",
"object": "chat.completion",
"service_tier": "default",
"usage": {
"completion_tokens": 1276,
"prompt_tokens": 1128,
"total_tokens": 2404,
"completion_tokens_details": {
"reasoning_tokens": 1019
},
"prompt_tokens_details": {
"cached_tokens": 0
}
}
},
"request_sha256": "fe5695eec21fe9f9674035f307d8e5f6bfacafa244a8184eb734188d6be405af",
"response_sha256": "ba47b7677546e460af60eac62f20d263c5fbb4432fdffc40cc00ad01d6f6f034",
"elapsed_seconds": 37.571053,
"usage": {
"prompt_tokens": 1128,
"completion_tokens": 1276,
"total_tokens": 2404,
"provider_reported_cost_usd": null,
"cost_qualification": "provider did not expose monetary cost; no price was guessed"
}
}
],
"cost": {
"prompt_tokens": 1128,
"completion_tokens": 1276,
"total_tokens": 2404,
"provider_reported_cost_usd": null,
"cost_qualification": "provider did not expose monetary cost; no price was guessed"
},
"candidate_acceptance_rate": 0.6666666666666666,
"gates": {
"cross_trajectory_support_met": true,
"root_cause_targets_control_code": true,
"real_coding_model_called": true,
"impact_prediction_precedes_validation": true,
"all_candidates_isolated": true,
"trusted_surfaces_unchanged": true,
"same_release_gate_for_both_generators": true,
"deterministic_candidate_release_to_canary": true,
"real_llm_candidate_release_to_canary": true,
"known_bad_candidate_rejected_and_retained": true,
"failure_replay_reduces_calls": true,
"temporary_recovery_preserved": true,
"old_task_regression_zero": true,
"canary_only_not_production": true,
"rollback_hash_pinned_to_stable": true,
"release_manifest_fields_complete": true
},
"accepted": true
}
@@ -0,0 +1 @@
3a9a053ce7f021712ccf8503e089be665df2730a0e986908e865fdcabae0a395 evidence.json
@@ -0,0 +1,157 @@
{
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,18 @@\n-\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n-\n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n-NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n+NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\", \"PAYMENT_DECLINED\"}\n \n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n \"\"\"Open after repeated failures.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"before": "up to 4",
"after": 1
},
"temporary_timeout_recovery_rate": {
"before": 1.0,
"after": 1.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "801604c8b4eb",
"candidate_sha256": "801604c8b4ebe0611dc0d78c4b0131736341bcac990df6ad817607b8486d402b",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,18 @@\n-\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n-\n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n-NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n+NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\", \"PAYMENT_DECLINED\"}\n \n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n \"\"\"Open after repeated failures.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 6,
"deleted_lines": 4,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"public_api_compatible": true,
"security_scan": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": true,
"old_task_regression": true,
"canary_ready": true,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [],
"canary_gate": {
"eligible": true,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "real_llm_coding_agent",
"model": "doubao-seed-1-6-250615",
"provider": "ark",
"seed": 8501,
"api_calls": 1,
"receipt": {
"backend": {
"provider": "ark",
"endpoint": "https://ark.cn-beijing.volces.com/api/v3/chat/completions",
"credential_env": "ARK_API_KEY",
"model": "doubao-seed-1-6-250615",
"credential_value_recorded": false
},
"request": {
"model": "doubao-seed-1-6-250615",
"messages": [
{
"role": "user",
"content": "You are the Coding Agent in a controlled self-modification pipeline.\n\nModify only the supplied retry-policy module. Preserve both public function\nsignatures and retry behavior for temporary failures. Permanent failures\n(retryable=false or a listed permanent code) must not be retried and must open\nthe circuit on the first occurrence. Update VERSION to a candidate version.\nDo not import modules, access files, or alter validation/release logic.\n\nBefore the source, predict the intended impact. Return JSON only:\n{\"impact_prediction\": {\"non_retryable_calls\": {\"before\": \"up to 4\", \"after\": 1},\n\"temporary_timeout_recovery_rate\": {\"before\": 1.0, \"after\": 1.0}},\n\"source\": \"the complete Python module\"}\n\nFailure diagnosis:\n{\n \"change_required\": true,\n \"target\": \"stable/retry_policy.py\",\n \"target_component\": \"retry_and_circuit_breaker_control\",\n \"source_case_ids\": [\n \"run-payment-001\",\n \"run-payment-002\"\n ],\n \"source_trajectories\": [\n {\n \"id\": \"run-payment-001\",\n \"trajectory_sha256\": \"4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008\",\n \"evidence\": \"The same declined payment was submitted four times.\"\n },\n {\n \"id\": \"run-payment-002\",\n \"trajectory_sha256\": \"6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59\",\n \"evidence\": \"A second task repeated the identical non-retryable call three times.\"\n }\n ],\n \"patterns\": [\n {\n \"cluster_id\": \"charge_card:PAYMENT_DECLINED\",\n \"tool\": \"charge_card\",\n \"error_code\": \"PAYMENT_DECLINED\",\n \"source_case_ids\": [\n \"run-payment-001\",\n \"run-payment-002\"\n ],\n \"cross_trajectory_support\": 2,\n \"total_redundant_calls\": 5\n }\n ],\n \"reason\": \"The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.\",\n \"change_contract\": {\n \"expected_fix\": [\n \"non-retryable tool-call attempts fall to one\",\n \"the circuit opens on the first permanent failure\"\n ],\n \"potential_regressions\": [\n \"temporary timeouts stop retrying\",\n \"the five-failure circuit threshold changes for retryable errors\",\n \"public function signatures change\"\n ]\n }\n}\n\nPreviously rejected candidates (do not repeat their failure):\n[\n {\n \"candidate_sha256\": \"824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2\",\n \"failed_checks\": [\n \"temporary_recovery\",\n \"old_task_regression\",\n \"canary_ready\"\n ],\n \"rejection_reason\": \"failed gates: temporary_recovery, old_task_regression, canary_ready\",\n \"failure\": \"disabled temporary-timeout retries\"\n }\n]\n\nStable module:\n\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n\nVERSION = \"1.0.0\"\nMAX_RETRIES = 3\nCIRCUIT_BREAKER_THRESHOLD = 5\nNON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n\n\ndef should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n return attempt < MAX_RETRIES\n\n\ndef should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n \"\"\"Open after repeated failures.\"\"\"\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n\n"
}
],
"temperature": 0,
"seed": 8501,
"max_tokens": 1400,
"response_format": {
"type": "json_object"
}
},
"response": {
"id": "0217853450409166bc656bbd49cfaee971fadc31892ba5b3aa2b5",
"choices": [
{
"finish_reason": "stop",
"index": 0,
"message": {
"content": "{\"impact_prediction\": {\"non_retryable_calls\": {\"before\": \"up to 4\", \"after\": 1}, \"temporary_timeout_recovery_rate\": {\"before\": 1.0, \"after\": 1.0}}, \"source\": \"VERSION = \\\"1.0.1\\\"\\nMAX_RETRIES = 3\\nCIRCUIT_BREAKER_THRESHOLD = 5\\nNON_RETRYABLE_CODES = {\\\"AUTH_DENIED\\\", \\\"INVALID_ARGUMENT\\\", \\\"PAYMENT_DECLINED\\\"}\\n\\n\\ndef should_retry(error_code, retryable, attempt):\\n \\\"\\\"\\\"Return whether another tool call should be attempted.\\\"\\\"\\\"\\n if not retryable or error_code in NON_RETRYABLE_CODES:\\n return False\\n return attempt < MAX_RETRIES\\n\\n\\ndef should_open_circuit(consecutive_failures, *, error_code=\\\"\\\", retryable=True):\\n \\\"\\\"\\\"Open after repeated failures.\\\"\\\"\\\"\\n if not retryable or error_code in NON_RETRYABLE_CODES:\\n return consecutive_failures >= 1\\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\"}",
"role": "assistant",
"reasoning_content": "Okay, let's tackle this problem. The user wants me to modify the retry-policy module to fix the issue where non-retryable errors are being retried multiple times, and the circuit isn't opening on the first permanent failure. \n\nFirst, I need to understand the current behavior. From the failure diagnosis, the problem is that even when an error is non-retryable (retryable=false) or has a permanent error code, the retry policy is still allowing retries. For example, in the cases provided, PAYMENT_DECLINED errors were retried multiple times, leading to redundant calls.\n\nLooking at the existing code:\n\nThe should_retry function currently checks if the attempt is less than MAX_RETRIES (which is 3). So even if the error is non-retryable, it would retry up to 3 times, leading to 4 total attempts (initial + 3 retries). That's why in the examples, there were 4 and 3 calls respectively.\n\nThe should_open_circuit function opens the circuit only after consecutive_failures reach CIRCUIT_BREAKER_THRESHOLD (5), regardless of the error type. So permanent failures aren't triggering the circuit to open immediately.\n\nThe change needs to ensure that non-retryable errors (either retryable=false or in NON_RETRYABLE_CODES) are not retried. So should_retry should return False in those cases. Also, when such an error occurs, the circuit should open on the first occurrence.\n\nSo modifying should_retry:\n\nOriginal: return attempt < MAX_RETRIES\n\nNew logic: Only retry if retryable is True, the error_code is not in NON_RETRYABLE_CODES, and attempt < MAX_RETRIES.\n\nWait, the parameters for should_retry are error_code, retryable, attempt. So the function should check if retryable is False, then return False. Also, if error_code is in NON_RETRYABLE_CODES, return False. Otherwise, check if attempt < MAX_RETRIES.\n\nSo the should_retry function should be:\n\ndef should_retry(error_code, retryable, attempt):\n if not retryable or error_code in NON_RETRYABLE_CODES:\n return False\n return attempt < MAX_RETRIES\n\nThat way, if either retryable is False or the error code is non-retryable, it won't retry. So the initial attempt is 1, and no retries, so total 1 call. Which fixes the first part of the problem.\n\nFor the circuit breaker: should_open_circuit needs to open on the first permanent failure. So if the error is non-retryable (retryable=False or error_code in NON_RETRYABLE_CODES), then consecutive_failures >=1 should trigger the circuit. But how does the current function get the error info? The parameters are consecutive_failures, and keyword args error_code and retryable.\n\nSo modifying should_open_circuit:\n\nOriginal: return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n\nNew logic: If the error is a permanent failure (retryable=False or error_code in NON_RETRYABLE_CODES), then open the circuit if consecutive_failures >=1. Otherwise, use the existing threshold of 5.\n\nSo:\n\ndef should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n if not retryable or error_code in NON_RETRYABLE_CODES:\n return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n\nThis way, for permanent errors, even one failure opens the circuit. For temporary ones, it still takes 5.\n\nAlso, the VERSION needs to be updated. The original is 1.0.0, so maybe 1.0.1 or 1.1.0. Since it's a bug fix, 1.0.1 makes sense.\n\nPutting it all together:\n\nUpdate VERSION to \"1.0.1\".\n\nModify should_retry to check retryable and error_code.\n\nModify should_open_circuit to check for permanent errors and open on first failure.\n\nTesting for possible regressions: The problem mentions that temporary timeouts should still retry. So if a temporary error (retryable=True and not in NON_RETRYABLE_CODES) occurs, the retries should still happen. The original MAX_RETRIES is 3, so 4 attempts total. The new code preserves that, so temporary_timeout_recovery_rate remains 1.0.\n\nSo the impact prediction would be non_retryable_calls before up to 4 (initial + 3 retries), after 1. Temporary timeout recovery rate remains 1.0.\n\nThus, the JSON impact prediction is as specified.\n\nNow, the source code with these changes.\n"
}
}
],
"created": 1785345078,
"model": "doubao-seed-1-6-250615",
"object": "chat.completion",
"service_tier": "default",
"usage": {
"completion_tokens": 1276,
"prompt_tokens": 1128,
"total_tokens": 2404,
"completion_tokens_details": {
"reasoning_tokens": 1019
},
"prompt_tokens_details": {
"cached_tokens": 0
}
}
},
"request_sha256": "fe5695eec21fe9f9674035f307d8e5f6bfacafa244a8184eb734188d6be405af",
"response_sha256": "ba47b7677546e460af60eac62f20d263c5fbb4432fdffc40cc00ad01d6f6f034",
"elapsed_seconds": 37.571053,
"usage": {
"prompt_tokens": 1128,
"completion_tokens": 1276,
"total_tokens": 2404,
"provider_reported_cost_usd": null,
"cost_qualification": "provider did not expose monetary cost; no price was guessed"
}
}
},
"decision": "release_to_canary",
"rejection_reason": null
}
@@ -0,0 +1,93 @@
{
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,18 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rejected\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n \n \n def should_retry(error_code, retryable, attempt):\n- \"\"\"Return whether another tool call should be attempted.\"\"\"\n- return attempt < MAX_RETRIES\n+ \"\"\"Incorrect over-broad fix retained as a rejected candidate.\"\"\"\n+ return False\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"after": 1
},
"temporary_timeout_recovery_rate": {
"after": 0.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "824bbfb244a7",
"candidate_sha256": "824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,18 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rejected\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n \n \n def should_retry(error_code, retryable, attempt):\n- \"\"\"Return whether another tool call should be attempted.\"\"\"\n- return attempt < MAX_RETRIES\n+ \"\"\"Incorrect over-broad fix retained as a rejected candidate.\"\"\"\n+ return False\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 6,
"deleted_lines": 4,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"public_api_compatible": true,
"security_scan": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": false,
"old_task_regression": false,
"canary_ready": false,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [
"temporary_recovery",
"old_task_regression",
"canary_ready"
],
"canary_gate": {
"eligible": false,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "negative_control",
"api_calls": 0
},
"decision": "reject_candidate",
"rejection_reason": "failed gates: temporary_recovery, old_task_regression, canary_ready"
}
@@ -0,0 +1,5 @@
{
"candidates/deterministic/retry_policy.py": "b0fb4d1caf96c7aca16fc53d1dcf518345ea1a5b0aef9b60168f24534acf552c",
"candidates/real_llm/retry_policy.py": "d6e79810003e7d5f3e8d43ace0688e38033b08a4752bb0dfb9260d9bbe976b8f",
"candidates/rejected_control/retry_policy.py": "824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2"
}
@@ -0,0 +1,20 @@
"""Stable version 1.0.0. It intentionally contains the reproduced bug."""
VERSION = "1.1.0-candidate"
MAX_RETRIES = 3
CIRCUIT_BREAKER_THRESHOLD = 5
NON_RETRYABLE_CODES = {"AUTH_DENIED", "INVALID_ARGUMENT", "PAYMENT_DECLINED"}
def should_retry(error_code, retryable, attempt):
"""Return whether another tool call should be attempted."""
if not retryable or error_code in NON_RETRYABLE_CODES:
return False
return attempt < MAX_RETRIES
def should_open_circuit(consecutive_failures, *, error_code="", retryable=True):
"""Open immediately for permanent errors; otherwise use the threshold."""
if not retryable or error_code in NON_RETRYABLE_CODES:
return consecutive_failures >= 1
return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD
@@ -0,0 +1,20 @@
"""Candidate version 1.0.1-rc.1 with permanent-failure handling."""
VERSION = "1.0.1-rc.1"
MAX_RETRIES = 3
CIRCUIT_BREAKER_THRESHOLD = 5
NON_RETRYABLE_CODES = {"AUTH_DENIED", "INVALID_ARGUMENT"}
def should_retry(error_code, retryable, attempt):
"""Return whether another tool call should be attempted."""
if not retryable or error_code in NON_RETRYABLE_CODES:
return False
return attempt < MAX_RETRIES
def should_open_circuit(consecutive_failures, *, error_code="", retryable=True):
"""Open immediately for permanent failures or after repeated temporary failures."""
if not retryable or error_code in NON_RETRYABLE_CODES:
return consecutive_failures >= 1
return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD
@@ -0,0 +1,18 @@
"""Stable version 1.0.0. It intentionally contains the reproduced bug."""
VERSION = "1.0.1-rejected"
MAX_RETRIES = 3
CIRCUIT_BREAKER_THRESHOLD = 5
NON_RETRYABLE_CODES = {"AUTH_DENIED", "INVALID_ARGUMENT"}
def should_retry(error_code, retryable, attempt):
"""Incorrect over-broad fix retained as a rejected candidate."""
return False
def should_open_circuit(consecutive_failures, *, error_code="", retryable=True):
"""Open immediately for permanent errors; otherwise use the threshold."""
if not retryable or error_code in NON_RETRYABLE_CODES:
return consecutive_failures >= 1
return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD
@@ -0,0 +1,93 @@
{
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,20 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.1.0-candidate\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n-NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n+NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\", \"PAYMENT_DECLINED\"}\n \n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"before": "up to 4",
"after": 1
},
"temporary_timeout_recovery_rate": {
"before": 1.0,
"after": 1.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "b0fb4d1caf96",
"candidate_sha256": "b0fb4d1caf96c7aca16fc53d1dcf518345ea1a5b0aef9b60168f24534acf552c",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,20 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.1.0-candidate\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n-NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n+NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\", \"PAYMENT_DECLINED\"}\n \n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 7,
"deleted_lines": 3,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"security_scan": true,
"sandbox_execution": true,
"public_api_compatible": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": true,
"old_task_regression": true,
"canary_ready": true,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [],
"canary_gate": {
"eligible": true,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "deterministic",
"model": null,
"api_calls": 0
},
"decision": "release_to_canary",
"rejection_reason": null
}
@@ -0,0 +1,678 @@
{
"experiment": "9-6",
"executed_at": "2026-08-02T04:39:54.499339+00:00",
"execution_mode": "real_api_coding_agent_plus_model_external_release_harness",
"provider": "openrouter",
"model": "openai/gpt-5.6-sol",
"seed": 8501,
"input_artifacts": {
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"trajectory_sha256": "1e4664c40e99a5fcba2e9462226d7c32b611c573be9f9ba479ed2d26f844b0c2",
"validator_sha256_before_generation": "8c354d347b9d5423568205ebe7a5905dd580955756238674d648b9e00e2f6bd5",
"validator_sha256_after_generation": "8c354d347b9d5423568205ebe7a5905dd580955756238674d648b9e00e2f6bd5",
"trusted_surface_sha256_before": {
"evolution.py": "8c354d347b9d5423568205ebe7a5905dd580955756238674d648b9e00e2f6bd5",
"candidate_sandbox.py": "0fdd0576479c86482d8944050c2dc8a4d92c9eb696abaff4982bf1ad8b072fb8",
"sandbox_runner.py": "bc971dfa909758152ccad386096841dd30a68f4621be6c8d9650a51d2e8c46eb",
"Dockerfile.sandbox": "8c71105f404373a92cdd5923a894b05e1358ab42873d08d3d349a9fd3d2a1ade"
},
"trusted_surface_sha256_after": {
"evolution.py": "8c354d347b9d5423568205ebe7a5905dd580955756238674d648b9e00e2f6bd5",
"candidate_sandbox.py": "0fdd0576479c86482d8944050c2dc8a4d92c9eb696abaff4982bf1ad8b072fb8",
"sandbox_runner.py": "bc971dfa909758152ccad386096841dd30a68f4621be6c8d9650a51d2e8c46eb",
"Dockerfile.sandbox": "8c71105f404373a92cdd5923a894b05e1358ab42873d08d3d349a9fd3d2a1ade"
}
},
"candidate_sandbox": {
"image": "ai-agent-book/self-modifying-agent-sandbox:2548a1de2baf",
"network": "none",
"root_filesystem": "read_only",
"user": "65534:65534",
"memory": "64m",
"cpus": 0.5,
"wall_clock_timeout_seconds": 8.0
},
"diagnosis": {
"change_required": true,
"target": "stable/retry_policy.py",
"target_component": "retry_and_circuit_breaker_control",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"patterns": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"reason": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"change_contract": {
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
]
}
},
"rejected_history_given_to_coding_agent": [
{
"candidate_sha256": "824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2",
"failed_checks": [
"temporary_recovery",
"old_task_regression",
"canary_ready"
],
"rejection_reason": "failed gates: temporary_recovery, old_task_regression, canary_ready",
"failure": "disabled temporary-timeout retries"
}
],
"behavior_metrics": {
"stable_buggy_baseline": {
"mean_nonretryable_calls": 3.5,
"temporary_error_recovery_rate": 1.0,
"old_task_regressions": 0
},
"deterministic": {
"mean_nonretryable_calls": 1.0,
"temporary_error_recovery_rate": 1.0,
"old_task_regressions": 0
},
"real_llm": {
"mean_nonretryable_calls": 1.0,
"temporary_error_recovery_rate": 1.0,
"old_task_regressions": 0
},
"rejected_control": {
"mean_nonretryable_calls": 1.0,
"temporary_error_recovery_rate": 0.0,
"old_task_regressions": 1
}
},
"comparison": {
"deterministic": {
"decision": "release_to_canary",
"checks": {
"static_compile": true,
"security_scan": true,
"sandbox_execution": true,
"public_api_compatible": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": true,
"old_task_regression": true,
"canary_ready": true,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"patch_size": {
"added_lines": 7,
"deleted_lines": 3,
"changed_lines": 10
},
"behavior": {
"mean_nonretryable_calls": 1.0,
"temporary_error_recovery_rate": 1.0,
"old_task_regressions": 0
}
},
"real_llm": {
"decision": "release_to_canary",
"checks": {
"static_compile": true,
"security_scan": true,
"sandbox_execution": true,
"public_api_compatible": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": true,
"old_task_regression": true,
"canary_ready": true,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"patch_size": {
"added_lines": 7,
"deleted_lines": 3,
"changed_lines": 10
},
"behavior": {
"mean_nonretryable_calls": 1.0,
"temporary_error_recovery_rate": 1.0,
"old_task_regressions": 0
}
},
"rejected_control": {
"decision": "reject_candidate",
"checks": {
"static_compile": true,
"security_scan": true,
"sandbox_execution": true,
"public_api_compatible": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": false,
"old_task_regression": false,
"canary_ready": false,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"patch_size": {
"added_lines": 6,
"deleted_lines": 4,
"changed_lines": 10
},
"behavior": {
"mean_nonretryable_calls": 1.0,
"temporary_error_recovery_rate": 0.0,
"old_task_regressions": 1
}
}
},
"manifests": {
"deterministic": {
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,20 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.1.0-candidate\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n-NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n+NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\", \"PAYMENT_DECLINED\"}\n \n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"before": "up to 4",
"after": 1
},
"temporary_timeout_recovery_rate": {
"before": 1.0,
"after": 1.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "b0fb4d1caf96",
"candidate_sha256": "b0fb4d1caf96c7aca16fc53d1dcf518345ea1a5b0aef9b60168f24534acf552c",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,20 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.1.0-candidate\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n-NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n+NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\", \"PAYMENT_DECLINED\"}\n \n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 7,
"deleted_lines": 3,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"security_scan": true,
"sandbox_execution": true,
"public_api_compatible": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": true,
"old_task_regression": true,
"canary_ready": true,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [],
"canary_gate": {
"eligible": true,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "deterministic",
"model": null,
"api_calls": 0
},
"decision": "release_to_canary",
"rejection_reason": null
},
"real_llm": {
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,6 +1,6 @@\n-\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n+\"\"\"Candidate version 1.0.1-rc.1 with permanent-failure handling.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rc.1\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n@@ -8,9 +8,13 @@\n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent failures or after repeated temporary failures.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"before": "up to 4",
"after": 1
},
"temporary_timeout_recovery_rate": {
"before": 1.0,
"after": 1.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "d6e79810003e",
"candidate_sha256": "d6e79810003e7d5f3e8d43ace0688e38033b08a4752bb0dfb9260d9bbe976b8f",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,6 +1,6 @@\n-\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n+\"\"\"Candidate version 1.0.1-rc.1 with permanent-failure handling.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rc.1\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n@@ -8,9 +8,13 @@\n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent failures or after repeated temporary failures.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 7,
"deleted_lines": 3,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"security_scan": true,
"sandbox_execution": true,
"public_api_compatible": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": true,
"old_task_regression": true,
"canary_ready": true,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [],
"canary_gate": {
"eligible": true,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "real_llm_coding_agent",
"model": "openai/gpt-5.6-sol",
"provider": "openrouter",
"seed": 8501,
"api_calls": 1,
"receipt": {
"backend": {
"provider": "openrouter",
"endpoint": "https://openrouter.ai/api/v1/chat/completions",
"credential_env": "OPENROUTER_API_KEY",
"model": "openai/gpt-5.6-sol",
"credential_value_recorded": false
},
"request": {
"model": "openai/gpt-5.6-sol",
"messages": [
{
"role": "user",
"content": "You are the Coding Agent in a controlled self-modification pipeline.\n\nModify only the supplied retry-policy module. Preserve both public function\nsignatures and retry behavior for temporary failures. Permanent failures\n(retryable=false or a listed permanent code) must not be retried and must open\nthe circuit on the first occurrence. Update VERSION to a candidate version.\nDo not import modules, access files, or alter validation/release logic.\n\nBefore the source, predict the intended impact. Return JSON only:\n{\"impact_prediction\": {\"non_retryable_calls\": {\"before\": \"up to 4\", \"after\": 1},\n\"temporary_timeout_recovery_rate\": {\"before\": 1.0, \"after\": 1.0}},\n\"source\": \"the complete Python module\"}\n\nFailure diagnosis:\n{\n \"change_required\": true,\n \"target\": \"stable/retry_policy.py\",\n \"target_component\": \"retry_and_circuit_breaker_control\",\n \"source_case_ids\": [\n \"run-payment-001\",\n \"run-payment-002\"\n ],\n \"source_trajectories\": [\n {\n \"id\": \"run-payment-001\",\n \"trajectory_sha256\": \"4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008\",\n \"evidence\": \"The same declined payment was submitted four times.\"\n },\n {\n \"id\": \"run-payment-002\",\n \"trajectory_sha256\": \"6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59\",\n \"evidence\": \"A second task repeated the identical non-retryable call three times.\"\n }\n ],\n \"patterns\": [\n {\n \"cluster_id\": \"charge_card:PAYMENT_DECLINED\",\n \"tool\": \"charge_card\",\n \"error_code\": \"PAYMENT_DECLINED\",\n \"source_case_ids\": [\n \"run-payment-001\",\n \"run-payment-002\"\n ],\n \"cross_trajectory_support\": 2,\n \"total_redundant_calls\": 5\n }\n ],\n \"reason\": \"The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.\",\n \"change_contract\": {\n \"expected_fix\": [\n \"non-retryable tool-call attempts fall to one\",\n \"the circuit opens on the first permanent failure\"\n ],\n \"potential_regressions\": [\n \"temporary timeouts stop retrying\",\n \"the five-failure circuit threshold changes for retryable errors\",\n \"public function signatures change\"\n ]\n }\n}\n\nPreviously rejected candidates (do not repeat their failure):\n[\n {\n \"candidate_sha256\": \"824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2\",\n \"failed_checks\": [\n \"temporary_recovery\",\n \"old_task_regression\",\n \"canary_ready\"\n ],\n \"rejection_reason\": \"failed gates: temporary_recovery, old_task_regression, canary_ready\",\n \"failure\": \"disabled temporary-timeout retries\"\n }\n]\n\nStable module:\n\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n\nVERSION = \"1.0.0\"\nMAX_RETRIES = 3\nCIRCUIT_BREAKER_THRESHOLD = 5\nNON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n\n\ndef should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n return attempt < MAX_RETRIES\n\n\ndef should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n \"\"\"Open after repeated failures.\"\"\"\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n\n"
}
],
"temperature": 0,
"seed": 8501,
"max_tokens": 1400,
"response_format": {
"type": "json_object"
}
},
"response": {
"id": "gen-1785645586-58eflec0vxlXmqNTlbkd",
"choices": [
{
"finish_reason": "stop",
"index": 0,
"message": {
"content": "{\"impact_prediction\":{\"non_retryable_calls\":{\"before\":\"up to 4\",\"after\":1},\"temporary_timeout_recovery_rate\":{\"before\":1.0,\"after\":1.0}},\"source\":\"\\\"\\\"\\\"Candidate version 1.0.1-rc.1 with permanent-failure handling.\\\"\\\"\\\"\\n\\nVERSION = \\\"1.0.1-rc.1\\\"\\nMAX_RETRIES = 3\\nCIRCUIT_BREAKER_THRESHOLD = 5\\nNON_RETRYABLE_CODES = {\\\"AUTH_DENIED\\\", \\\"INVALID_ARGUMENT\\\"}\\n\\n\\ndef should_retry(error_code, retryable, attempt):\\n \\\"\\\"\\\"Return whether another tool call should be attempted.\\\"\\\"\\\"\\n if not retryable or error_code in NON_RETRYABLE_CODES:\\n return False\\n return attempt < MAX_RETRIES\\n\\n\\ndef should_open_circuit(consecutive_failures, *, error_code=\\\"\\\", retryable=True):\\n \\\"\\\"\\\"Open immediately for permanent failures or after repeated temporary failures.\\\"\\\"\\\"\\n if not retryable or error_code in NON_RETRYABLE_CODES:\\n return consecutive_failures >= 1\\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\\n\"}",
"role": "assistant",
"reasoning_details": [
{
"type": "reasoning.encrypted",
"data": "gAAAAABqbsoVfzLT_630yuZzHKyd8nnXw_G6aqojKdjAmzVDbLd4Xn-Q3mIKe2go0qV-MzGTWKLAI49dpBvB7Rh_5pD2V7g9Lo20b0upq1QQnrlwSgTTkNNIU42VP09tK7BlainxGC3VjVQzoiDnzW1ycnev5uExeR6RMeYeK4OycCtSm432sFdjGobCDAkD63hztrlRR9LbpO5F_N-r9FE6XK9__6rPfpVxwssCnzw6UrJSIrAnY78EnxrZ5Brr_x7TS1DRWkKycysVRmdyH7lialKB5-VQqHVYnzGIDRmInx2z8Eb33a0oxFKoZ60wm4Dt51u3B4ZigQuSnm8qaL0C3e6Sx1CcMjqgkvAveoDqvPiRe2Jn99gGD1Zb2a4QuzpWFJoPBw0wP-5Ftr_9oeiXXIrC-iV6WcqW60nWo3T8QoE8AyL5xPhgkYOXTsWxB6eE8qhUcdfUkPI6Jb5WzJJV6aBYPE8VtUOt0a-kpKSs7VoHqBXZLKb6XBUJuRA1kNfD9-878znM_o0HLa-zeXAh0o5sRU3tm8JUFM2wTPC4vIW9j6MBneAnSAgPP5-ecZ8zNcfJwX8tGq6pv8m7t8fNw6hBFhweTz0H6nfP40ew75rl20hlSwzZpvhxNrqQ7sDEgHSS_pSeMEyy_3Q_3gJjRII-63s5oFCV6KA4J-3y6rTq8B8nBWCrmC6t6Wr154B8duIsKEj5XkwqJwJqVJ0ve0Zn1ajrnoT5U9koJ4gr8QQHjGGzeB8iWKYlXDj7U3DRnfFpDi2W9ITie15t9KGl4vgwLqGpC4W3Tw0ler9B1iI8RI4guTstB-P3kk1AL3Wy23w5NOZpvGtAFHmq0tTT2p7pevH_1vreX8VMrXpnR4TtRXS_ozgbJhg7SzikZYlL43F_6mpmJxxg5FvTaj_J2QEV-sXNu0HkYIk7SarA5ULcDflz05fperzFaKpc6DdXtar9Mufjhn24mX1a8799OAZbgS9h3vaFa0z-7cBUTfplDVVydBNxteka07DevlG9fxTQCi9KjhOhqMH3oadsDbiufIp2YeGz3bocIBTIhPVVUoL9ywJW7kwVIfDFUV_hONXVKfhjWjH-Q0O3BCPn76nmUnyDlZrrggLqm5YDLvulyRZzspRVryr4IcbOSC4tK3n8s4-v6zNsnPtszq7sSNyxoTqryCQlrifvFcYOZQw4Cc0CHiKwojD7vQsjy1q4m3If6IfRXDbK4kOdkajkOSj-ir9kNRu1r04fb6eMbIRZYmbkfoUkoT17fJT5ruSinGmvKs8B4MS8896hpzIXLaxmd_4rdg0j4byhJjvQHiIjVDVdc3icZT6RAuwGuv2VlkoH6gD4UsJTQY7TTzDCs96-add1yczyk9Az2B74qXLQgstAy3ubGDhM-QjmEMhU6fULqriEbJZSk-u-HYPVJ3CtJSHXFnviF3ur6FRQr1bvk4s0lrksXPOPmtR3Gg26UiPQET_JwsvafY_ttLJ2wbudPzhGSijztaphFjmnFWkH53xLNRMACNPi_fXuTXwcoSwIc0M_pa2MVooxFAlDsiNYhlyKfgYY9aB77RAmqfHx1movlyjgWJlQm1vvcngw3VxYHoG_kGu4fFQn5Kd2hC5rbrd4a4v3lPCzQkAKGTDqqsjYyH_H0lg4RkVYo-n_iGNWRlUI5blONowfxTXn4WS5oP7QGajw0WFbPI6FOcv3ISK8CJYCC_fjrtJoOia2OC1rVRzAqr1EuxWH6H_W9gQl0dae0CZUC_XTC8kZGvcKEC7hBz-u3OdRi4iycAYOPxlzMffE",
"format": "openai-responses-v1",
"id": "rs_09bdf9a0a95f7f05016a6eca1367a8819ebed6d613bbe9886e",
"index": 0
}
]
},
"native_finish_reason": "completed"
}
],
"created": 1785645586,
"model": "openai/gpt-5.6-sol",
"object": "chat.completion",
"service_tier": "default",
"usage": {
"completion_tokens": 392,
"prompt_tokens": 839,
"total_tokens": 1231,
"completion_tokens_details": {
"audio_tokens": 0,
"reasoning_tokens": 128,
"image_tokens": 0
},
"prompt_tokens_details": {
"audio_tokens": 0,
"cached_tokens": 0,
"cache_write_tokens": 0,
"video_tokens": 0
},
"cost": 0.015955,
"is_byok": false,
"cost_details": {
"upstream_inference_cost": 0.015955,
"upstream_inference_prompt_cost": 0.004195,
"upstream_inference_completions_cost": 0.01176
}
},
"provider": "OpenAI"
},
"request_sha256": "80938ad7618b7a10cbf6a441221678a0e08a3acd88e03a9277b5b48c767b37b9",
"response_sha256": "0547761669dd89448a523da688652d900c055c104d208c20681a0055e19feeb3",
"elapsed_seconds": 4.693797,
"usage": {
"prompt_tokens": 839,
"completion_tokens": 392,
"total_tokens": 1231,
"provider_reported_cost_usd": 0.015955,
"cost_qualification": "provider-native usage.cost"
}
}
},
"decision": "release_to_canary",
"rejection_reason": null
},
"rejected_control": {
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,18 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rejected\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n \n \n def should_retry(error_code, retryable, attempt):\n- \"\"\"Return whether another tool call should be attempted.\"\"\"\n- return attempt < MAX_RETRIES\n+ \"\"\"Incorrect over-broad fix retained as a rejected candidate.\"\"\"\n+ return False\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"after": 1
},
"temporary_timeout_recovery_rate": {
"after": 0.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "824bbfb244a7",
"candidate_sha256": "824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,18 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rejected\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n \n \n def should_retry(error_code, retryable, attempt):\n- \"\"\"Return whether another tool call should be attempted.\"\"\"\n- return attempt < MAX_RETRIES\n+ \"\"\"Incorrect over-broad fix retained as a rejected candidate.\"\"\"\n+ return False\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 6,
"deleted_lines": 4,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"security_scan": true,
"sandbox_execution": true,
"public_api_compatible": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": false,
"old_task_regression": false,
"canary_ready": false,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [
"temporary_recovery",
"old_task_regression",
"canary_ready"
],
"canary_gate": {
"eligible": false,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "negative_control",
"api_calls": 0
},
"decision": "reject_candidate",
"rejection_reason": "failed gates: temporary_recovery, old_task_regression, canary_ready"
}
},
"raw_api_receipts": [
{
"backend": {
"provider": "openrouter",
"endpoint": "https://openrouter.ai/api/v1/chat/completions",
"credential_env": "OPENROUTER_API_KEY",
"model": "openai/gpt-5.6-sol",
"credential_value_recorded": false
},
"request": {
"model": "openai/gpt-5.6-sol",
"messages": [
{
"role": "user",
"content": "You are the Coding Agent in a controlled self-modification pipeline.\n\nModify only the supplied retry-policy module. Preserve both public function\nsignatures and retry behavior for temporary failures. Permanent failures\n(retryable=false or a listed permanent code) must not be retried and must open\nthe circuit on the first occurrence. Update VERSION to a candidate version.\nDo not import modules, access files, or alter validation/release logic.\n\nBefore the source, predict the intended impact. Return JSON only:\n{\"impact_prediction\": {\"non_retryable_calls\": {\"before\": \"up to 4\", \"after\": 1},\n\"temporary_timeout_recovery_rate\": {\"before\": 1.0, \"after\": 1.0}},\n\"source\": \"the complete Python module\"}\n\nFailure diagnosis:\n{\n \"change_required\": true,\n \"target\": \"stable/retry_policy.py\",\n \"target_component\": \"retry_and_circuit_breaker_control\",\n \"source_case_ids\": [\n \"run-payment-001\",\n \"run-payment-002\"\n ],\n \"source_trajectories\": [\n {\n \"id\": \"run-payment-001\",\n \"trajectory_sha256\": \"4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008\",\n \"evidence\": \"The same declined payment was submitted four times.\"\n },\n {\n \"id\": \"run-payment-002\",\n \"trajectory_sha256\": \"6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59\",\n \"evidence\": \"A second task repeated the identical non-retryable call three times.\"\n }\n ],\n \"patterns\": [\n {\n \"cluster_id\": \"charge_card:PAYMENT_DECLINED\",\n \"tool\": \"charge_card\",\n \"error_code\": \"PAYMENT_DECLINED\",\n \"source_case_ids\": [\n \"run-payment-001\",\n \"run-payment-002\"\n ],\n \"cross_trajectory_support\": 2,\n \"total_redundant_calls\": 5\n }\n ],\n \"reason\": \"The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.\",\n \"change_contract\": {\n \"expected_fix\": [\n \"non-retryable tool-call attempts fall to one\",\n \"the circuit opens on the first permanent failure\"\n ],\n \"potential_regressions\": [\n \"temporary timeouts stop retrying\",\n \"the five-failure circuit threshold changes for retryable errors\",\n \"public function signatures change\"\n ]\n }\n}\n\nPreviously rejected candidates (do not repeat their failure):\n[\n {\n \"candidate_sha256\": \"824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2\",\n \"failed_checks\": [\n \"temporary_recovery\",\n \"old_task_regression\",\n \"canary_ready\"\n ],\n \"rejection_reason\": \"failed gates: temporary_recovery, old_task_regression, canary_ready\",\n \"failure\": \"disabled temporary-timeout retries\"\n }\n]\n\nStable module:\n\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n\nVERSION = \"1.0.0\"\nMAX_RETRIES = 3\nCIRCUIT_BREAKER_THRESHOLD = 5\nNON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n\n\ndef should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n return attempt < MAX_RETRIES\n\n\ndef should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n \"\"\"Open after repeated failures.\"\"\"\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n\n"
}
],
"temperature": 0,
"seed": 8501,
"max_tokens": 1400,
"response_format": {
"type": "json_object"
}
},
"response": {
"id": "gen-1785645586-58eflec0vxlXmqNTlbkd",
"choices": [
{
"finish_reason": "stop",
"index": 0,
"message": {
"content": "{\"impact_prediction\":{\"non_retryable_calls\":{\"before\":\"up to 4\",\"after\":1},\"temporary_timeout_recovery_rate\":{\"before\":1.0,\"after\":1.0}},\"source\":\"\\\"\\\"\\\"Candidate version 1.0.1-rc.1 with permanent-failure handling.\\\"\\\"\\\"\\n\\nVERSION = \\\"1.0.1-rc.1\\\"\\nMAX_RETRIES = 3\\nCIRCUIT_BREAKER_THRESHOLD = 5\\nNON_RETRYABLE_CODES = {\\\"AUTH_DENIED\\\", \\\"INVALID_ARGUMENT\\\"}\\n\\n\\ndef should_retry(error_code, retryable, attempt):\\n \\\"\\\"\\\"Return whether another tool call should be attempted.\\\"\\\"\\\"\\n if not retryable or error_code in NON_RETRYABLE_CODES:\\n return False\\n return attempt < MAX_RETRIES\\n\\n\\ndef should_open_circuit(consecutive_failures, *, error_code=\\\"\\\", retryable=True):\\n \\\"\\\"\\\"Open immediately for permanent failures or after repeated temporary failures.\\\"\\\"\\\"\\n if not retryable or error_code in NON_RETRYABLE_CODES:\\n return consecutive_failures >= 1\\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\\n\"}",
"role": "assistant",
"reasoning_details": [
{
"type": "reasoning.encrypted",
"data": "gAAAAABqbsoVfzLT_630yuZzHKyd8nnXw_G6aqojKdjAmzVDbLd4Xn-Q3mIKe2go0qV-MzGTWKLAI49dpBvB7Rh_5pD2V7g9Lo20b0upq1QQnrlwSgTTkNNIU42VP09tK7BlainxGC3VjVQzoiDnzW1ycnev5uExeR6RMeYeK4OycCtSm432sFdjGobCDAkD63hztrlRR9LbpO5F_N-r9FE6XK9__6rPfpVxwssCnzw6UrJSIrAnY78EnxrZ5Brr_x7TS1DRWkKycysVRmdyH7lialKB5-VQqHVYnzGIDRmInx2z8Eb33a0oxFKoZ60wm4Dt51u3B4ZigQuSnm8qaL0C3e6Sx1CcMjqgkvAveoDqvPiRe2Jn99gGD1Zb2a4QuzpWFJoPBw0wP-5Ftr_9oeiXXIrC-iV6WcqW60nWo3T8QoE8AyL5xPhgkYOXTsWxB6eE8qhUcdfUkPI6Jb5WzJJV6aBYPE8VtUOt0a-kpKSs7VoHqBXZLKb6XBUJuRA1kNfD9-878znM_o0HLa-zeXAh0o5sRU3tm8JUFM2wTPC4vIW9j6MBneAnSAgPP5-ecZ8zNcfJwX8tGq6pv8m7t8fNw6hBFhweTz0H6nfP40ew75rl20hlSwzZpvhxNrqQ7sDEgHSS_pSeMEyy_3Q_3gJjRII-63s5oFCV6KA4J-3y6rTq8B8nBWCrmC6t6Wr154B8duIsKEj5XkwqJwJqVJ0ve0Zn1ajrnoT5U9koJ4gr8QQHjGGzeB8iWKYlXDj7U3DRnfFpDi2W9ITie15t9KGl4vgwLqGpC4W3Tw0ler9B1iI8RI4guTstB-P3kk1AL3Wy23w5NOZpvGtAFHmq0tTT2p7pevH_1vreX8VMrXpnR4TtRXS_ozgbJhg7SzikZYlL43F_6mpmJxxg5FvTaj_J2QEV-sXNu0HkYIk7SarA5ULcDflz05fperzFaKpc6DdXtar9Mufjhn24mX1a8799OAZbgS9h3vaFa0z-7cBUTfplDVVydBNxteka07DevlG9fxTQCi9KjhOhqMH3oadsDbiufIp2YeGz3bocIBTIhPVVUoL9ywJW7kwVIfDFUV_hONXVKfhjWjH-Q0O3BCPn76nmUnyDlZrrggLqm5YDLvulyRZzspRVryr4IcbOSC4tK3n8s4-v6zNsnPtszq7sSNyxoTqryCQlrifvFcYOZQw4Cc0CHiKwojD7vQsjy1q4m3If6IfRXDbK4kOdkajkOSj-ir9kNRu1r04fb6eMbIRZYmbkfoUkoT17fJT5ruSinGmvKs8B4MS8896hpzIXLaxmd_4rdg0j4byhJjvQHiIjVDVdc3icZT6RAuwGuv2VlkoH6gD4UsJTQY7TTzDCs96-add1yczyk9Az2B74qXLQgstAy3ubGDhM-QjmEMhU6fULqriEbJZSk-u-HYPVJ3CtJSHXFnviF3ur6FRQr1bvk4s0lrksXPOPmtR3Gg26UiPQET_JwsvafY_ttLJ2wbudPzhGSijztaphFjmnFWkH53xLNRMACNPi_fXuTXwcoSwIc0M_pa2MVooxFAlDsiNYhlyKfgYY9aB77RAmqfHx1movlyjgWJlQm1vvcngw3VxYHoG_kGu4fFQn5Kd2hC5rbrd4a4v3lPCzQkAKGTDqqsjYyH_H0lg4RkVYo-n_iGNWRlUI5blONowfxTXn4WS5oP7QGajw0WFbPI6FOcv3ISK8CJYCC_fjrtJoOia2OC1rVRzAqr1EuxWH6H_W9gQl0dae0CZUC_XTC8kZGvcKEC7hBz-u3OdRi4iycAYOPxlzMffE",
"format": "openai-responses-v1",
"id": "rs_09bdf9a0a95f7f05016a6eca1367a8819ebed6d613bbe9886e",
"index": 0
}
]
},
"native_finish_reason": "completed"
}
],
"created": 1785645586,
"model": "openai/gpt-5.6-sol",
"object": "chat.completion",
"service_tier": "default",
"usage": {
"completion_tokens": 392,
"prompt_tokens": 839,
"total_tokens": 1231,
"completion_tokens_details": {
"audio_tokens": 0,
"reasoning_tokens": 128,
"image_tokens": 0
},
"prompt_tokens_details": {
"audio_tokens": 0,
"cached_tokens": 0,
"cache_write_tokens": 0,
"video_tokens": 0
},
"cost": 0.015955,
"is_byok": false,
"cost_details": {
"upstream_inference_cost": 0.015955,
"upstream_inference_prompt_cost": 0.004195,
"upstream_inference_completions_cost": 0.01176
}
},
"provider": "OpenAI"
},
"request_sha256": "80938ad7618b7a10cbf6a441221678a0e08a3acd88e03a9277b5b48c767b37b9",
"response_sha256": "0547761669dd89448a523da688652d900c055c104d208c20681a0055e19feeb3",
"elapsed_seconds": 4.693797,
"usage": {
"prompt_tokens": 839,
"completion_tokens": 392,
"total_tokens": 1231,
"provider_reported_cost_usd": 0.015955,
"cost_qualification": "provider-native usage.cost"
}
}
],
"cost": {
"prompt_tokens": 839,
"completion_tokens": 392,
"total_tokens": 1231,
"provider_reported_cost_usd": 0.015955,
"cost_qualification": "provider-native usage.cost"
},
"candidate_acceptance_rate": 0.6666666666666666,
"gates": {
"cross_trajectory_support_met": true,
"root_cause_targets_control_code": true,
"real_coding_model_called": true,
"impact_prediction_precedes_validation": true,
"all_candidates_isolated": true,
"trusted_surfaces_unchanged": true,
"same_release_gate_for_both_generators": true,
"deterministic_candidate_release_to_canary": true,
"real_llm_candidate_release_to_canary": true,
"known_bad_candidate_rejected_and_retained": true,
"failure_replay_reduces_calls": true,
"temporary_recovery_preserved": true,
"old_task_regression_zero": true,
"canary_only_not_production": true,
"rollback_hash_pinned_to_stable": true,
"release_manifest_fields_complete": true
},
"accepted": true
}
@@ -0,0 +1 @@
761ed7dc4a5ad5b5d97c05a83f6b66c6c2003fc6ee20cc53a699a54c0c8eb020 evidence.json
@@ -0,0 +1,180 @@
{
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,6 +1,6 @@\n-\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n+\"\"\"Candidate version 1.0.1-rc.1 with permanent-failure handling.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rc.1\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n@@ -8,9 +8,13 @@\n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent failures or after repeated temporary failures.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"before": "up to 4",
"after": 1
},
"temporary_timeout_recovery_rate": {
"before": 1.0,
"after": 1.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "d6e79810003e",
"candidate_sha256": "d6e79810003e7d5f3e8d43ace0688e38033b08a4752bb0dfb9260d9bbe976b8f",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,6 +1,6 @@\n-\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n+\"\"\"Candidate version 1.0.1-rc.1 with permanent-failure handling.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rc.1\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n@@ -8,9 +8,13 @@\n \n def should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return False\n return attempt < MAX_RETRIES\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent failures or after repeated temporary failures.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 7,
"deleted_lines": 3,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"security_scan": true,
"sandbox_execution": true,
"public_api_compatible": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": true,
"old_task_regression": true,
"canary_ready": true,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [],
"canary_gate": {
"eligible": true,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "real_llm_coding_agent",
"model": "openai/gpt-5.6-sol",
"provider": "openrouter",
"seed": 8501,
"api_calls": 1,
"receipt": {
"backend": {
"provider": "openrouter",
"endpoint": "https://openrouter.ai/api/v1/chat/completions",
"credential_env": "OPENROUTER_API_KEY",
"model": "openai/gpt-5.6-sol",
"credential_value_recorded": false
},
"request": {
"model": "openai/gpt-5.6-sol",
"messages": [
{
"role": "user",
"content": "You are the Coding Agent in a controlled self-modification pipeline.\n\nModify only the supplied retry-policy module. Preserve both public function\nsignatures and retry behavior for temporary failures. Permanent failures\n(retryable=false or a listed permanent code) must not be retried and must open\nthe circuit on the first occurrence. Update VERSION to a candidate version.\nDo not import modules, access files, or alter validation/release logic.\n\nBefore the source, predict the intended impact. Return JSON only:\n{\"impact_prediction\": {\"non_retryable_calls\": {\"before\": \"up to 4\", \"after\": 1},\n\"temporary_timeout_recovery_rate\": {\"before\": 1.0, \"after\": 1.0}},\n\"source\": \"the complete Python module\"}\n\nFailure diagnosis:\n{\n \"change_required\": true,\n \"target\": \"stable/retry_policy.py\",\n \"target_component\": \"retry_and_circuit_breaker_control\",\n \"source_case_ids\": [\n \"run-payment-001\",\n \"run-payment-002\"\n ],\n \"source_trajectories\": [\n {\n \"id\": \"run-payment-001\",\n \"trajectory_sha256\": \"4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008\",\n \"evidence\": \"The same declined payment was submitted four times.\"\n },\n {\n \"id\": \"run-payment-002\",\n \"trajectory_sha256\": \"6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59\",\n \"evidence\": \"A second task repeated the identical non-retryable call three times.\"\n }\n ],\n \"patterns\": [\n {\n \"cluster_id\": \"charge_card:PAYMENT_DECLINED\",\n \"tool\": \"charge_card\",\n \"error_code\": \"PAYMENT_DECLINED\",\n \"source_case_ids\": [\n \"run-payment-001\",\n \"run-payment-002\"\n ],\n \"cross_trajectory_support\": 2,\n \"total_redundant_calls\": 5\n }\n ],\n \"reason\": \"The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.\",\n \"change_contract\": {\n \"expected_fix\": [\n \"non-retryable tool-call attempts fall to one\",\n \"the circuit opens on the first permanent failure\"\n ],\n \"potential_regressions\": [\n \"temporary timeouts stop retrying\",\n \"the five-failure circuit threshold changes for retryable errors\",\n \"public function signatures change\"\n ]\n }\n}\n\nPreviously rejected candidates (do not repeat their failure):\n[\n {\n \"candidate_sha256\": \"824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2\",\n \"failed_checks\": [\n \"temporary_recovery\",\n \"old_task_regression\",\n \"canary_ready\"\n ],\n \"rejection_reason\": \"failed gates: temporary_recovery, old_task_regression, canary_ready\",\n \"failure\": \"disabled temporary-timeout retries\"\n }\n]\n\nStable module:\n\"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n\nVERSION = \"1.0.0\"\nMAX_RETRIES = 3\nCIRCUIT_BREAKER_THRESHOLD = 5\nNON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n\n\ndef should_retry(error_code, retryable, attempt):\n \"\"\"Return whether another tool call should be attempted.\"\"\"\n return attempt < MAX_RETRIES\n\n\ndef should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n \"\"\"Open after repeated failures.\"\"\"\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n\n"
}
],
"temperature": 0,
"seed": 8501,
"max_tokens": 1400,
"response_format": {
"type": "json_object"
}
},
"response": {
"id": "gen-1785645586-58eflec0vxlXmqNTlbkd",
"choices": [
{
"finish_reason": "stop",
"index": 0,
"message": {
"content": "{\"impact_prediction\":{\"non_retryable_calls\":{\"before\":\"up to 4\",\"after\":1},\"temporary_timeout_recovery_rate\":{\"before\":1.0,\"after\":1.0}},\"source\":\"\\\"\\\"\\\"Candidate version 1.0.1-rc.1 with permanent-failure handling.\\\"\\\"\\\"\\n\\nVERSION = \\\"1.0.1-rc.1\\\"\\nMAX_RETRIES = 3\\nCIRCUIT_BREAKER_THRESHOLD = 5\\nNON_RETRYABLE_CODES = {\\\"AUTH_DENIED\\\", \\\"INVALID_ARGUMENT\\\"}\\n\\n\\ndef should_retry(error_code, retryable, attempt):\\n \\\"\\\"\\\"Return whether another tool call should be attempted.\\\"\\\"\\\"\\n if not retryable or error_code in NON_RETRYABLE_CODES:\\n return False\\n return attempt < MAX_RETRIES\\n\\n\\ndef should_open_circuit(consecutive_failures, *, error_code=\\\"\\\", retryable=True):\\n \\\"\\\"\\\"Open immediately for permanent failures or after repeated temporary failures.\\\"\\\"\\\"\\n if not retryable or error_code in NON_RETRYABLE_CODES:\\n return consecutive_failures >= 1\\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\\n\"}",
"role": "assistant",
"reasoning_details": [
{
"type": "reasoning.encrypted",
"data": "gAAAAABqbsoVfzLT_630yuZzHKyd8nnXw_G6aqojKdjAmzVDbLd4Xn-Q3mIKe2go0qV-MzGTWKLAI49dpBvB7Rh_5pD2V7g9Lo20b0upq1QQnrlwSgTTkNNIU42VP09tK7BlainxGC3VjVQzoiDnzW1ycnev5uExeR6RMeYeK4OycCtSm432sFdjGobCDAkD63hztrlRR9LbpO5F_N-r9FE6XK9__6rPfpVxwssCnzw6UrJSIrAnY78EnxrZ5Brr_x7TS1DRWkKycysVRmdyH7lialKB5-VQqHVYnzGIDRmInx2z8Eb33a0oxFKoZ60wm4Dt51u3B4ZigQuSnm8qaL0C3e6Sx1CcMjqgkvAveoDqvPiRe2Jn99gGD1Zb2a4QuzpWFJoPBw0wP-5Ftr_9oeiXXIrC-iV6WcqW60nWo3T8QoE8AyL5xPhgkYOXTsWxB6eE8qhUcdfUkPI6Jb5WzJJV6aBYPE8VtUOt0a-kpKSs7VoHqBXZLKb6XBUJuRA1kNfD9-878znM_o0HLa-zeXAh0o5sRU3tm8JUFM2wTPC4vIW9j6MBneAnSAgPP5-ecZ8zNcfJwX8tGq6pv8m7t8fNw6hBFhweTz0H6nfP40ew75rl20hlSwzZpvhxNrqQ7sDEgHSS_pSeMEyy_3Q_3gJjRII-63s5oFCV6KA4J-3y6rTq8B8nBWCrmC6t6Wr154B8duIsKEj5XkwqJwJqVJ0ve0Zn1ajrnoT5U9koJ4gr8QQHjGGzeB8iWKYlXDj7U3DRnfFpDi2W9ITie15t9KGl4vgwLqGpC4W3Tw0ler9B1iI8RI4guTstB-P3kk1AL3Wy23w5NOZpvGtAFHmq0tTT2p7pevH_1vreX8VMrXpnR4TtRXS_ozgbJhg7SzikZYlL43F_6mpmJxxg5FvTaj_J2QEV-sXNu0HkYIk7SarA5ULcDflz05fperzFaKpc6DdXtar9Mufjhn24mX1a8799OAZbgS9h3vaFa0z-7cBUTfplDVVydBNxteka07DevlG9fxTQCi9KjhOhqMH3oadsDbiufIp2YeGz3bocIBTIhPVVUoL9ywJW7kwVIfDFUV_hONXVKfhjWjH-Q0O3BCPn76nmUnyDlZrrggLqm5YDLvulyRZzspRVryr4IcbOSC4tK3n8s4-v6zNsnPtszq7sSNyxoTqryCQlrifvFcYOZQw4Cc0CHiKwojD7vQsjy1q4m3If6IfRXDbK4kOdkajkOSj-ir9kNRu1r04fb6eMbIRZYmbkfoUkoT17fJT5ruSinGmvKs8B4MS8896hpzIXLaxmd_4rdg0j4byhJjvQHiIjVDVdc3icZT6RAuwGuv2VlkoH6gD4UsJTQY7TTzDCs96-add1yczyk9Az2B74qXLQgstAy3ubGDhM-QjmEMhU6fULqriEbJZSk-u-HYPVJ3CtJSHXFnviF3ur6FRQr1bvk4s0lrksXPOPmtR3Gg26UiPQET_JwsvafY_ttLJ2wbudPzhGSijztaphFjmnFWkH53xLNRMACNPi_fXuTXwcoSwIc0M_pa2MVooxFAlDsiNYhlyKfgYY9aB77RAmqfHx1movlyjgWJlQm1vvcngw3VxYHoG_kGu4fFQn5Kd2hC5rbrd4a4v3lPCzQkAKGTDqqsjYyH_H0lg4RkVYo-n_iGNWRlUI5blONowfxTXn4WS5oP7QGajw0WFbPI6FOcv3ISK8CJYCC_fjrtJoOia2OC1rVRzAqr1EuxWH6H_W9gQl0dae0CZUC_XTC8kZGvcKEC7hBz-u3OdRi4iycAYOPxlzMffE",
"format": "openai-responses-v1",
"id": "rs_09bdf9a0a95f7f05016a6eca1367a8819ebed6d613bbe9886e",
"index": 0
}
]
},
"native_finish_reason": "completed"
}
],
"created": 1785645586,
"model": "openai/gpt-5.6-sol",
"object": "chat.completion",
"service_tier": "default",
"usage": {
"completion_tokens": 392,
"prompt_tokens": 839,
"total_tokens": 1231,
"completion_tokens_details": {
"audio_tokens": 0,
"reasoning_tokens": 128,
"image_tokens": 0
},
"prompt_tokens_details": {
"audio_tokens": 0,
"cached_tokens": 0,
"cache_write_tokens": 0,
"video_tokens": 0
},
"cost": 0.015955,
"is_byok": false,
"cost_details": {
"upstream_inference_cost": 0.015955,
"upstream_inference_prompt_cost": 0.004195,
"upstream_inference_completions_cost": 0.01176
}
},
"provider": "OpenAI"
},
"request_sha256": "80938ad7618b7a10cbf6a441221678a0e08a3acd88e03a9277b5b48c767b37b9",
"response_sha256": "0547761669dd89448a523da688652d900c055c104d208c20681a0055e19feeb3",
"elapsed_seconds": 4.693797,
"usage": {
"prompt_tokens": 839,
"completion_tokens": 392,
"total_tokens": 1231,
"provider_reported_cost_usd": 0.015955,
"cost_qualification": "provider-native usage.cost"
}
}
},
"decision": "release_to_canary",
"rejection_reason": null
}
@@ -0,0 +1,94 @@
{
"artifact_type": "agent_control_code_patch",
"failure_cluster": [
{
"cluster_id": "charge_card:PAYMENT_DECLINED",
"tool": "charge_card",
"error_code": "PAYMENT_DECLINED",
"source_case_ids": [
"run-payment-001",
"run-payment-002"
],
"cross_trajectory_support": 2,
"total_redundant_calls": 5
}
],
"source_trajectories": [
{
"id": "run-payment-001",
"trajectory_sha256": "4a0b38498b006bf988279b0ff7984f04245db21ee0668986a49f3ca3f4969008",
"evidence": "The same declined payment was submitted four times."
},
{
"id": "run-payment-002",
"trajectory_sha256": "6407eb8005fb39702005d553963405329607b34e67acbb18901c79060dbe1e59",
"evidence": "A second task repeated the identical non-retryable call three times."
}
],
"inferred_root_cause": "The deterministic control policy ignores retryable=false and does not open the circuit for permanent errors. The root cause belongs in retry/circuit-breaker code, not a prompt.",
"target_component": "retry_and_circuit_breaker_control",
"target_file": "stable/retry_policy.py",
"code_diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,18 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rejected\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n \n \n def should_retry(error_code, retryable, attempt):\n- \"\"\"Return whether another tool call should be attempted.\"\"\"\n- return attempt < MAX_RETRIES\n+ \"\"\"Incorrect over-broad fix retained as a rejected candidate.\"\"\"\n+ return False\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"impact_prediction": {
"non_retryable_calls": {
"after": 1
},
"temporary_timeout_recovery_rate": {
"after": 0.0
}
},
"expected_fix": [
"non-retryable tool-call attempts fall to one",
"the circuit opens on the first permanent failure"
],
"potential_regressions": [
"temporary timeouts stop retrying",
"the five-failure circuit threshold changes for retryable errors",
"public function signatures change"
],
"stable_version": "fcd37db6ebb1",
"stable_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"candidate_version": "824bbfb244a7",
"candidate_sha256": "824bbfb244a7b17ac835706be588542a63ad03e0d737d6c9d5da719c969652d2",
"rollback_version": "fcd37db6ebb1",
"rollback_sha256": "fcd37db6ebb19ed2e2492f086365a9f8addfcc4410242151185a1481d130041a",
"diff": "--- stable/retry_policy.py\n+++ candidate/retry_policy.py\n@@ -1,16 +1,18 @@\n \"\"\"Stable version 1.0.0. It intentionally contains the reproduced bug.\"\"\"\n \n-VERSION = \"1.0.0\"\n+VERSION = \"1.0.1-rejected\"\n MAX_RETRIES = 3\n CIRCUIT_BREAKER_THRESHOLD = 5\n NON_RETRYABLE_CODES = {\"AUTH_DENIED\", \"INVALID_ARGUMENT\"}\n \n \n def should_retry(error_code, retryable, attempt):\n- \"\"\"Return whether another tool call should be attempted.\"\"\"\n- return attempt < MAX_RETRIES\n+ \"\"\"Incorrect over-broad fix retained as a rejected candidate.\"\"\"\n+ return False\n \n \n def should_open_circuit(consecutive_failures, *, error_code=\"\", retryable=True):\n- \"\"\"Open after repeated failures.\"\"\"\n+ \"\"\"Open immediately for permanent errors; otherwise use the threshold.\"\"\"\n+ if not retryable or error_code in NON_RETRYABLE_CODES:\n+ return consecutive_failures >= 1\n return consecutive_failures >= CIRCUIT_BREAKER_THRESHOLD\n",
"patch_size": {
"added_lines": 6,
"deleted_lines": 4,
"changed_lines": 10
},
"checks": {
"static_compile": true,
"security_scan": true,
"sandbox_execution": true,
"public_api_compatible": true,
"failure_replay": true,
"nonretryable_circuit": true,
"temporary_recovery": false,
"old_task_regression": false,
"canary_ready": false,
"rollback_ready": true,
"protected_surfaces_unchanged": true
},
"failed_checks": [
"temporary_recovery",
"old_task_regression",
"canary_ready"
],
"canary_gate": {
"eligible": false,
"scope": "shadow traffic only; stable remains unchanged",
"rollback_trigger": "any non-retryable repeat or temporary-recovery regression"
},
"rollback_gate": {
"artifact_hash_matches_stable": true,
"rollback_version": "fcd37db6ebb1"
},
"provenance": {
"generator": "negative_control",
"api_calls": 0
},
"decision": "reject_candidate",
"rejection_reason": "failed gates: temporary_recovery, old_task_regression, canary_ready"
}