P04-01: 同時発生の更新規約
This commit is contained in:
@@ -15,6 +15,7 @@ import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
sys.dont_write_bytecode = True
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SPEC = ROOT / 'docs/spec/acceptance/P04-01.json'
|
||||
SPEC_HASH = '9ec722e7dfb0bee178d291624a026420c08412574e238bba1fde012c7a6f7881'
|
||||
@@ -24,7 +25,8 @@ REGISTERED_COMMIT = 'deb1bcb2374eb378b840ca345db952bd8572cb6e'
|
||||
EXECUTION_ORIGIN = '9767b0a28ca8d252520307dbbac60a1d8cfb87ab'
|
||||
CHECKER_PATH = 'tools/check_p04_order_evidence.py'
|
||||
DOC_SCOPE = 'docs/plans/original-completion-2026-10-02/execution/p04-01/'
|
||||
MAIN_ANCHOR = '9694f50ee63750192376ca69bc7dda3f884784c5'
|
||||
MAIN_ANCHOR = '9b1a18c1eb25ca1300dcd59da78423c0dda2f498'
|
||||
TESTED_PRODUCT = '5f6bc11d6bb6e92d22d787989b219fef3a435bc1'
|
||||
SELECTION_SHA = '320ca668732b4ff72fc4449998af2327d4e5c527b06896740806aaf0487282b4'
|
||||
_GIT_ENV = None
|
||||
# Fixed membership, never supplied by the evidence index.
|
||||
@@ -135,10 +137,17 @@ def literal(a, b):
|
||||
|
||||
|
||||
def git_bytes(*args):
|
||||
env = _GIT_ENV if _GIT_ENV is not None else dict(os.environ, GIT_OPTIONAL_LOCKS='0')
|
||||
env = _GIT_ENV if _GIT_ENV is not None else git_environment()
|
||||
return subprocess.check_output(['git', '--no-replace-objects', *args], cwd=ROOT, env=env)
|
||||
|
||||
|
||||
def git_environment():
|
||||
env = {k: v for k, v in os.environ.items() if not k.startswith('GIT_')}
|
||||
env.update(GIT_OPTIONAL_LOCKS='0', GIT_NO_REPLACE_OBJECTS='1', GIT_CONFIG_NOSYSTEM='1',
|
||||
GIT_CONFIG_GLOBAL=os.devnull)
|
||||
return env
|
||||
|
||||
|
||||
@contextmanager
|
||||
def isolated_objects():
|
||||
"""merge-tree writes only disposable objects; canonical refs/index stay untouched.
|
||||
@@ -149,11 +158,9 @@ def isolated_objects():
|
||||
global _GIT_ENV
|
||||
require(_GIT_ENV is None, 'nested object store')
|
||||
objects = git_bytes('rev-parse', '--path-format=absolute', '--git-path', 'objects').decode().strip()
|
||||
with tempfile.TemporaryDirectory(prefix='p04-object-audit-') as temporary:
|
||||
env = dict(os.environ)
|
||||
for key in ('GIT_OBJECT_DIRECTORY', 'GIT_ALTERNATE_OBJECT_DIRECTORIES',
|
||||
'GIT_INDEX_FILE', 'GIT_QUARANTINE_PATH'):
|
||||
env.pop(key, None)
|
||||
build = Path(os.environ['BUILD_OUTPUT_DIR']).resolve(strict=True)
|
||||
with tempfile.TemporaryDirectory(prefix='p04-object-audit-', dir=build) as temporary:
|
||||
env = git_environment()
|
||||
env.update(GIT_OBJECT_DIRECTORY=temporary, GIT_ALTERNATE_OBJECT_DIRECTORIES=objects,
|
||||
GIT_OPTIONAL_LOCKS='0', GIT_NO_REPLACE_OBJECTS='1')
|
||||
_GIT_ENV = env
|
||||
@@ -208,7 +215,7 @@ def supplied_file(directory, descriptor):
|
||||
if path.is_absolute():
|
||||
support = directory / 'audit-support'
|
||||
roots = [support / n for n in ('p04-whole-closure-r01', 'native-first-current',
|
||||
'p04-current-native-series-r01')]
|
||||
'p04-current-native-series-r01', 'p04-r17-full-inputs-r01')]
|
||||
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())
|
||||
@@ -304,6 +311,128 @@ def verify_product_target(index, directory, checker_commit):
|
||||
'tested_product': tested, 'product_target': target}
|
||||
|
||||
|
||||
def ancestor(older, newer):
|
||||
# merge-base's nonzero status is data only for the ordinary non-ancestor case.
|
||||
try:
|
||||
git_bytes('merge-base', '--is-ancestor', older, newer)
|
||||
return True
|
||||
except subprocess.CalledProcessError as exc:
|
||||
require(exc.returncode == 1, 'cannot determine ancestry')
|
||||
return False
|
||||
|
||||
|
||||
def submission_role(commit):
|
||||
require(ancestor(REGISTERED_COMMIT, commit) and not ancestor(MAIN_ANCHOR, commit),
|
||||
'invalid submission ancestry')
|
||||
changed = git_bytes('diff', '--no-ext-diff', '--no-renames', '--name-only', '-z',
|
||||
REGISTERED_COMMIT, commit).split(b'\0')
|
||||
require(all(allowed_path(p.decode()) for p in changed if p), 'submission outside allowed_paths')
|
||||
|
||||
|
||||
def actual_checkout():
|
||||
"""Bind the executing modules and every worktree file to the actual HEAD."""
|
||||
commit = git_bytes('rev-parse', '--verify', 'HEAD^{commit}').decode().strip()
|
||||
tree = git_bytes('rev-parse', 'HEAD^{tree}').decode().strip()
|
||||
entries = tree_entries(tree)
|
||||
require(not git_bytes('status', '--porcelain=v1', '--untracked-files=all',
|
||||
'--ignore-submodules=none'), 'checkout is not clean')
|
||||
require(not git_bytes('ls-files', '--others', '-z'), 'untracked/ignored substitution')
|
||||
for path, (mode, oid) in entries.items():
|
||||
actual = safe(ROOT, path)
|
||||
require(actual.read_bytes() == git_bytes('cat-file', 'blob', oid), 'HEAD/tree/FS bytes: ' + path)
|
||||
require(('100755' if actual.stat().st_mode & 0o111 else '100644') == mode,
|
||||
'HEAD/tree/FS mode: ' + path)
|
||||
# Also reject untracked directory symlinks, including ones ignored by Git.
|
||||
for parent, directories, files in os.walk(ROOT, followlinks=False):
|
||||
if Path(parent) == ROOT:
|
||||
directories[:] = [p for p in directories if p != '.git']
|
||||
files = [p for p in files if p != '.git']
|
||||
for name in directories + files:
|
||||
require(not (Path(parent) / name).is_symlink(), 'worktree symlink')
|
||||
require(Path(__file__).resolve() == safe(ROOT, CHECKER_PATH), 'checker module location')
|
||||
return commit, tree, entries
|
||||
|
||||
|
||||
def verify_roles(index, directory):
|
||||
"""Infer roles from Git, never from an index or a caller's stage label."""
|
||||
require(not ({'candidate_commit', 'candidate_tree', 'code_only', 'candidate', 'phase'} & index.keys()),
|
||||
'candidate/code-only/phase declarations are not evidence')
|
||||
commit, actual_tree, actual = actual_checkout()
|
||||
require(_GIT_ENV is not None, 'isolated object store required')
|
||||
if not ancestor(MAIN_ANCHOR, commit):
|
||||
submission_role(commit)
|
||||
submitted, main, role = commit, MAIN_ANCHOR, 'prospective composition'
|
||||
else:
|
||||
parents = git_bytes('show', '-s', '--format=%P', commit).decode().split()
|
||||
require(len(parents) == 2, 'integration/final requires a two-parent no-ff merge')
|
||||
main, submitted = parents
|
||||
require(ancestor(MAIN_ANCHOR, main), 'merge main ancestry')
|
||||
submission_role(submitted)
|
||||
role = 'integration/final'
|
||||
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')
|
||||
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():
|
||||
require(main_entries.get(path) == target.get(path) or allowed_path(path),
|
||||
'composition changed game/unknown source: ' + path)
|
||||
# Metadata membership comes from the real main anchor, never a declared exclusion.
|
||||
metadata = sorted(p for p in anchor_entries if not selected_path(p))
|
||||
for path in target:
|
||||
require(selected_path(path) or allowed_path(path) or path in metadata,
|
||||
'unknown source hidden as metadata: ' + path)
|
||||
if role == 'integration/final':
|
||||
require(actual_tree == composed and actual == target, 'actual merge differs from composition')
|
||||
require(target[CHECKER_PATH] == patch[CHECKER_PATH] == actual[CHECKER_PATH],
|
||||
'checker blob differs from submission')
|
||||
for path in patch:
|
||||
if allowed_path(path):
|
||||
require(target.get(path) == patch[path], 'reviewed patch differs in merge: ' + path)
|
||||
binding = index['product_binding']
|
||||
require(set(binding) == {'tested_product', 'runner_inputs'}, 'unknown product role/metadata declaration')
|
||||
require(binding['tested_product'] == TESTED_PRODUCT, 'wrong tested revision')
|
||||
product = product_manifest(target)
|
||||
tested_entries = tree_entries(TESTED_PRODUCT)
|
||||
expected = product_manifest(tested_entries)
|
||||
require(len(product) == 1338 and product == expected and
|
||||
product_manifest(main_entries) == expected and product_manifest(anchor_entries) == expected,
|
||||
'complete 1338-file native product mismatch')
|
||||
require(all(target[p][0] == main_entries[p][0] == tested_entries[p][0] for p in product),
|
||||
'native product mode mismatch')
|
||||
require(index['source_map'] == {p: v['sha256'] for p, v in product.items()}, 'stale pin: source map')
|
||||
runner_paths = set()
|
||||
for descriptor in binding['runner_inputs']:
|
||||
path = supplied_file(directory, descriptor)
|
||||
require(path not in runner_paths, 'duplicate runner input')
|
||||
runner_paths.add(path)
|
||||
native = load(path)
|
||||
before = native['source_before']
|
||||
require(set(before) == set(product) and all(
|
||||
{'bytes': v['bytes'], 'sha256': v['sha256']} == product[p] for p, v in before.items()),
|
||||
'runner complete source map mismatch')
|
||||
require(native['runner_sha256'] == product['tools/run_all_tests.py']['sha256'], 'runner source pin')
|
||||
overrides = native['QA_overrides']
|
||||
require(len(overrides) == 1 and overrides[0].startswith('tests/') and overrides[0] in product,
|
||||
'QA override membership')
|
||||
selected = {p: v['sha256'] for p, v in product.items()}
|
||||
selected[overrides[0]] = native['QA']['sha256']
|
||||
require(native['selected_source_map'] == selected, 'selected QA source map')
|
||||
needed = native.get('fixed_input_pins', []) + [native['QA']]
|
||||
require(set(descriptor['materials']) == {p['path'] for p in needed}, 'input material membership')
|
||||
for pin in needed:
|
||||
material = supplied_file(directory, descriptor['materials'][pin['path']])
|
||||
require(material.stat().st_size == pin['bytes'] and sha(material) == pin['sha256'], 'input bytes')
|
||||
require(sha(supplied_file(directory, descriptor['wrapper'])) == native['wrapper_sha256'], 'wrapper bytes')
|
||||
require(runner_paths, 'runner inputs missing')
|
||||
require(index['versions'] == {'registered': REGISTERED_COMMIT, 'execution_origin': EXECUTION_ORIGIN,
|
||||
'tested': TESTED_PRODUCT}, 'evidence version roles')
|
||||
return composed, {'role': role, 'actual_head': commit, 'actual_tree': actual_tree,
|
||||
'submission': submitted, 'main': main, 'existing_metadata': metadata,
|
||||
'manifest_sha256': manifest_digest(product), 'runner_paths': runner_paths,
|
||||
'tested_product': TESTED_PRODUCT}
|
||||
|
||||
|
||||
def function_bytes(data):
|
||||
"""Top-level named func through next named func, preserving every raw byte.
|
||||
|
||||
@@ -366,6 +495,10 @@ def boundary_conditions(path, function):
|
||||
|
||||
|
||||
def applicability(index, spec, source, head):
|
||||
tested = index.get('versions', {}).get('tested')
|
||||
require(isinstance(tested, str) and tree_entries(tested) and
|
||||
product_manifest(tree_entries(tested)) == product_manifest(tree_entries(head)),
|
||||
'wrong tested revision')
|
||||
registered = spec['current_source_pins']
|
||||
require(index.get('registered_pins') == registered, 'registered pin declaration')
|
||||
for path, digest in registered.items():
|
||||
@@ -805,6 +938,148 @@ def verify_native(base):
|
||||
verified_conditions=['dependency_stop', 'recovery_completion', 'paused_midnight'])
|
||||
|
||||
|
||||
def verify_shift_completion(base):
|
||||
"""C's first 18:00 transaction, never the paid-midnight 1442 sale."""
|
||||
for row in load(safe(base, 'SOURCE_MANIFEST.json'))['files']:
|
||||
native_file(base, row['copy'], row)
|
||||
require(native_applicability(base) == TESTED_PRODUCT, 'shift tested revision')
|
||||
pids = native_ownership(base)
|
||||
require([pids['actual-native/' + phase] for phase in NATIVE_RUNS['actual-native']]
|
||||
== [77462, 77504, 77536], 'shift ended PID identity')
|
||||
inputs = load(safe(base, 'actual-native/runner-input.json'))
|
||||
expected = product_manifest(tree_entries(TESTED_PRODUCT))
|
||||
require(len(inputs['source_before']) == 1338 and
|
||||
{p: {'bytes': v['bytes'], 'sha256': v['sha256']} for p, v in inputs['source_before'].items()}
|
||||
== expected, 'shift complete native source')
|
||||
prefix = 'actual-native/order-evidence/'
|
||||
observations = load(safe(base, prefix + 'observations.json'))
|
||||
labels = ['first-before-17-59', 'first-18-00-before-facility', 'first-18-00-after-facility',
|
||||
'first-18-00-after-staff', 'first-18-00-tick-complete', 'first-18-01-tick-complete']
|
||||
points = []
|
||||
previous_ledger = None
|
||||
service_id = None
|
||||
paid_rows = None
|
||||
original_service = None
|
||||
completed_service = None
|
||||
for i, label in enumerate(labels):
|
||||
rows = [r for r in observations['observations'] if r['label'] == label]
|
||||
require(len(rows) == 1, 'shift phase membership')
|
||||
observation = rows[0]
|
||||
snapshot = load(safe(base, prefix + label + '.json'))
|
||||
minute = [1079, 1080, 1080, 1080, 1080, 1081][i]
|
||||
require(snapshot['clock']['absolute_minute'] == observation['minute'] == minute, 'shift phase clock')
|
||||
state = snapshot['systems']['runtime']
|
||||
service = observation['service']
|
||||
if i == 0:
|
||||
service_id = service['service_id']
|
||||
original_service = service
|
||||
identity = ('service_id', 'request_id', 'facility_id', 'guest_ids', 'inventory_reservations',
|
||||
'price_snapshot', 'duration_minutes', 'started_at', 'staff_ids')
|
||||
require(all(service[k] == original_service[k] for k in identity), 'shift original service identity')
|
||||
require(service['service_id'] == service_id and service['elapsed_minutes'] == (44 if i < 2 else 45)
|
||||
and service['duration_minutes'] == 45 and service['price_snapshot'] == 25,
|
||||
'shift service identity/progress')
|
||||
candidates = state['facilities']['service_history'] + [s for f in state['facilities']['instances']
|
||||
for s in f['active_services']]
|
||||
require([s for s in candidates if s['service_id'] == service_id] == [service], 'shift raw service join')
|
||||
require(observation['reservations'] == state['inventory'], 'shift inventory join')
|
||||
reserved = [r for r in state['inventory']['reservations'] if r['reservation_id'] in service['inventory_reservations']]
|
||||
require(reserved and len(reserved) == len(service['inventory_reservations']) and all(
|
||||
r['requester_id'] == service['request_id'] and r['state'] == ('ACTIVE' if i < 2 else 'CONSUMED')
|
||||
and r['terminal_at'] == (-1 if i < 2 else 1080) for r in reserved), 'shift reservation join')
|
||||
day2 = ['p04.order.server.a', 'p04.order.server.b']
|
||||
require(observation['active_staff'] == (day2 if i < 3 else []), 'shift DAY2 before/after handover')
|
||||
facility = [f for f in state['facilities']['instances'] if f['instance_id'] == service['facility_id']]
|
||||
require(len(facility) == 1 and facility[0]['active_staff_ids'] == observation['active_staff'],
|
||||
'shift full-state active staff join')
|
||||
require([w['staff']['staff_id'] for w in observation['workers']] == day2, 'shift worker identity set')
|
||||
for worker in observation['workers']:
|
||||
require(worker['staff'] in state['staff']['staff'],
|
||||
'shift worker raw join')
|
||||
if i < 3:
|
||||
require(worker['shift'] in state['staff']['shifts'] and worker['is_present'] is True and worker['shift']['kind'] == 'DAY' and
|
||||
worker['shift']['end_at'] == 1080 and worker['shift']['actual_ended_at'] == -1,
|
||||
'shift original DAY worker present')
|
||||
else:
|
||||
ended = [r for r in state['staff']['shifts'] if r['staff_id'] == worker['staff']['staff_id']]
|
||||
require(worker['shift'] == {} and worker['is_present'] is False and
|
||||
worker['staff']['state'] == 'OFF_DUTY' and len(ended) == 1 and
|
||||
ended[0]['actual_ended_at'] == ended[0]['end_at'] == 1080,
|
||||
'shift normal handover history')
|
||||
ledger = state['economy']['entries']
|
||||
sale = [r for r in ledger if r['category'] == 'SERVICE_SALE']
|
||||
if i < 2:
|
||||
require(sale == [] and observation['receipts'] == [], 'shift precompletion charge')
|
||||
else:
|
||||
require(service['state'] == 'COMPLETED' and service['completed_at'] == 1080 and len(sale) == 1,
|
||||
'shift single completion')
|
||||
transaction = sale[0]
|
||||
require(transaction['transaction_id'] == 'ledger_00000006' and transaction['amount'] == 25 and
|
||||
transaction['absolute_minute'] == 1080 and transaction['source_entity_id'] == service['facility_id']
|
||||
and transaction['credit_account'] == 'GUEST_WALLET:' + service['guest_ids'][0], 'shift sale identity')
|
||||
receipts = receipt_rows(observation['receipts'])
|
||||
require(receipts == [r for r in ledger if r['transaction_id'] == 'ledger_00000006'], 'shift receipt raw join')
|
||||
require([r for r in state['economy']['idempotency'] if r['key'] == 'service.payment.' + service_id]
|
||||
== [{'key': 'service.payment.' + service_id, 'transaction_id': 'ledger_00000006'}],
|
||||
'shift idempotency join')
|
||||
if i == 2:
|
||||
completed_service = service
|
||||
paid_rows = observation['receipts']
|
||||
require(paid_rows == observations['first_receipts'] and paid_rows[0]['staff_at_receipt'] == day2,
|
||||
'shift receipt precedes handover')
|
||||
else:
|
||||
require(service == completed_service and ledger == previous_ledger and
|
||||
observation['receipts'] == paid_rows, 'shift extra charge/completion')
|
||||
previous_ledger = ledger
|
||||
points.append(label)
|
||||
return {'verified_conditions': ['shift_completion'], 'phases': points, 'transaction_id': 'ledger_00000006'}
|
||||
|
||||
|
||||
def combine_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
|
||||
establish candidate applicability, and cannot grant a successful whole gate.
|
||||
"""
|
||||
import importlib.util
|
||||
module_path = ROOT / DOC_SCOPE / 'p04_native_series.py'
|
||||
module_spec = importlib.util.spec_from_file_location('p04_series', module_path)
|
||||
series = importlib.util.module_from_spec(module_spec)
|
||||
module_spec.loader.exec_module(series)
|
||||
c_base = directory / 'audit-support/native-first-current'
|
||||
require(native == verify_native(c_base), 'C result must be recomputed from raw')
|
||||
base = directory / 'audit-support/p04-raw-collect-r20'
|
||||
manifest_path = safe(base, 'MANIFEST.json')
|
||||
manifest = load(manifest_path)
|
||||
require(manifest['protocol'] == 'p04-native-series-collection-v1' and
|
||||
manifest['relocation_manifest_sha256'] == series.MANIFEST_SHA256,
|
||||
'series relocation binding')
|
||||
require(set(manifest['series']) == set(series.RUNS), 'series manifest membership')
|
||||
shift = verify_shift_completion(c_base)
|
||||
verified = set(native['verified_conditions']) | set(shift['verified_conditions'])
|
||||
bindings = {}
|
||||
for name in series.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'] and
|
||||
binding['relocation_manifest_sha256'] == series.MANIFEST_SHA256, 'series manifest SHA binding')
|
||||
recorded = load(path)
|
||||
require(recorded['verifier_sha256'] == sha(module_path), 'series verifier changed since collection')
|
||||
actual = getattr(series, 'verify_' + name)(directory)
|
||||
require({k: v for k, v in recorded.items() if k != 'verifier_sha256'} == actual,
|
||||
'series raw result/reference drift')
|
||||
verified.update(actual['verified_conditions'])
|
||||
bindings[name] = binding['sha256']
|
||||
return {'verified_conditions': sorted(verified), 'series_manifest_sha256': sha(manifest_path),
|
||||
'C_source_manifest_sha256': sha(safe(c_base, 'SOURCE_MANIFEST.json')),
|
||||
'C_provenance_sha256': sha(safe(c_base, 'OWNERSHIP_RAW_PROVENANCE.json')),
|
||||
'series_bindings': bindings, 'relocation_manifest_sha256': series.MANIFEST_SHA256,
|
||||
'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.
|
||||
@@ -812,14 +1087,23 @@ def verify(directory):
|
||||
require(sha(SPEC) == SPEC_HASH or (spec_bytes.endswith(b'\n') and
|
||||
hashlib.sha256(spec_bytes[:-1]).hexdigest() == SPEC_HASH), 'dispatch spec pin mismatch')
|
||||
spec = load(SPEC)
|
||||
evidence = directory / 'p04-evidence'
|
||||
evidence = Path(os.environ.get('P04_EVIDENCE_DIR', str(directory / 'p04-evidence'))).absolute()
|
||||
require(not evidence.is_symlink(), 'symlink evidence directory')
|
||||
index = load(safe(evidence, 'index.json'))
|
||||
require(type(index.get('schema_version')) is int and index['schema_version'] == 1, 'schema_version')
|
||||
require(type(index.get('schema_version')) is int and index['schema_version'] in (1, 2), 'schema_version')
|
||||
require(index.get('task_id') == 'P04-01' and index.get('formal_acceptance') is False, 'task/acceptance')
|
||||
checker_commit = git_bytes('rev-parse', 'HEAD').decode().strip()
|
||||
require(index.get('candidate_commit') == checker_commit, 'checker invocation commit mismatch')
|
||||
head, target_result = verify_product_target(index, directory, checker_commit)
|
||||
head, target_result = verify_roles(index, directory)
|
||||
if index['schema_version'] == 2:
|
||||
import importlib.util
|
||||
module_path = ROOT / DOC_SCOPE / 'build_p04_index.py'
|
||||
module_spec = importlib.util.spec_from_file_location('p04_index', module_path)
|
||||
builder = importlib.util.module_from_spec(module_spec)
|
||||
module_spec.loader.exec_module(builder)
|
||||
expected = builder.payload(directory, sys.modules[__name__])
|
||||
require(index == expected, 'forged index/raw mapping differs from recomputation')
|
||||
require(not index['raw_conditions']['missing_conditions'], 'uncollected original boundaries: ' +
|
||||
', '.join(index['raw_conditions']['missing_conditions']))
|
||||
return target_result
|
||||
source = index.get('source_map')
|
||||
applicability(index, spec, source, head)
|
||||
oldmap = load(ROOT / 'docs/plans/original-completion-2026-10-02/execution/p04-01-input-r01/historical-source-map.json')
|
||||
@@ -903,23 +1187,37 @@ def verify(directory):
|
||||
require(native['production_commit'] == target_result['tested_product'], 'native production role mismatch')
|
||||
# This adapter covers only the supplied dependency/formal series. Never
|
||||
# promote it to the missing original scenarios through scalar booleans.
|
||||
missing = (set(REQUIRED) | {'EV'}) - set(native['verified_conditions'])
|
||||
combined = combine_native_series(directory, native)
|
||||
missing = set(combined['missing_conditions'])
|
||||
require(not missing, 'uncollected original boundaries: ' + ', '.join(sorted(missing)) +
|
||||
'; formal_original_credit=0')
|
||||
return target_result
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--verify-only', action='store_true', required=True)
|
||||
parser.parse_args()
|
||||
mode = parser.add_mutually_exclusive_group(required=True)
|
||||
mode.add_argument('--verify-only', action='store_true')
|
||||
mode.add_argument('--verify-series-only', action='store_true', help='Read-only Stage R composition; always leaves Stage A pending')
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
require(bool(os.environ.get('BUILD_OUTPUT_DIR')), 'BUILD_OUTPUT_DIR required')
|
||||
if args.verify_series_only:
|
||||
directory = Path(os.environ['BUILD_OUTPUT_DIR']).absolute()
|
||||
native = verify_native(directory / 'audit-support/native-first-current')
|
||||
result = combine_native_series(directory, native)
|
||||
result.update(task_id='P04-01', machine_verified=False,
|
||||
error='candidate binding stage A pending; uncollected original boundaries: ' +
|
||||
', '.join(result['missing_conditions']))
|
||||
print(json.dumps(result, ensure_ascii=False, sort_keys=True))
|
||||
return 1
|
||||
with isolated_objects():
|
||||
verify(Path(os.environ['BUILD_OUTPUT_DIR']).resolve())
|
||||
result = verify(Path(os.environ['BUILD_OUTPUT_DIR']).resolve())
|
||||
except (ValueError, OSError, KeyError, TypeError, IndexError, AttributeError, subprocess.SubprocessError) as exc:
|
||||
print(json.dumps({'task_id': 'P04-01', 'machine_verified': False, 'formal_acceptance': False, 'error': str(exc)}, ensure_ascii=False))
|
||||
return 1
|
||||
print(json.dumps({'task_id': 'P04-01', 'machine_verified': True, 'formal_acceptance': False}))
|
||||
print(json.dumps({'task_id': 'P04-01', 'machine_verified': True, 'formal_acceptance': False,
|
||||
'role': result['role'], 'actual_head': result['actual_head']}))
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user