P05-02: 全費目と資金区分:表金・裏金、維持費未払い、仕入れ、人件費、元本、利息、税の帳簿への接続(原 P05-02 の完了の条件)
This commit is contained in:
@@ -414,6 +414,29 @@
|
||||
],
|
||||
"old_bounded_teardown": false,
|
||||
"new_audio_QA": false
|
||||
},
|
||||
"tests/economy/test_p05_funds_runtime.gd": {
|
||||
"source_sha256": "38a90af176e88e83041af7b20324f1383f9f38cdf05fa452c6cf75b8e3bf5b95",
|
||||
"ordinary_cleanup_prepared": true,
|
||||
"ordinary_control_labels": [
|
||||
"single"
|
||||
],
|
||||
"old_bounded_teardown": false,
|
||||
"new_audio_QA": false
|
||||
},
|
||||
"tests/economy/test_p05_funds_restart_1_write.gd": {
|
||||
"source_sha256": "3b28e94f1a1f577d74c5322d532b32854339dd4731532ac0b21b4fbc7ffb12f3",
|
||||
"ordinary_cleanup_prepared": false,
|
||||
"ordinary_control_labels": [],
|
||||
"old_bounded_teardown": false,
|
||||
"new_audio_QA": false
|
||||
},
|
||||
"tests/economy/test_p05_funds_restart_2_read.gd": {
|
||||
"source_sha256": "1b5bbf0f5c58df39ec28cc867c18a1a14d293fd36459343a118a3e97bc31d33a",
|
||||
"ordinary_cleanup_prepared": false,
|
||||
"ordinary_control_labels": [],
|
||||
"old_bounded_teardown": false,
|
||||
"new_audio_QA": false
|
||||
}
|
||||
},
|
||||
"outside_routes": {
|
||||
@@ -448,6 +471,9 @@
|
||||
}
|
||||
},
|
||||
"fixed_generated_report_routes": {
|
||||
"tests/economy/test_p05_funds_restart_1_write.gd": [
|
||||
"artifacts/p05-02/restart-handoff.json"
|
||||
],
|
||||
"tests/mvp/test_runtime_upkeep.gd": [
|
||||
"artifacts/upkeep-2026-09-29/preclose-snapshot.txt",
|
||||
"artifacts/upkeep-2026-09-29/closed-snapshot.txt"
|
||||
|
||||
@@ -0,0 +1,605 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Root-owned narrow P05-02 (front and hidden funds, rank tax, loan interest) collection using the
|
||||
unchanged guarded phase protocol of tools/run_p18_relationship_tests.py. After the roster, the F6
|
||||
restart writer and reader suites run as two more phases (separate engine processes); the writer's
|
||||
only declared generated report is the save handoff the reader loads."""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import stat
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import sys
|
||||
import uuid
|
||||
|
||||
sys.dont_write_bytecode = True
|
||||
import run_all_tests as shared
|
||||
|
||||
ROSTER = [
|
||||
'tests/economy/test_p05_funds_runtime.gd',
|
||||
'tests/mvp/test_original_midnight_settlement.gd',
|
||||
'tests/mvp/test_runtime_operations_integration.gd',
|
||||
'tests/s2/test_runtime_operations_cycle.gd',
|
||||
'tests/s6/test_runtime_save_lifecycle.gd',
|
||||
'tests/s6/test_runtime_snapshot_serialization.gd',
|
||||
'tests/supply/test_supply_management_service.gd',
|
||||
'tests/ui/test_upkeep_closed_ui.gd',
|
||||
]
|
||||
# P05-02 F6 (SPEC section 6): the writer saves, the reader in the next phase's engine resumes.
|
||||
RESTART = [
|
||||
'tests/economy/test_p05_funds_restart_1_write.gd',
|
||||
'tests/economy/test_p05_funds_restart_2_read.gd',
|
||||
]
|
||||
HANDOFF = 'artifacts/p05-02/restart-handoff.json'
|
||||
SUITES = ROSTER + RESTART
|
||||
WRITER_LINE = r'(?m)^P05_RESTART_WRITER pid=([0-9]+) handoff_sha256=([0-9a-f]{64})$'
|
||||
READER_LINE = r'(?m)^P05_RESTART_READER pid=([0-9]+) writer_pid=([0-9]+) handoff_sha256=([0-9a-f]{64})$'
|
||||
|
||||
|
||||
def collect(args, root, out, refs, markers, contracts, policy, contract_path, contract_sha, parse_paths):
|
||||
source_bytes = sum(pin['bytes'] for pin in refs.values())
|
||||
free = shutil.disk_usage(out.parent).free
|
||||
needed = source_bytes + shared.MIN_SPACE
|
||||
shared.require(free >= needed, 'fresh source and phase disk admission')
|
||||
outer = shared.module('p05_owned_outer', shared.SUPPORT / 'owned_outer.py')
|
||||
shared.require(not outer.native.helper['live_engines'](), 'another Godot owns CPU')
|
||||
engine = shutil.which('godot')
|
||||
shared.require(engine and Path(engine).is_file(), 'native launcher exists')
|
||||
engine = str(Path(engine).resolve())
|
||||
out.mkdir(parents=True, exist_ok=False)
|
||||
stage = out / 'stage'
|
||||
stage.mkdir()
|
||||
(out / 'starters').mkdir()
|
||||
(out / 'bootstrap').mkdir()
|
||||
for name, pin in shared.read(shared.SUPPORT / 'bootstrap-scripts.json').items():
|
||||
data = pin['text'].encode('utf-8')
|
||||
shared.require(hashlib.sha256(data).hexdigest() == pin['sha256'], 'unchanged external bootstrap bytes')
|
||||
(out / 'bootstrap' / name).write_bytes(data)
|
||||
protected = shared.default_player(root)
|
||||
expected = {name: {'bytes': pin['bytes'], 'sha256': pin['sha256']} for name, pin in refs.items()}
|
||||
selected = {'root_before': refs, 'map': {name: pin['sha256'] for name, pin in refs.items()}, 'timeout': args.timeout}
|
||||
for name, pin in refs.items():
|
||||
target = stage / name
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
shared.copy_source(Path(pin['path']), target)
|
||||
shared.require(shared.inventory(stage, stage=True) == expected, 'complete private source copy')
|
||||
public = (stage / 'project.godot').read_bytes()
|
||||
shared.write(out / 'parse-paths.json', parse_paths)
|
||||
run_id = uuid.uuid4().hex
|
||||
shared.write(out / 'runner-input.json', dict(protocol='guarded-p05-02-v1', run_id=run_id,
|
||||
owner_runner_pid=os.getpid(), project_root=str(root), stage=str(stage), roster=ROSTER,
|
||||
restart_phases=RESTART, restart_handoff=HANDOFF,
|
||||
selected_source_map=selected['map'], marker_contract_sha256=contract_sha,
|
||||
runner_sha256=shared.sha(Path(__file__)), shared_runner_sha256=shared.sha(shared.HERE / 'run_all_tests.py'),
|
||||
marker_module_sha256=shared.sha(shared.HERE / 'strict_test_markers.py'),
|
||||
engine=engine, engine_sha256=shared.sha(engine), default_player_before=protected,
|
||||
formal_acceptance=False, original_unit_complete=False))
|
||||
shared.write(out / 'source-start.json', refs)
|
||||
diagnostics = shared.module('p05_diagnostics', shared.SUPPORT / 'diagnostic_gate.py')
|
||||
owners = shared.module('p05_owners', shared.SUPPORT / 'ordinary_proof_gate.py')
|
||||
audio = shared.module('p05_audio', shared.SUPPORT / 'audio_evidence_gate.py')
|
||||
phases, rows, previous = [], [], {}
|
||||
error = None
|
||||
try:
|
||||
for phase, test in [('import', None), ('parse', None)] + [(str(i).zfill(3), name) for i, name in enumerate(SUITES)]:
|
||||
shared.require(shared.sha(contract_path) == contract_sha, 'marker contract unchanged')
|
||||
row = shared.execute_phase(engine, stage, out, phase, test, selected, expected, previous,
|
||||
policy, contracts, parse_paths, public, protected, root, outer, markers, diagnostics, owners, audio)
|
||||
archive_profiles(out, row)
|
||||
phases.append(row)
|
||||
if test:
|
||||
row.update(sequence=len(rows), godot=engine)
|
||||
rows.append(row)
|
||||
(out / 'all-tests.json').write_text(json.dumps(rows, ensure_ascii=False, indent=2) + '\n')
|
||||
print(('PASS ' if row['passed'] else 'FAIL ') + test, flush=True)
|
||||
shared.require(row['passed'], 'first failed phase stops without retry: ' + phase)
|
||||
except BaseException as caught:
|
||||
error = type(caught).__name__ + ': ' + str(caught)
|
||||
finally:
|
||||
cleanup, cleanup_errors = outer.finish_captured(outer.OWNED)
|
||||
guard_errors = []
|
||||
try:
|
||||
shared.require(shared.source_refs(root) == refs, 'whole source unchanged')
|
||||
shared.require(shared.sha(contract_path) == contract_sha, 'marker contract unchanged at end')
|
||||
shared.require(shared.default_player(root) == protected, 'default profile untouched')
|
||||
shared.require(shared.inventory(stage, stage=True) == dict(expected, **previous), 'whole stage exact')
|
||||
except BaseException as caught:
|
||||
guard_errors.append(type(caught).__name__ + ': ' + str(caught))
|
||||
ended = bool(outer.OWNED) and all(row['engine_ended'] is True for row in cleanup)
|
||||
passed = error is None and not cleanup_errors and not guard_errors and ended and len(phases) == len(SUITES) + 2 and all(row['passed'] for row in phases)
|
||||
context = shared.totals(rows, SUITES)
|
||||
shared.write(out / 'runner-ended.json', dict(context, protocol='guarded-p05-02-v1', run_id=run_id,
|
||||
owner_runner_pid=os.getpid(), passed=passed, engine_ended=ended,
|
||||
actual_captured_PIDs=[process.pid for process in outer.OWNED], final_owned_cleanup=cleanup,
|
||||
cleanup_errors=cleanup_errors, guard_errors=guard_errors, error=error, phases=phases,
|
||||
all_tests_sha256=shared.sha(out / 'all-tests.json') if (out / 'all-tests.json').exists() else None,
|
||||
default_player_after=shared.default_player(root), formal_acceptance=False,
|
||||
original_unit_complete=False, independent_review='pending', native_Windows='pending'))
|
||||
if passed:
|
||||
seal(out, refs, engine, contract_sha)
|
||||
# Root also exercises precisely the verifier that ordinary Runner uses.
|
||||
verify(out, refs, markers, contracts, policy, contract_sha, parse_paths)
|
||||
print(json.dumps(dict(context, passed=passed, error=error, cleanup_errors=cleanup_errors, guard_errors=guard_errors)), flush=True)
|
||||
return 0 if passed else 1
|
||||
|
||||
|
||||
|
||||
# Receipt file names are always relative; absolute paths in native receipts are
|
||||
# historical identity strings only and are never opened by the verifier.
|
||||
def require(ok, reason):
|
||||
shared.require(ok, reason)
|
||||
|
||||
|
||||
def digest(value):
|
||||
return hashlib.sha256(json.dumps(value, sort_keys=True, separators=(',', ':'),
|
||||
ensure_ascii=False).encode()).hexdigest()
|
||||
|
||||
|
||||
def content_map(refs):
|
||||
return {name: {'bytes': pin['bytes'], 'sha256': pin['sha256']}
|
||||
for name, pin in refs.items()}
|
||||
|
||||
|
||||
def plain_path(path):
|
||||
path = Path(path)
|
||||
require('..' not in path.parts, 'parent traversal refused')
|
||||
absolute = Path(os.path.abspath(path))
|
||||
for part in [absolute, *absolute.parents]:
|
||||
require(not part.is_symlink(), 'symlink path refused: ' + str(part))
|
||||
return absolute
|
||||
|
||||
|
||||
def confined(out, name):
|
||||
require(type(name) is str and name and '\\' not in name, 'ordinary relative evidence name')
|
||||
path = Path(name)
|
||||
require(not path.is_absolute() and '..' not in path.parts
|
||||
and path.as_posix() == name and name != '.', 'evidence path escape or alias')
|
||||
result = plain_path(out / path)
|
||||
require(result.is_relative_to(out), 'evidence confined to output')
|
||||
return result
|
||||
|
||||
|
||||
def inventory(out):
|
||||
result = {}
|
||||
require(out.is_dir(), 'output directory required')
|
||||
for directory, dirs, files in os.walk(out, followlinks=False):
|
||||
for name in dirs + files:
|
||||
p = Path(directory) / name
|
||||
mode = p.lstat().st_mode
|
||||
require(stat.S_ISREG(mode) or stat.S_ISDIR(mode), 'nonordinary evidence refused')
|
||||
if stat.S_ISREG(mode):
|
||||
require(p.stat().st_nlink == 1, 'hardlinked evidence refused')
|
||||
result[p.relative_to(out).as_posix()] = {
|
||||
'bytes': p.stat().st_size, 'sha256': shared.sha(p)}
|
||||
return result
|
||||
|
||||
|
||||
def unique_object(pairs):
|
||||
result = {}
|
||||
for key, value in pairs:
|
||||
require(key not in result, 'duplicate JSON key')
|
||||
result[key] = value
|
||||
return result
|
||||
|
||||
|
||||
def read_json(path):
|
||||
return json.loads(path.read_text(encoding='utf-8'), object_pairs_hook=unique_object,
|
||||
parse_constant=lambda token: require(False, 'nonfinite JSON ' + token))
|
||||
|
||||
|
||||
def archive_profiles(out, row):
|
||||
for label in ('startup', 'runtime'):
|
||||
value = row.get('whole_' + label + '_profile_after')
|
||||
if value is None:
|
||||
continue
|
||||
dest = out / 'profiles' / row['phase'] / label
|
||||
dest.mkdir(parents=True, exist_ok=False)
|
||||
source = plain_path(value['path'])
|
||||
require(shared.inventory(source) == value['files'], 'whole owned profile before archive')
|
||||
for name in value['files']:
|
||||
target = confined(out, str((dest / name).relative_to(out)))
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copyfile(source / name, target)
|
||||
require(shared.inventory(dest) == value['files'] == shared.inventory(source),
|
||||
'whole owned profile archive exact')
|
||||
|
||||
|
||||
def seal(out, refs, engine, contract_sha):
|
||||
# Last file written: an interrupted collection has no complete receipt.
|
||||
shutil.copyfile(engine, out / 'engine.bin')
|
||||
require(shared.sha(out / 'engine.bin') == shared.sha(engine), 'engine archive exact')
|
||||
source = content_map(refs)
|
||||
shared.write(out / 'receipt.json', {
|
||||
'schema': 'guarded-p05-02-v1', 'source_map': source,
|
||||
'parse_checks': len([name for name in refs if name.endswith('.gd')]),
|
||||
'source_map_sha256': digest(source),
|
||||
'project_settings_sha256': source['project.godot']['sha256'],
|
||||
'marker_contract_sha256': contract_sha,
|
||||
'engine_sha256': shared.sha(engine),
|
||||
'files': inventory(out),
|
||||
})
|
||||
|
||||
|
||||
def cleanup_gate(value):
|
||||
require(value['owned_child_created'] is True and value['engine_ended'] is True
|
||||
and value['actual_process_exit_code'] == 0 and value['errors'] == [],
|
||||
'successful actual owned cleanup')
|
||||
attempts = value['attempts']
|
||||
require(1 <= len(attempts) <= 3, 'bounded cleanup attempts')
|
||||
for index, row in enumerate(attempts):
|
||||
require(row['attempt'] == index + 1 and row['errors'] == []
|
||||
and row['wait_timeout_seconds'] == 5 and row['wait_completed'] is True
|
||||
and row['wait_returned_code'] == 0 and row['poll_after'] == 0,
|
||||
'complete bounded owned wait')
|
||||
|
||||
|
||||
def outer_cleanup(rows, pids):
|
||||
require([r['pid'] for r in rows] == pids, 'exact captured cleanup PID order')
|
||||
for row in rows:
|
||||
require(row['engine_ended'] is True and row['outer_cleanup_errors'] == []
|
||||
and row['foreign_process_or_group_signals'] == 0
|
||||
and row['outer_maximum_helper_invocations'] == 3
|
||||
and row['helper_maximum_waits'] == 3 and row['per_wait_timeout_seconds'] == 5,
|
||||
'unchanged outer cleanup contract')
|
||||
cleanup_gate(row['cleanup'])
|
||||
|
||||
|
||||
def verify(out, refs, markers, contracts, policy, contract_sha, parse_paths):
|
||||
receipt_path = confined(out, 'receipt.json')
|
||||
require(receipt_path.is_file(), 'regular final receipt required')
|
||||
manifest = read_json(receipt_path)
|
||||
require(manifest['schema'] == 'guarded-p05-02-v1', 'current receipt schema required')
|
||||
files = manifest['files']
|
||||
require(type(files) is dict and files, 'complete raw manifest')
|
||||
for name, pin in files.items():
|
||||
p = confined(out, name)
|
||||
require(p.is_file() and set(pin) == {'bytes', 'sha256'}
|
||||
and type(pin['bytes']) is int and pin['bytes'] >= 0
|
||||
and re.fullmatch('[0-9a-f]{64}', pin['sha256']) is not None,
|
||||
'ordinary artifact pin')
|
||||
actual = inventory(out)
|
||||
receipt_pin = actual.pop('receipt.json')
|
||||
require(actual == files, 'complete raw file set and SHA-256 equality')
|
||||
source = content_map(refs)
|
||||
require(manifest['source_map'] == source and manifest['source_map_sha256'] == digest(source),
|
||||
'current whole source content map independent of checkout path')
|
||||
require(manifest['project_settings_sha256'] == source['project.godot']['sha256']
|
||||
and manifest['marker_contract_sha256'] == contract_sha, 'current project/marker pins')
|
||||
|
||||
def read(name):
|
||||
require(name in files, 'required raw file missing: ' + name)
|
||||
return read_json(confined(out, name))
|
||||
|
||||
def text(name):
|
||||
require(name in files, 'required raw transport missing: ' + name)
|
||||
return confined(out, name).read_text(encoding='utf-8')
|
||||
|
||||
start, end = read('runner-input.json'), read('runner-ended.json')
|
||||
require(start['protocol'] == end['protocol'] == 'guarded-p05-02-v1'
|
||||
and start['run_id'] == end['run_id']
|
||||
and re.fullmatch('[0-9a-f]{32}', start['run_id']) is not None,
|
||||
'same current run')
|
||||
require(type(start['owner_runner_pid']) is int and start['owner_runner_pid'] > 0
|
||||
and start['owner_runner_pid'] == end['owner_runner_pid'], 'same collector owner')
|
||||
require(start['roster'] == ROSTER and start['restart_phases'] == RESTART
|
||||
and start['restart_handoff'] == HANDOFF and len(set(SUITES)) == len(SUITES),
|
||||
'exact unique roster and restart tests')
|
||||
require(start['selected_source_map'] == {n: p['sha256'] for n, p in source.items()}
|
||||
and content_map(read('source-start.json')) == source, 'whole selected source pins')
|
||||
for field, name in [('runner_sha256', 'tools/run_p05_funds_tests.py'),
|
||||
('shared_runner_sha256', 'tools/run_all_tests.py'),
|
||||
('marker_module_sha256', 'tools/strict_test_markers.py')]:
|
||||
require(start[field] == source[name]['sha256'], 'current collector/shared/marker pin')
|
||||
require(start['marker_contract_sha256'] == contract_sha, 'marker contract pin')
|
||||
# Resolve only the locally configured launcher, never the receipt's engine path.
|
||||
engine = shutil.which('godot')
|
||||
require(engine and shared.sha(engine) == start['engine_sha256']
|
||||
== manifest['engine_sha256'] == files['engine.bin']['sha256'],
|
||||
'current native engine and retained bytes pinned')
|
||||
derived_paths = ['res://' + name for name in sorted(refs) if name.endswith('.gd')]
|
||||
require(read('parse-paths.json') == parse_paths == derived_paths
|
||||
and manifest['parse_checks'] == len(derived_paths),
|
||||
'all exact source parse paths and receipt count')
|
||||
require(end['passed'] is True and end['engine_ended'] is True and end['error'] is None
|
||||
and end['cleanup_errors'] == [] and end['guard_errors'] == [],
|
||||
'finished successful collection without guard/cleanup error')
|
||||
for receipt in (start, end):
|
||||
require(receipt['formal_acceptance'] is False and receipt['original_unit_complete'] is False,
|
||||
'backend evidence never completes original unit')
|
||||
before = start['default_player_before']
|
||||
require(before == end['default_player_after'] and before['logs_and_locks_included'] is True
|
||||
and type(before['existed']) is bool and type(before['files']) is dict,
|
||||
'complete default player before/after equality')
|
||||
for name, pin in before['files'].items():
|
||||
confined(out, name) # Validate the inventory name; never open the player.
|
||||
require(set(pin) == {'bytes', 'sha256'} and type(pin['bytes']) is int
|
||||
and pin['bytes'] >= 0 and re.fullmatch('[0-9a-f]{64}', pin['sha256']),
|
||||
'whole default player file pin')
|
||||
require(before['existed'] or before['files'] == {}, 'absent player has no files')
|
||||
|
||||
native = shared.module('p05_verify_native', shared.SUPPORT / 'owned_diagnostic_process.py')
|
||||
diagnostics = shared.module('p05_verify_diagnostics', shared.SUPPORT / 'diagnostic_gate.py')
|
||||
owners = shared.module('p05_verify_owners', shared.SUPPORT / 'ordinary_proof_gate.py')
|
||||
# Helpers are loaded for their pure gates only. No run/probe/cleanup is called.
|
||||
origin = Path(start['stage']).parent
|
||||
require(Path(start['stage']) == origin / 'stage' and origin.is_absolute()
|
||||
and '..' not in origin.parts, 'original output identity')
|
||||
|
||||
def relocated(value):
|
||||
if isinstance(value, dict):
|
||||
return {relocated(k): relocated(v) for k, v in value.items()}
|
||||
if isinstance(value, list):
|
||||
return [relocated(v) for v in value]
|
||||
if isinstance(value, str) and value.startswith(str(origin) + '/'):
|
||||
return str(confined(out, value[len(str(origin)) + 1:]))
|
||||
return value
|
||||
|
||||
def proof_read(path):
|
||||
path = plain_path(path)
|
||||
require(path.is_relative_to(out), 'proof path stays in output')
|
||||
return relocated(read(path.relative_to(out).as_posix()))
|
||||
|
||||
owners.read = proof_read
|
||||
phases = end['phases']
|
||||
require(len(phases) == len(SUITES) + 2, 'exact import, parse, roster and restart phases')
|
||||
tests = read('all-tests.json')
|
||||
stage_files = shared.inventory(confined(out, 'stage'), stage=True)
|
||||
require(set(stage_files) == set(source) | {HANDOFF}, 'retained stage is the source and the restart handoff')
|
||||
handoff = stage_files[HANDOFF]
|
||||
require(len(tests) == len(SUITES) and end['all_tests_sha256'] == files['all-tests.json']['sha256'],
|
||||
'complete test rows')
|
||||
pids = []
|
||||
for index, (phase, test) in enumerate([('import', None), ('parse', None)]
|
||||
+ [(str(i).zfill(3), n) for i, n in enumerate(SUITES)]):
|
||||
row = read(phase + '-receipt.json')
|
||||
expected_row = dict(row)
|
||||
if test:
|
||||
expected_row.update(sequence=index - 2, godot=start['engine'])
|
||||
require(tests[index - 2] == expected_row, 'test row matches raw phase receipt')
|
||||
require(phases[index] == expected_row and row['phase'] == phase and row['test'] == test
|
||||
and row['passed'] is True and row['failed'] is False
|
||||
and row['validation_error'] is None and not row.get('guard_error')
|
||||
and row['default_player_entire_profile_unchanged'] is True,
|
||||
'exact successful phase')
|
||||
pid = row['actual_pid']
|
||||
require(type(pid) is int and pid > 0 and pid not in pids, 'distinct actual PIDs per phase')
|
||||
pids.append(pid)
|
||||
process = read(phase + '/process.json')
|
||||
require(process == row['native_process'] and process['pid'] == pid
|
||||
and process['owned_child_process_helper_sha256'] == native.HELPER_SHA
|
||||
== source['tools/regression/p09_owned_engine_process.py']['sha256'],
|
||||
'actual phase/process/helper agreement')
|
||||
stdout, stderr, logger = (text(phase + '/' + n) for n in
|
||||
('stdout.log', 'stderr.log', 'engine-native.log'))
|
||||
raw = stdout + stderr
|
||||
require(text(row['log']) == raw and row['log_sha256'] == files[row['log']]['sha256'],
|
||||
'literal complete raw stream')
|
||||
require(process['stdout_sha256'] == files[phase + '/stdout.log']['sha256']
|
||||
and process['stderr_sha256'] == files[phase + '/stderr.log']['sha256'],
|
||||
'process transport SHA')
|
||||
require(row['raw_native_log'] == dict(files[phase + '/engine-native.log'],
|
||||
path=str(origin / phase / 'engine-native.log')), 'native logger pin')
|
||||
review = diagnostics.review_streams(native, {
|
||||
'stdout': stdout, 'stderr': stderr, 'native_file': logger}, test)
|
||||
require(row['finite_original_diagnostic_review'] == review
|
||||
and diagnostics.diagnostic_result_gate(process, review)
|
||||
and shared.process_gate(process, review['allowed_e31_error_lines']),
|
||||
'strict diagnostics/process gates')
|
||||
require(native.native_diagnostics(stdout, stderr, row['command'])
|
||||
== process['strict_native_diagnostics'], 'raw banner/diagnostics recomputed')
|
||||
command = [start['engine'], '--headless', '--path', start['stage']]
|
||||
if phase == 'import':
|
||||
command += ['--editor', '--import', '--quit', '--verbose']
|
||||
else:
|
||||
script = ('bootstrap/parse_full_dependencies.gd' if phase == 'parse'
|
||||
else 'starters/' + phase + '.gd')
|
||||
command += ['--script', str(origin / script), '--verbose']
|
||||
require(row['starter_sha256'] == files[script]['sha256'], 'exact starter pin')
|
||||
if test:
|
||||
expected_starter = ('extends ' + json.dumps('res://' + test) + '\nconst Guard := preload('
|
||||
+ json.dumps(str(origin / 'bootstrap/profile_guard.gd'))
|
||||
+ ')\nfunc _initialize() -> void:\n\tif not Guard.activate():\n\t\tquit(97)\n\t\treturn\n\tsuper._initialize()\n')
|
||||
require(text(script) == expected_starter, 'unchanged guarded starter bytes')
|
||||
command += ['--log-file', str(origin / phase / 'engine-native.log')]
|
||||
require(row['command'] == process['argv'] == command, 'exact native argv/logger')
|
||||
for filename, field, event in [('started.json', 'actual_start_binding', 'ENGINE_STARTED'),
|
||||
('ended.json', 'actual_end_binding', 'ENGINE_ENDED')]:
|
||||
binding = read(phase + '/' + filename)
|
||||
require(binding == process[field] and binding['event'] == event
|
||||
and binding['actual_pid'] == binding['pid'] == pid
|
||||
and binding['owner_pid'] == start['owner_runner_pid']
|
||||
and binding['command'] == binding['argv'] == command, 'actual START/END ownership')
|
||||
binding = process['actual_start_binding']
|
||||
identity = binding['current_process_identity']
|
||||
if identity is None:
|
||||
require(binding['tracked_child_ended_before_initial_probe'] is True, 'early ended tracked child')
|
||||
else:
|
||||
require(binding['live_identity_exact'] is True and identity == {
|
||||
'pid': pid, 'ppid': start['owner_runner_pid'], 'pgid': pid, 'args': ' '.join(command)},
|
||||
'recorded live child PID/PPID/PGID/argv')
|
||||
finish = process['actual_end_binding']
|
||||
require(finish['engine_ended'] is True and finish['timed_out'] is False
|
||||
and finish['lifecycle_error'] is None and finish['exit_code'] == 0
|
||||
and finish['actual_process_exit_code'] == 0
|
||||
and finish['start_receipt_written'] is True
|
||||
and finish['monotonic_ns'] >= binding['monotonic_ns'], 'complete native END')
|
||||
cleanup = read(phase + '/adapter-owned-cleanup.json')
|
||||
require(cleanup == process['adapter_owned_cleanup'], 'raw adapter cleanup')
|
||||
cleanup_gate(cleanup)
|
||||
capture = row['outer_actual_capture']
|
||||
require(read(phase + '/outer-owned-finally.json') == {
|
||||
k: v for k, v in capture.items()
|
||||
if k not in ('outer_receipt_written', 'outer_receipt_error', 'passed')},
|
||||
'whole raw outer receipt')
|
||||
require(capture['actual_captured_pids'] == [pid] and capture['passed'] is True
|
||||
and capture['all_captured_ended'] is True and capture['adapter_exception'] is None
|
||||
and capture['outer_cleanup_errors'] == [] and capture['outer_receipt_error'] is None
|
||||
and capture['outer_receipt_written'] is True
|
||||
and capture['all_cleanup_before_outer_receipt'] is True
|
||||
and capture['foreign_process_or_group_signals'] == 0
|
||||
and row['engine_ended'] is True and row['exit_code'] == 0, 'owned outer capture')
|
||||
outer_cleanup(capture['cleanup'], [pid])
|
||||
startup = read(phase + '-startup-profile-before.json')
|
||||
require(startup == {'path': row['whole_startup_profile_after']['path'], 'existed': False,
|
||||
'files': {}, 'before_native_spawn': True}, 'fresh startup profile')
|
||||
require(row['whole_startup_profile_after']['fresh_before_engine'] is True,
|
||||
'startup fresh before engine')
|
||||
name = row['profile_startup_name']
|
||||
require(re.fullmatch('TheTree-PCK-tests-[0-9a-f]{32}-standard-startup-' + phase, name)
|
||||
and Path(startup['path']).name == name and row['private_project_fields'] == 2
|
||||
and row['private_project_sha256'] == hashlib.sha256(shared.private_project(
|
||||
(shared.HERE.parent / 'project.godot').read_bytes(), name)).hexdigest(),
|
||||
'exact two-field startup isolation')
|
||||
for label in ('startup', 'runtime'):
|
||||
if label == 'runtime' and phase == 'import':
|
||||
continue
|
||||
whole = row['whole_' + label + '_profile_after']
|
||||
archive = confined(out, 'profiles/' + phase + '/' + label)
|
||||
require(archive.is_dir() and shared.inventory(archive)
|
||||
== whole['files'], 'complete retained private profile')
|
||||
if phase != 'import':
|
||||
guard = read(phase + '-profile.json')
|
||||
runtime = Path(row['whole_runtime_profile_after']['path'])
|
||||
name = guard['custom_user_dir_name']
|
||||
require(re.fullmatch('TheTree-PCK-tests-[0-9a-f]{32}-standard-runtime-' + phase, name)
|
||||
and runtime.name == name and guard['verified'] is True
|
||||
and guard['conditions'] == [True] * 5 and guard['conditions_checked'] == 5
|
||||
and guard['fresh_before_parent_initialize'] is True
|
||||
and guard['profile_writes_before_guard'] == 0
|
||||
and guard['actual_user_data_dir'] == guard['expected_user_data_dir'] == str(runtime)
|
||||
and guard['globalized_probe'] == str(runtime / 'guard-probe')
|
||||
and guard['project_settings_persisted'] is False, 'all unchanged Guard conditions')
|
||||
require(row['actual_private_profile'] == {
|
||||
'report': guard, 'report_sha256': files[phase + '-profile.json']['sha256'],
|
||||
'whole_files': row['whole_runtime_profile_after']['files']}, 'whole raw Guard report')
|
||||
require(row['controlled_environment'] == {
|
||||
'THE_TREE_PACK_PROFILE_NAME': name, 'THE_TREE_PACK_PROFILE_EXPECTED': str(runtime),
|
||||
'THE_TREE_PACK_PROFILE_REPORT': str(origin / (phase + '-profile.json')),
|
||||
'THE_TREE_FULL_PARSE_PATHS': str(origin / 'parse-paths.json'),
|
||||
**({'THE_TREE_AUDIO_TEARDOWN_PROOF_DIR': str(origin / (phase + '-teardown/owned-audio')),
|
||||
'THE_TREE_AUDIO_FIXTURE_CONTROL_PROOF': str(origin / (phase + '-teardown/control.json'))}
|
||||
if test and policy['suite_policies'].get(test, {}).get('ordinary_cleanup_prepared') else {})},
|
||||
'exact controlled Guard/proof environment')
|
||||
else:
|
||||
require(row['controlled_environment'] == {}, 'fresh import environment')
|
||||
if phase == 'parse':
|
||||
require(len(re.findall(r'(?m)^FULL_DEPENDENCY_PARSE\b', raw)) == 1
|
||||
and re.findall(r'(?m)^FULL_DEPENDENCY_PARSE checks=([0-9]+) failures=([0-9]+)\n', raw)
|
||||
== [(str(len(parse_paths)), '0')] and row['actual_parse_checks'] == len(parse_paths), 'unique all-script parse marker')
|
||||
if test:
|
||||
parsed = markers.parse_raw(test, raw, contracts, source[test]['sha256'])
|
||||
require(parsed['passed'] and row['completion'] == parsed
|
||||
and row['reported_checks'] == parsed['checks']
|
||||
and row['reported_failures'] == parsed['failures']
|
||||
and row['completion_marker'] == parsed['marker'] and row['collector_errors'] == [],
|
||||
'source-pinned raw completion marker')
|
||||
require(row['source_sha256'] == row['source_sha256_end'] == source[test]['sha256'],
|
||||
'exact test source before/after')
|
||||
p = shared.phase_policy(test, Path(refs[test]['path']), policy['suite_policies'])
|
||||
require(row['policy'] == p, 'current exact suite policy')
|
||||
if p['ordinary_cleanup_prepared']:
|
||||
proof = owners.ordinary_gate(confined(out, phase + '-teardown'), pid, out,
|
||||
p['ordinary_control_labels'])
|
||||
require(proof == relocated(row['ordinary_owner_pairs']), 'full ordinary/audio ownership proof')
|
||||
if test == RESTART[0]:
|
||||
require(row['generated_reports'] == {HANDOFF: dict(handoff, actual_engine_pid=pid,
|
||||
producer_test=test, producer_source_sha256=source[test]['sha256'], payload_modified=False)},
|
||||
'the writer generates exactly the retained restart handoff')
|
||||
require(re.findall(WRITER_LINE, raw) == [(str(pid), handoff['sha256'])]
|
||||
and read_json(confined(out, 'stage/' + HANDOFF))['writer_pid'] == pid,
|
||||
'the writer engine printed and recorded its own handoff')
|
||||
writer_pid = pid
|
||||
else:
|
||||
require(row['generated_reports'] == {}, 'only the restart writer generates a report')
|
||||
if test == RESTART[1]:
|
||||
require(re.findall(READER_LINE, raw) == [(str(pid), str(writer_pid), handoff['sha256'])]
|
||||
and pid != writer_pid, 'a separate reader engine read the exact writer handoff')
|
||||
require(end['actual_captured_PIDs'] == pids, 'all captured engines')
|
||||
outer_cleanup(end['final_owned_cleanup'], pids)
|
||||
require(all(end[k] == v for k, v in shared.totals(tests, SUITES).items()), 'recomputed exact totals')
|
||||
require(shared.inventory(confined(out, 'stage'), stage=True) == dict(source, **{HANDOFF: handoff}),
|
||||
'entire retained source/settings and handoff exact')
|
||||
for name, pin in shared.read(shared.SUPPORT / 'bootstrap-scripts.json').items():
|
||||
require(text('bootstrap/' + name).encode() == pin['text'].encode()
|
||||
and files['bootstrap/' + name]['sha256'] == pin['sha256'], 'unchanged bootstrap/Guard pins')
|
||||
require(inventory(out) == dict(files, **{'receipt.json': receipt_pin}),
|
||||
'whole raw evidence unchanged during verification')
|
||||
require(content_map(shared.source_refs(shared.HERE.parent)) == source,
|
||||
'whole current source unchanged during verification')
|
||||
print(json.dumps({'verified': True, 'actual_suites': len(SUITES), 'parse_checks': len(parse_paths),
|
||||
'actual_checks': end['actual_all_roster_checks'], 'engines_started': 0,
|
||||
'formal_acceptance': False, 'original_unit_complete': False}))
|
||||
return 0
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
argv = list(sys.argv[1:] if argv is None else argv)
|
||||
# No argparse abbreviation, repeated flags, = aliases or positional tokens.
|
||||
parser = argparse.ArgumentParser(description=__doc__, allow_abbrev=False)
|
||||
parser.add_argument('--output', required=True)
|
||||
modes = parser.add_mutually_exclusive_group()
|
||||
modes.add_argument('--collect', action='store_true', help='Root only; fresh native collection')
|
||||
modes.add_argument('--prepare-only', action='store_true')
|
||||
seen = set()
|
||||
i = 0
|
||||
while i < len(argv):
|
||||
flag = argv[i]
|
||||
require(flag in ('--output', '--collect', '--prepare-only', '--help')
|
||||
and flag not in seen, 'unknown, duplicate or malformed flag')
|
||||
seen.add(flag)
|
||||
if flag == '--output':
|
||||
i += 1
|
||||
require(i < len(argv) and argv[i] and not argv[i].startswith('--'), 'output value required')
|
||||
i += 1
|
||||
args = parser.parse_args(argv)
|
||||
args.timeout = 1200
|
||||
root = shared.HERE.parent
|
||||
out = plain_path(args.output)
|
||||
refs = shared.source_refs(root)
|
||||
require(set(SUITES).issubset(shared.roster(root)), 'normal discovery includes narrow roster and restart tests')
|
||||
discovered = shared.roster(root)
|
||||
require(discovered.index(RESTART[0]) < discovered.index(RESTART[1]), 'the full roster also runs the writer first')
|
||||
markers = shared.module('p05_exact_markers', shared.HERE / 'strict_test_markers.py')
|
||||
contract_path = root / 'docs/plans/original-completion-2026-10-02/execution/completion_marker_contracts.json'
|
||||
contract_sha = shared.sha(contract_path)
|
||||
contracts = markers.load_contracts(contract_path)
|
||||
require(all(name in contracts for name in SUITES), 'complete marker roster')
|
||||
policy = shared.read(shared.SUPPORT / 'suite-policy.json')
|
||||
shared.policy_coverage(SUITES, refs, policy)
|
||||
for test in SUITES:
|
||||
shared.phase_policy(test, Path(refs[test]['path']), policy['suite_policies'])
|
||||
require(test not in policy['outside_routes'], 'no outside report routes in the narrow run')
|
||||
require(policy['fixed_generated_report_routes'].get(test, []) == ([HANDOFF] if test == RESTART[0] else []),
|
||||
'only the restart writer declares one generated report')
|
||||
for test in ROSTER[:1] + RESTART:
|
||||
require(contracts[test]['source_sha256_at_schema_audit'] == refs[test]['sha256'],
|
||||
'new strict source-hashed marker')
|
||||
parse_paths = ['res://' + name for name in sorted(refs) if name.endswith('.gd')]
|
||||
if args.prepare_only:
|
||||
ancestor = out.parent
|
||||
while not ancestor.exists():
|
||||
ancestor = ancestor.parent
|
||||
free = shutil.disk_usage(ancestor).free
|
||||
size = sum(p['bytes'] for p in refs.values())
|
||||
print(json.dumps({'roster': ROSTER, 'source_files': len(refs), 'source_bytes': size,
|
||||
'free_bytes': free, 'conservative_required_bytes': size + shared.MIN_SPACE,
|
||||
'capacity_available': free >= size + shared.MIN_SPACE, 'parse_paths': len(parse_paths),
|
||||
'restart_phases': RESTART, 'future_native_phases': len(SUITES) + 2, 'actual_checks': None, 'engines': 0, 'stages': 0,
|
||||
'formal_acceptance': False}))
|
||||
return 0
|
||||
if args.collect:
|
||||
require(not out.exists() and out.parent.is_dir(), 'fresh output with existing parent required')
|
||||
require(not out.is_relative_to(root), 'private collection outside source tree')
|
||||
return collect(args, root, out, refs, markers, contracts, policy,
|
||||
contract_path, contract_sha, parse_paths)
|
||||
return verify(out, refs, markers, contracts, policy, contract_sha, parse_paths)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
raise SystemExit(main())
|
||||
except (AssertionError, OSError, ValueError, KeyError, TypeError) as error:
|
||||
print(type(error).__name__ + ': ' + str(error), file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
Reference in New Issue
Block a user