146 lines
9.5 KiB
Python
146 lines
9.5 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:
|
|
packet = original_packet(self, task_id, role, sha)
|
|
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)
|
|
|
|
from runner.cli import main
|
|
main()
|