232 lines
15 KiB
Python
232 lines
15 KiB
Python
"""Owner coordinator routing, recorded direction and bounded review context."""
|
|
import os
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
control = Path(os.environ['OWNER_RUNNER_CONTROL']).resolve()
|
|
sys.path.insert(0, str(control))
|
|
from runner.core import Runner
|
|
|
|
ALLOWED_CODEX_MODELS = ('gpt-6.1-sol', 'gpt-6-astra')
|
|
original_llm = Runner.llm
|
|
|
|
def owner_model_llm(self, task_id, role, service, prompt, cwd, schema):
|
|
prompt = ("Latest owner review-material policy: fixed 500000-byte limits are removed. Do not omit required sources or evidence or perform compression/re-submission merely to satisfy the obsolete cap. Claude commander/reviewer can inspect their source checkout with Read,Grep,Glob; reviewer validation materials are mirrored into .review-material within the frozen checkout. Other services keep their own tool sets. Preserve scope, acceptance, exact-version evidence and independent review. Read relevant dependencies directly and report required context gaps.\n" + prompt)
|
|
if service == 'claude' and role == 'commander':
|
|
schema = json.loads(json.dumps(schema))
|
|
state = self.task(task_id)["state"]
|
|
actions = {"ready": ["run", "wait"], "repair_ready": ["run", "wait"],
|
|
"submitted": ["validate", "wait"], "repair_pending": ["request-repair", "wait"],
|
|
"blocked": ["request-repair", "wait"], "review_pending": ["review", "wait"],
|
|
"reviewed": ["prepare-integration", "wait"], "completed": ["wait"]}
|
|
if state in actions:
|
|
schema["properties"]["action"]["enum"] = actions[state]
|
|
prompt = "Actual Runner state: " + state + "; valid actions: " + ", ".join(actions[state]) + ". Return a valid action; do not repeat completed transitions.\n" + prompt
|
|
schema['required'] += ['codex_model', 'codex_model_reason']
|
|
schema['properties']['codex_model'] = {'type': 'string', 'enum': list(ALLOWED_CODEX_MODELS)}
|
|
schema['properties']['codex_model_reason'] = {'type': 'string', 'minLength': 1}
|
|
prompt = ('Owner-authorized model policy: You, Claude Opus 5.5, select the Codex worker model for this task. '
|
|
'Default gpt-6.1-sol. Select gpt-6-astra only when task difficulty warrants it; '
|
|
'state concrete reasons and consider quality, time and usage. Return codex_model and codex_model_reason '
|
|
'with the ordinary decision. Model choice does not authorize a run, repair, cap change or acceptance waiver.\n' + prompt)
|
|
if service == 'codex':
|
|
row = self.db.execute(
|
|
"SELECT data FROM events WHERE task_id=? AND event='commander_proposal' ORDER BY id DESC LIMIT 1",
|
|
(task_id,)).fetchone()
|
|
if not row:
|
|
raise ValueError('Codex model selection requires recorded Claude commander decision')
|
|
decision = json.loads(row[0])['decision']
|
|
chosen = decision.get('codex_model')
|
|
if decision.get('task_id') != task_id or decision.get('action') != 'run' or chosen not in ALLOWED_CODEX_MODELS or not str(decision.get('codex_model_reason', '')).strip():
|
|
raise ValueError('A recorded Claude run decision with explicit model and reason is required')
|
|
prompt = ("Recorded Claude commander run direction for this exact fixed task. Apply within the immutable spec, scope and acceptance; do not widen them.\n" + json.dumps(decision, ensure_ascii=False) + "\n" + prompt)
|
|
self._owner_codex_model = chosen
|
|
try:
|
|
return original_llm(self, task_id, role, service, prompt, cwd, schema)
|
|
finally:
|
|
del self._owner_codex_model
|
|
return original_llm(self, task_id, role, service, prompt, cwd, schema)
|
|
|
|
Runner.llm = owner_model_llm
|
|
original = Runner.provider_argv
|
|
|
|
def owner_model_argv(self, service, role, runtime, schema):
|
|
argv = original(self, service, role, runtime, schema)
|
|
if service in ('claude', 'codex'):
|
|
if '--model' in argv:
|
|
position = argv.index('--model')
|
|
del argv[position:position + 2]
|
|
argv += ['--model', 'claude-opus-5-5' if service == 'claude' else getattr(self, '_owner_codex_model', 'gpt-6.1-sol')]
|
|
return argv
|
|
|
|
Runner.provider_argv = owner_model_argv
|
|
original_packet = Runner.packet
|
|
|
|
def packet_with_actual_evidence(self, task_id, role, sha=None):
|
|
if role == "reviewer" and self.config["project"] == "the-tree-p18-01-model" and task_id == "P18-01-CODE":
|
|
import importlib.util
|
|
context_path = Path(__file__).with_name("p18_review_context.py")
|
|
spec = importlib.util.spec_from_file_location("p18_owner_review_context", context_path)
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
packet = module.packet(self, task_id, sha or self.task(task_id)["submitted"], original_packet)
|
|
else:
|
|
if role == 'reviewer' and self.config['project'] == 'the-tree-p08-03-code' and task_id == 'P08-03':
|
|
import runner.core as packet_core
|
|
import subprocess, hashlib
|
|
actual_git = packet_core.git
|
|
def binary_safe_git(repo, *argv, **kwargs):
|
|
if len(argv) == 2 and argv[0] == 'show' and ':' in argv[1]:
|
|
raw = subprocess.check_output(['git', '-C', str(repo), *argv])
|
|
try:
|
|
value = raw.decode('utf-8')
|
|
if '\x00' not in value:
|
|
return value.strip()
|
|
except UnicodeDecodeError:
|
|
pass
|
|
revision, path = argv[1].split(':', 1)
|
|
return json.dumps({'source_kind':'binary', 'path':path, 'bytes':len(raw),
|
|
'sha256':hashlib.sha256(raw).hexdigest(),
|
|
'git_blob':actual_git(repo, 'rev-parse', argv[1]),
|
|
'full_bytes_available':'unchanged committed file in frozen reviewer checkout; use Read for images or inspect raw file'}, ensure_ascii=False)
|
|
return actual_git(repo, *argv, **kwargs)
|
|
packet_core.git = binary_safe_git
|
|
try:
|
|
packet = original_packet(self, task_id, role, sha)
|
|
finally:
|
|
packet_core.git = actual_git
|
|
else:
|
|
packet = original_packet(self, task_id, role, sha)
|
|
if role == 'reviewer' and self.config['project'] == 'the-tree-p08-03-code' and task_id == 'P08-03':
|
|
import hashlib
|
|
frozen = Path(os.environ['OWNER_P08_PREPARED_REVIEW'])
|
|
prefix, data = packet.split('\nDATA:\n', 1)
|
|
body = json.loads(data)
|
|
context = frozen / '.owner-review-context'
|
|
context.mkdir(exist_ok=True)
|
|
manifest = {'candidate': sha, 'complete_sources': {}, 'validation_sources': {}}
|
|
for key in ('sources', 'validation_sources'):
|
|
for name in body[key]:
|
|
path = frozen / name
|
|
require(path.is_file() and not path.is_symlink(), 'committed reviewer source available')
|
|
raw = path.read_bytes()
|
|
manifest['complete_sources' if key == 'sources' else key][name] = {'path': name, 'bytes': len(raw), 'sha256': hashlib.sha256(raw).hexdigest()}
|
|
body[key] = {'complete_manifest': '.owner-review-context/source-manifest.json', 'section': 'complete_sources' if key == 'sources' else key, 'instruction': 'Read complete files directly from this frozen checkout; no source omitted or truncated.'}
|
|
(context / 'source-manifest.json').write_text(json.dumps(manifest, ensure_ascii=False, indent=2))
|
|
(context / 'complete-diff.txt').write_text(body['diff'])
|
|
body['diff'] = {'path': '.owner-review-context/complete-diff.txt', 'instruction': 'Read complete candidate diff; all original content preserved.'}
|
|
packet = prefix + '\nDATA:\n' + json.dumps(body, ensure_ascii=False)
|
|
extra = os.environ.get('OWNER_REVIEW_SUPPLEMENT')
|
|
if role == 'reviewer' and extra:
|
|
prefix, data = packet.split('\nDATA:\n', 1)
|
|
body = json.loads(data)
|
|
body['coordinator_actual_runtime_evidence'] = json.loads(Path(extra).read_text())
|
|
packet = prefix + '\nDATA:\n' + json.dumps(body, ensure_ascii=False)
|
|
return packet
|
|
|
|
Runner.packet = packet_with_actual_evidence
|
|
# Exact owner coordinator correction: allocation placeholder and infrastructure retry.
|
|
from runner.core import GateError, require, git, read_json
|
|
import uuid
|
|
_original_process = Runner.process
|
|
|
|
def p18_process(self, task_id, role, service, argv, cwd, *args, **kwargs):
|
|
if self.config["project"] == "the-tree-p18-01-model" and task_id == "P18-01-CODE" and role == "validation" and service is None:
|
|
c = json.loads(self.task(task_id)["contract"])
|
|
require(c["base_commit"] == "d2a1f80a613e7c77b02b941026bc49c2d85db863" and c["spec_sha256"] == "04e9ae701b6ee1e399542564add695ca7fce54499e52dd2e907b1dbdc23a366d", "exact P18 allocation guard")
|
|
expected = [sys.executable, "-B", "tools/run_p18_relationship_tests.py", "--output", "{build_dir}/p18-relationship-evidence"]
|
|
require(len(argv) == len(expected) and Path(argv[0]).resolve() == Path(expected[0]).resolve() and argv[1:] == expected[1:], "fixed registered P18 validation argv")
|
|
declared = list(argv)
|
|
output = Path(self.allocation(task_id)["build_dir"]) / "p18-relationship-evidence"
|
|
require(output.resolve().is_relative_to(self.runtime(task_id).resolve()), "allocated output containment")
|
|
argv = list(argv)
|
|
argv[-1] = str(output)
|
|
self.event(task_id, "validation_argument_resolution", {"declared_argv": declared, "resolved_argv": argv, "policy_changed": False})
|
|
return _original_process(self, task_id, role, service, argv, cwd, *args, **kwargs)
|
|
|
|
Runner.process = p18_process
|
|
_original_validate = Runner.validate
|
|
|
|
def p18_validate(self, task_id):
|
|
task = self.task(task_id)
|
|
if not (self.config["project"] == "the-tree-p18-01-model" and task_id == "P18-01-CODE" and task["state"] == "repair_pending" and task["submitted"] == "0084760ee05a97adfcbd783a71161491f3629918"):
|
|
return _original_validate(self, task_id)
|
|
previous = self.db.execute("SELECT artifact FROM evidence WHERE task_id=? AND kind='validation' AND commit_sha=? AND passed=0 ORDER BY id DESC LIMIT 1", (task_id, task["submitted"])).fetchone()
|
|
require(previous is not None, "actual failed validation required for infrastructure retry")
|
|
report = read_json(previous[0])
|
|
require(len(report["checks"]) == 1 and report["checks"][0]["id"] == "p18-model", "exact one validator")
|
|
artifact = Path(report["checks"][0]["artifact"])
|
|
command = read_json(artifact / "command.json")
|
|
require(command["argv"][-1] == "{build_dir}/p18-relationship-evidence" and (artifact / "stderr.log").read_text().strip() == "AssertionError: regular final receipt required", "known owner allocation error only")
|
|
require((Path(self.allocation(task_id)["build_dir"]) / "p18-relationship-evidence/receipt.json").is_file(), "actual precollected receipt required")
|
|
self.event(task_id, "owner_infrastructure_validation_retry", {"failed_report": previous[0], "submitted_commit": task["submitted"], "source_changes": False, "repair_counter_unchanged": task["repairs"], "reason": "Correct the owner-declared allocation placeholder and rerun the actual unchanged validator. No acceptance evidence is manufactured."})
|
|
self.state(task_id, "validating", "Owner allocation correction; same source and receipt; no new code repair")
|
|
wt = self.detached(task_id + "-validation-" + uuid.uuid4().hex[:8], task["submitted"])
|
|
try:
|
|
self.check_scope(task_id, wt, task["submitted"])
|
|
self.verify(task_id, wt, task["submitted"], "validation")
|
|
self.has_evidence(task_id, "validation", task["submitted"])
|
|
self.state(task_id, "review_pending")
|
|
except (GateError, OSError) as exc:
|
|
self.state(task_id, "repair_pending", str(exc))
|
|
raise
|
|
|
|
Runner.validate = p18_validate
|
|
|
|
adapter_path = os.environ.get("OWNER_P22_FINALIZATION_ADAPTER")
|
|
if adapter_path:
|
|
import importlib.util
|
|
approved_path = Path("/Users/korizatou114/Projects/とりにく工房ゲーム制作部/docs/plans/original-completion-2026-10-02/checkpoints/p22-02-slot-contract-r02/proposed_task_timeout_adapter.py")
|
|
if Path(adapter_path).resolve() != approved_path.resolve():
|
|
raise ValueError("Exact approved timeout adapter required")
|
|
adapter_spec = importlib.util.spec_from_file_location("owner_p22_finalization_timeout", approved_path)
|
|
adapter_module = importlib.util.module_from_spec(adapter_spec)
|
|
adapter_spec.loader.exec_module(adapter_module)
|
|
adapter_module.install(Runner)
|
|
|
|
p08_read_adapter = os.environ.get("OWNER_P08_R09_PROOF_READER_ADAPTER")
|
|
if p08_read_adapter:
|
|
import importlib.util
|
|
import runner.core as p08_core
|
|
adapter_spec = importlib.util.spec_from_file_location("owner_p08_r09_proof_read_scope", p08_read_adapter)
|
|
adapter_module = importlib.util.module_from_spec(adapter_spec)
|
|
adapter_spec.loader.exec_module(adapter_module)
|
|
adapter_module.install(p08_core)
|
|
|
|
|
|
# Reuse the fully prepared frozen review after the known text-decoding failure.
|
|
prepared_review = os.environ.get("OWNER_P08_PREPARED_REVIEW")
|
|
if prepared_review:
|
|
import hashlib
|
|
frozen = Path("/Users/korizatou114/Projects/TheTree-managed-worktrees/p08-03-code/P08-03-review-d137e8d8")
|
|
require(Path(prepared_review).resolve() == frozen.resolve(), "exact prepared P08 review")
|
|
pinned = "7dde98ccb749cbd1c1b82e066b59350e73191400"
|
|
detached_original, materials_original = Runner.detached, Runner.review_materials
|
|
def reused_detached(self, name, revision):
|
|
if self.config["project"] == "the-tree-p08-03-code" and name.startswith("P08-03-review-"):
|
|
require(revision == pinned and git(frozen, "rev-parse", "HEAD") == pinned, "frozen review candidate")
|
|
require(not git(frozen, "diff", "HEAD", "--name-only"), "unchanged tracked review sources")
|
|
return frozen
|
|
return detached_original(self, name, revision)
|
|
def reused_materials(self, task_id, worktree, revision):
|
|
if self.config["project"] != "the-tree-p08-03-code" or task_id != "P08-03":
|
|
return materials_original(self, task_id, worktree, revision)
|
|
require(Path(worktree) == frozen and revision == pinned, "exact P08 reuse binding")
|
|
manifest = read_json(frozen / ".review-material/manifest.json")
|
|
require(manifest["candidate"] == pinned and manifest["task_id"] == task_id and manifest["complete_nonsecret_registered_validation_material"], "complete frozen manifest")
|
|
for row in manifest["files"]:
|
|
path = frozen / row["path"]
|
|
require(path.resolve().is_relative_to(frozen.resolve()) and not path.is_symlink() and path.is_file(), "ordinary frozen proof")
|
|
digest = hashlib.sha256()
|
|
with path.open("rb") as stream:
|
|
for block in iter(lambda: stream.read(1048576), b""):
|
|
digest.update(block)
|
|
require(path.stat().st_size == row["bytes"] and digest.hexdigest() == row["sha256"], "frozen full proof bytes")
|
|
self.event(task_id, "owner_prepared_review_reuse", {"candidate": revision, "files_verified": len(manifest["files"]), "path": str(frozen), "reason": "Reuse complete frozen preparation after binary UTF-8 error; no source or acceptance changes"})
|
|
return {"path": ".review-material/manifest.json", "file_count": len(manifest["files"]), "byte_limit": None}
|
|
Runner.detached, Runner.review_materials = reused_detached, reused_materials
|
|
|
|
from runner.cli import main
|
|
main()
|