P04-01: 同時発生の更新規約

This commit is contained in:
Agent Control Runner
2026-10-18 14:36:16 +09:00
parent befa0ef1f6
commit acab529c8d
23 changed files with 2003 additions and 186 deletions
+88 -1
View File
@@ -283,6 +283,15 @@ def supplied_file(directory, descriptor):
support = directory / 'audit-support'
roots = [support / n for n in ('p04-whole-closure-r01', 'native-first-current',
'p04-current-native-series-r01', 'p04-r17-full-inputs-r01')]
fresh_path = support / 'p04-fresh-runs.json'
if fresh_path.is_file():
fresh = load(fresh_path)
require(fresh['protocol'] == 'p04-fresh-runs-v1', 'fresh material registry')
roots.append(support / 'p04-fresh-context')
for row in fresh['series'].values():
relative = Path(row['run'])
require(not relative.is_absolute() and '..' not in relative.parts, 'fresh material run path')
roots.append(directory / relative)
matches = [root for root in roots if path.is_relative_to(root)]
require(len(matches) == 1, 'unsupplied external material: ' + name)
path = safe(matches[0], path.relative_to(matches[0]).as_posix())
@@ -356,6 +365,10 @@ def verify_roles(index, directory):
composed = git_bytes('-c', 'rerere.enabled=false', 'merge-tree', '--write-tree',
main, submitted).decode().strip()
require(re.fullmatch('[0-9a-f]{40}', composed) is not None, 'conflicted composition')
if 'fresh_run_bindings' in index:
fresh = index['fresh_run_bindings']
require((fresh['M'], fresh['S'], fresh['Q_tree']) == (main, submitted, composed),
'fresh evidence does not bind recomputed Q')
main_entries, patch, target = [tree_entries(t) for t in (main, submitted, composed)]
anchor_entries = tree_entries(MAIN_ANCHOR)
for path in main_entries.keys() | target.keys():
@@ -1050,7 +1063,7 @@ def verify_shift_completion(base):
return {'verified_conditions': ['shift_completion'], 'phases': points, 'transaction_id': transaction_id}
def combine_native_series(directory, native):
def combine_historical_native_series(directory, native):
"""Independent R composition; rerun raw checks, never trust condition scalars.
The C verifier and its fixtures remain unchanged. This function does not
@@ -1095,6 +1108,80 @@ def combine_native_series(directory, native):
'stage_A': 'candidate binding stage A pending', 'formal_acceptance': False}
def combine_native_series(directory, native):
"""Fresh raw supplies conditions; historical collection is separate provenance."""
import importlib.util
def module(name, path):
spec = importlib.util.spec_from_file_location(name, path)
value = importlib.util.module_from_spec(spec)
spec.loader.exec_module(value)
return value
module_path = ROOT / DOC_SCOPE / 'p04_native_series.py'
series = module('p04_fresh_series', module_path)
root_bindings = series.fresh_bindings(directory)
collection = root_bindings['collection']
require(re.fullmatch(r'audit-support/p04-raw-collect-q[0-9]+', collection) is not None,
'exclusive fresh collection name')
base = directory / collection
manifest_path = safe(base, 'MANIFEST.json')
manifest = load(manifest_path)
require(manifest['protocol'] == 'p04-fresh-native-series-collection-v1'
and manifest['historical_merged'] is False
and set(manifest['series']) == set(series.FRESH_RUNS), 'fresh series roster')
verified, bindings, results, pids = set(), {}, {}, []
for name in series.FRESH_RUNS:
binding = manifest['series'][name]
path = safe(base, binding['path'])
require(path.name == name + '.json' and sha(path) == binding['sha256']
and path.stat().st_size == binding['bytes'], 'fresh series collection pin')
recorded = load(path)
require(recorded['verifier_sha256'] == sha(module_path), 'fresh verifier drift')
actual = getattr(series, 'verify_fresh_' + name)(directory)
require({k: v for k, v in recorded.items() if k != 'verifier_sha256'} == actual, 'fresh raw recomputation drift')
verified.update(actual['verified_conditions'])
pids.extend(actual['owned_pids'])
bindings[name], results[name] = binding['sha256'], actual
require(len(pids) == len(set(pids)), 'fresh series PID reuse')
order = results['s5']['facts']['order']['cases']
gates = {
'D05-P04-DESTRUCTION': [('S5C_DESTRUCTION_COMMAND', 'command_destruction_before_completion'),
('S5D_DESTRUCTION_RAID', 'raid_sale_before_destruction'),
('S5D_DESTRUCTION_RAID', 'raid_unfinished_release')],
'D05-P04-MIDNIGHT-DAY': [('S5E_MIDNIGHT', 'midnight_close_upkeep_before_sale'),
('S5E_MIDNIGHT', 'midnight_new_day_sale')],
'D05-P04-EXIT': [('S5F_EXIT', 'command_exit_before_start'), ('S5F_EXIT', 'planned_exit_after_completion')],
}
for ref, pairs in gates.items():
require(all(order[case][key] is True for case, key in pairs), 'S5 order gate: ' + ref)
power = results['s5']['facts']['power']['cases']
require(power['S5A_PURE']['measurements']['power_stop'] == REQUIRED['power_stop'][2]
and power['S5B_DEPENDENCY']['measurements']['dependency_stop'] == REQUIRED['dependency_stop'][2],
'S5 D05-P04-PAUSE-REASON gate')
full_verifier = module('p04_full_verifier', ROOT / DOC_SCOPE / 'full_suite_verifier.py')
full_binding = root_bindings['full_suite']
full_run = directory / full_binding['run']
require(not Path(full_binding['run']).is_absolute() and '..' not in Path(full_binding['run']).parts,
'full run path')
for leaf, key in [('runner-input.json', 'runner_input'), ('runner-ended.json', 'runner_ended')]:
series.checked(safe(full_run, leaf).read_bytes(), full_binding[key], 'Root full receipt')
full_inputs = load(safe(full_run, 'runner-input.json'))
full = full_verifier.verify(Path(full_inputs['project_root']), full_run, REQUIRED)
require(full['verified'] is True and set(full['conditions']) == set(REQUIRED) | {'EV'}, 'full condition membership')
expected_source = {n: p['sha256'] for n, p in load(directory / root_bindings['series']['s5']['run'] / 'source_before.json').items()}
require(full['source_sha256'] == expected_source, 'full and boundary exact same Q')
history = safe(directory / 'audit-support/p04-raw-collect-r22', 'MANIFEST.json')
c_base = directory / 'audit-support/native-first-current'
require(native == verify_native(c_base), 'historical C provenance recomputation')
return {'verified_conditions': sorted(verified), 'series_manifest_sha256': sha(manifest_path),
'series_bindings': bindings, 'fresh_collection': collection, 'full_suite': full,
'historical_collection': {'manifest_sha256': sha(history), 'merged': False},
'C_source_manifest_sha256': sha(safe(c_base, 'SOURCE_MANIFEST.json')),
'C_provenance_sha256': sha(safe(c_base, 'OWNERSHIP_RAW_PROVENANCE.json')),
'missing_conditions': sorted((set(REQUIRED) | {'EV'}) - verified),
'nativeWindows': {name: 'pending' for name in sorted(set(REQUIRED) | {'EV'})},
'stage_A': 'candidate binding stage A pending', 'formal_acceptance': False}
def verify(directory):
# Contract hashes the supplied spec string, while the checked-in JSON has
# one final LF. Accept only that exact representation difference.