73 lines
5.1 KiB
Diff
73 lines
5.1 KiB
Diff
--- runner/core.before
|
|
+++ runner/core.after
|
|
@@ -669,7 +669,7 @@
|
|
"-c","approval_policy=\"never\"","-c",f"sqlite_home={json.dumps(str(runtime/'sqlite'))}",
|
|
"-c",f"log_dir={json.dumps(str(runtime/'logs'))}","--output-schema",str(schema_file),"--output-last-message",str(runtime/"answer.json"),"-"]
|
|
elif service == "claude":
|
|
- # Existing read-only worktree/runtime access: inspect source as needed.
|
|
+ # Read-only tools inspect this checkout; evidence is mirrored here before review.
|
|
args=[cli,"-p","--safe-mode","--restricted","--output-format","json","--tools","Read,Grep,Glob","--strict-mcp-config","--mcp-config",'{"mcpServers":{}}',
|
|
"--setting-sources","","--no-session-persistence","--permission-mode","plan","--json-schema",json.dumps(schema)]
|
|
budget=self.config["policy"].get("claude_max_budget_usd")
|
|
@@ -932,6 +932,48 @@
|
|
except (GateError,OSError) as exc:
|
|
self.state(task_id,"repair_pending",str(exc)); raise
|
|
|
|
+ def review_materials(self, task_id, worktree, revision):
|
|
+ """Put complete registered proof within restricted read-only review cwd."""
|
|
+ worktree = Path(worktree)
|
|
+ destination = worktree / ".review-material"
|
|
+ require(not destination.exists(), "fresh review material directory required")
|
|
+ destination.mkdir()
|
|
+ rows = []
|
|
+ def copy_file(source, target):
|
|
+ require(source.is_file() and not source.is_symlink(), "ordinary review proof")
|
|
+ target.parent.mkdir(parents=True, exist_ok=True)
|
|
+ before = hashlib.sha256(source.read_bytes()).hexdigest()
|
|
+ if sys.platform == "darwin":
|
|
+ subprocess.run(["/bin/cp", "-pc", str(source), str(target)], check=True)
|
|
+ else:
|
|
+ shutil.copy2(source, target)
|
|
+ require(hashlib.sha256(target.read_bytes()).hexdigest() == before, "whole review proof mismatch")
|
|
+ rows.append({"path": str(target.relative_to(worktree)), "original_path": str(source),
|
|
+ "bytes": target.stat().st_size, "sha256": before})
|
|
+ evidence = self.db.execute("SELECT kind,artifact FROM evidence WHERE task_id=? AND commit_sha=? AND passed=1",
|
|
+ (task_id, revision)).fetchall()
|
|
+ for number, row in enumerate(evidence):
|
|
+ artifact = Path(row["artifact"])
|
|
+ copy_file(artifact, destination / "receipts" / (str(number)+"-"+artifact.name))
|
|
+ if artifact.suffix == ".json":
|
|
+ value = read_json(artifact)
|
|
+ for check in value.get("checks", []):
|
|
+ folder = Path(check["artifact"])
|
|
+ for name in ("stdout.log", "stderr.log", "command.json"):
|
|
+ path = folder / name
|
|
+ if path.is_file():
|
|
+ copy_file(path, destination / "validation-runs" / folder.name / name)
|
|
+ build = Path(self.allocation(task_id)["build_dir"])
|
|
+ require(build.resolve().is_relative_to(self.runtime(task_id).resolve()), "registered review build scope")
|
|
+ if build.exists():
|
|
+ for source in sorted(build.rglob("*")):
|
|
+ if source.is_file() and not secret_path(str(source.relative_to(build))):
|
|
+ copy_file(source, destination / "build" / source.relative_to(build))
|
|
+ write_json(destination / "manifest.json",
|
|
+ {"candidate": revision, "task_id": task_id, "complete_registered_build_and_receipts": True,
|
|
+ "file_count_limit": None, "byte_limit": None, "files": rows})
|
|
+ return {"path": ".review-material/manifest.json", "file_count": len(rows), "byte_limit": None}
|
|
+
|
|
def review(self, task_id):
|
|
task=self.task(task_id); require(task["state"] in ("review_pending","blocked","reviewed","approval_pending"), "機械検証合格後、オーナー承認前にレビューできます")
|
|
require(task["submitted"], "提出コミットがありません")
|
|
@@ -944,7 +986,10 @@
|
|
schema["properties"]["task_id"]["enum"]=[task_id]
|
|
schema["properties"]["commit"]["enum"]=[task["submitted"]]
|
|
try:
|
|
- value,artifact=self.llm(task_id,"reviewer","claude",self.packet(task_id,"reviewer",task["submitted"]),wt,schema)
|
|
+ material = self.review_materials(task_id, wt, task["submitted"])
|
|
+ prompt = self.packet(task_id, "reviewer", task["submitted"])
|
|
+ prompt += "\\nRead complete registered validation receipts and build proof via " + json.dumps(material) + ". All files are available within this frozen checkout; inspect related sources and proof as needed."
|
|
+ value,artifact=self.llm(task_id,"reviewer","claude",prompt,wt,schema)
|
|
c=json.loads(task["contract"])
|
|
passed=value["status"]=="pass" and set(value["acceptance_ids"])==set(c["acceptance_ids"]) and not any(f["severity"] in ("critical","high","medium") for f in value["findings"])
|
|
self.evidence(task_id,"review",task["submitted"],artifact/"result.json",passed)
|