153 lines
8.6 KiB
Python
153 lines
8.6 KiB
Python
"""Complete P18 changed-function review context; no acceptance or limit changes."""
|
|
import hashlib
|
|
import json
|
|
import re
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
TASK = 'P18-01-CODE'
|
|
BASE = 'd2a1f80a613e7c77b02b941026bc49c2d85db863'
|
|
SPEC = '04e9ae701b6ee1e399542564add695ca7fce54499e52dd2e907b1dbdc23a366d'
|
|
RUNTIME = 'autoload/simulation_runtime.gd'
|
|
MARKERS = 'docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json'
|
|
FOCUS = [
|
|
'tests/s4/test_original_relationship_model.gd',
|
|
'tests/s4/test_original_relationship_runtime.gd',
|
|
'tests/s4/test_relationship_event_service.gd',
|
|
'tests/s4/test_runtime_relationship_events.gd',
|
|
'tests/s6/test_runtime_snapshot_serialization.gd',
|
|
'tests/s6/test_runtime_save_lifecycle.gd',
|
|
'tests/ui/test_staff_management.gd',
|
|
]
|
|
|
|
|
|
def sha(text):
|
|
return hashlib.sha256(text.encode()).hexdigest()
|
|
|
|
|
|
def source(repo, revision, path):
|
|
return subprocess.check_output(['git', 'show', revision + ':' + path], cwd=repo).decode('utf-8')
|
|
|
|
|
|
def method_ranges(text):
|
|
lines = text.splitlines(keepends=True)
|
|
starts = [(i, re.match(r'^(?:static )?func\s+(\w+)\(', line).group(1))
|
|
for i, line in enumerate(lines)
|
|
if re.match(r'^(?:static )?func\s+(\w+)\(', line)]
|
|
assert starts, 'Runtime method boundaries missing'
|
|
methods = {name: (start, starts[i + 1][0] if i + 1 < len(starts) else len(lines))
|
|
for i, (start, name) in enumerate(starts)}
|
|
assert len(methods) == len(starts), 'duplicate Runtime methods'
|
|
return lines, starts[0][0], methods
|
|
|
|
|
|
def runtime_context(git, repo, revision):
|
|
full = source(repo, revision, RUNTIME)
|
|
old = source(repo, BASE, RUNTIME)
|
|
lines, header_end, methods = method_ranges(full)
|
|
old_lines, _, old_methods = method_ranges(old)
|
|
delta = git(repo, 'diff', '--no-ext-diff', '--unified=0', BASE, revision, '--', RUNTIME)
|
|
selected = set()
|
|
hunks = []
|
|
for match in re.finditer(r'(?m)^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@', delta):
|
|
old_start, old_count, start, count = match.groups()
|
|
old_start, old_count = int(old_start), int(old_count or '1')
|
|
start, count = int(start), int(count or '1')
|
|
touched = list(range(max(start - 1, 0), start - 1 + count)) if count else [max(start - 1, 0)]
|
|
names = {name for name, (lo, hi) in methods.items() if any(lo <= n < hi for n in touched)}
|
|
for name, (lo, hi) in old_methods.items():
|
|
if any(lo <= n < hi for n in range(max(old_start - 1, 0), old_start - 1 + old_count)) and name in methods:
|
|
names.add(name)
|
|
selected.update(names)
|
|
hunks.append(dict(new_start=start, new_count=count, methods=sorted(names)))
|
|
selected.update(name for name in methods if name in {
|
|
'create_snapshot', 'restore_snapshot', '_initialize_s4_relationship_events',
|
|
'_configure_relationship_event_boundaries', '_connect_relationship_signals',
|
|
'_execute_create_relationship', '_execute_change_relationship', '_execute_attack_relationship_shield',
|
|
'_on_relationship_registered', '_on_relationship_value_changed', '_on_relationship_shield_changed',
|
|
'_on_relationship_route_lock_changed', '_initialize_mvp_content_catalog',
|
|
'_register_or_validate_legacy_catalog_definitions', '_validate_catalog_staff_crosslinks',
|
|
})
|
|
covered = set(range(header_end))
|
|
pieces = [''.join(lines[:header_end])]
|
|
for name in sorted(selected, key=lambda n: methods[n][0]):
|
|
lo, hi = methods[name]
|
|
covered.update(range(lo, hi))
|
|
pieces.append('\n# COMPLETE METHOD %s; original lines %d-%d\n' % (name, lo + 1, hi))
|
|
pieces.append(''.join(lines[lo:hi]))
|
|
for hunk in hunks:
|
|
assert all(n in covered for n in range(hunk['new_start'] - 1, hunk['new_start'] - 1 + hunk['new_count'])), 'changed Runtime lines omitted'
|
|
omitted_changed_methods = [name for name in old_methods if name not in methods and name in delta]
|
|
assert not omitted_changed_methods, 'removed methods need explicit old full context'
|
|
context = ''.join(pieces)
|
|
proof = dict(path=RUNTIME, revision=revision, complete_source_sha256=sha(full),
|
|
base_source_sha256=sha(old), context_sha256=sha(context),
|
|
selected_complete_methods=sorted(selected), hunks=hunks,
|
|
all_new_changed_lines_included=True, complete_diff_in_packet=True,
|
|
omitted_scope='Unchanged Runtime methods outside the above complete methods. Full immutable source remains in Git at the supplied revision; request further context if needed.',
|
|
entire_Runtime_review_claimed=False)
|
|
return context, proof
|
|
|
|
|
|
def unchanged_dependency_context(repo, revision):
|
|
selected = {
|
|
'scripts/relationship/relationship_state.gd': None,
|
|
'scripts/staff/staff_service.gd': ['remove_staff', 'retire_staff'],
|
|
'scripts/guest/guest_service.gd': ['despawn_guest'],
|
|
}
|
|
result = {}
|
|
for path, names in selected.items():
|
|
full = source(repo, revision, path)
|
|
assert full == source(repo, BASE, path), 'relationship dependency changed; review complete delta first'
|
|
entry = {'path': path, 'revision': revision, 'whole_source_sha256': sha(full),
|
|
'unchanged_from_base': True, 'whole_file_included': names is None}
|
|
if names is None:
|
|
entry['source'] = full
|
|
else:
|
|
lines, _, methods = method_ranges(full)
|
|
assert all(name in methods for name in names), 'required dependency method absent'
|
|
entry['complete_methods'] = {name: ''.join(lines[methods[name][0]:methods[name][1]]) for name in names}
|
|
entry['omitted_scope'] = 'Other unchanged methods; not entire service review'
|
|
result[path] = entry
|
|
return result
|
|
|
|
|
|
def packet(runner, task_id, revision, original_packet):
|
|
from runner.core import git, allowed, secret_path, read_json, CONTROL, require
|
|
task = runner.task(task_id)
|
|
contract = json.loads(task['contract'])
|
|
require(task_id == TASK and runner.config['project'] == 'the-tree-p18-01-model'
|
|
and contract['base_commit'] == BASE and contract['spec_sha256'] == SPEC,
|
|
'P18 context exact contract guard')
|
|
ordinary = original_packet(runner, task_id, 'implementer', revision)
|
|
body = json.loads(ordinary.split('\nDATA:\n', 1)[1])
|
|
body['diff'] = git(runner.repo, 'diff', '--no-ext-diff', BASE, revision)
|
|
names = git(runner.repo, 'ls-tree', '-r', '--name-only', revision).splitlines()
|
|
body['sources'] = {p: source(runner.repo, revision, p)
|
|
for p in names if allowed(p, contract['allowed_paths']) and not secret_path(p)}
|
|
context, proof = runtime_context(git, runner.repo, revision)
|
|
body['sources'][RUNTIME] = context
|
|
marker = json.loads(body['sources'][MARKERS])
|
|
old_marker = json.loads(source(runner.repo, BASE, MARKERS))
|
|
other_old = [x for x in old_marker['rows'] if x['test'] not in FOCUS]
|
|
other_new = [x for x in marker['rows'] if x['test'] not in FOCUS]
|
|
require(other_old == other_new, 'unrelated marker records changed')
|
|
reduced = dict(marker, rows=[x for x in marker['rows'] if x['test'] in FOCUS])
|
|
require(len(reduced['rows']) == len(FOCUS), 'all seven complete marker records required')
|
|
body['review_context_provenance'] = {
|
|
'runtime': proof,
|
|
'markers': dict(path=MARKERS, complete_source_sha256=sha(body['sources'][MARKERS]),
|
|
base_source_sha256=sha(source(runner.repo, BASE, MARKERS)),
|
|
complete_selected_records=FOCUS, omitted_records_proven_unchanged=True),
|
|
'rules': 'Review every fixed backend criterion and all changes using full diff, complete selected methods/sources and actual evidence. Context limits do not waive criteria; request more context or reject if evidence is insufficient. Whole P18-01 completion is not claimed.'}
|
|
body['sources'][MARKERS] = json.dumps(reduced, ensure_ascii=False, indent=2)
|
|
body['immutable_identity_catalog'] = {p: source(runner.repo, revision, p)
|
|
for p in ['data/characters/mvp_unique_characters.json']}
|
|
body['immutable_relationship_dependencies'] = unchanged_dependency_context(runner.repo, revision)
|
|
body['tests'] = [read_json(row[0]) for row in runner.db.execute(
|
|
"SELECT artifact FROM evidence WHERE task_id=? AND kind='validation' AND commit_sha=? AND passed=1",
|
|
(task_id, revision))]
|
|
body['validation_sources'] = {'tools/run_p18_relationship_tests.py': body['sources']['tools/run_p18_relationship_tests.py']}
|
|
require(len(json.dumps(body).encode()) < 500000, 'unchanged review packet size guard')
|
|
return (CONTROL / 'prompts/reviewer.txt').read_text() + '\nDATA:\n' + json.dumps(body, ensure_ascii=False)
|