Files
ARCADIA-Studio/harness/experiments/analysis-source-s2b-windows-20260913/archive/evidence/.local/admit-analysis-s2b-gate.py
T

132 lines
8.2 KiB
Python

"""Admit S2b list/focused gates against b2's admitted129 plus thirteen fixed names.
Usage: NAME [ADMITTED_LIST_NAME SELECTOR], or --check-source for read-only setup.
Never runs a compiler/test. Full-suite failures cannot receive a pass receipt.
"""
from pathlib import Path
import hashlib, json, re, subprocess, sys
base = Path(__file__).resolve().parent.parent
root = base / '.local/analysis-core-worktree-20260911'
folder = base / '.local/analysis-source-gates-20260913'
baseline_source = 'b2c970b4673e062e47eadd12906d2316c4b1a7b3'
prefix = ['cargo', 'test', '--locked', '-p', 'oa-core', '--lib']
scopes = ['Cargo.toml', 'Cargo.lock', 'rust-toolchain.toml', '.cargo', 'build', 'crates', 'assets', 'docs', 'examples', 'harness/fixtures']
new_names = {'language::analysis_source::lower::tests::' + name for name in [
'staged_oa_and_sa_lowering_match_complete_independent_17_uuid_oracles',
'forward_cross_unit_resolution_keeps_original_offsets_and_shared_work',
'all_thirteen_expression_variants_lower_to_real_typed_values_and_admit',
'call_sites_and_parameter_scopes_preserve_distinct_original_occurrences',
'missing_ids_require_stabilization_without_uuid_or_budget_churn',
'duplicate_global_aliases_and_ids_fail_before_body_resolution',
'typed_reference_domains_unknown_names_and_parameter_scope_fail_at_tokens',
'ordinary_non_element_categories_are_collected_and_never_property_fallbacks',
'structural_lowering_defers_type_purity_layer_and_argument_sets_to_admission',
'lowering_phase_bounds_count_ordinary_globals_and_scoped_parameters_together',
'affine_kinds_optional_fields_list_signatures_and_unused_unbound_definitions_survive',
'duplicate_file_keys_and_exhausted_shared_budget_cannot_enter_lowering',
'iterative_lowering_preserves_128_deep_and_1024_wide_accepted_expressions',
]}
assert len(new_names) == 13
def digest(raw): return hashlib.sha256(raw).hexdigest()
def safe_name(name):
assert re.fullmatch(r'[a-zA-Z0-9-]+', name)
return name
def raw(name, suffix): return (folder / (safe_name(name) + suffix)).read_bytes()
def record(name): return json.loads(raw(name, '.result.json'))
def receipt(name): return json.loads(raw(name, '.admission.json'))
def verify_receipt(name, admission):
for key, suffix in [('result_sha256', '.result.json'), ('inputs_sha256', '.inputs.json'), ('log_sha256', '.log')]:
assert admission[key] == digest(raw(name, suffix)), (name, key)
baseline = record('list-b2c970b')
baseline_admission = receipt('list-b2c970b')
verify_receipt('list-b2c970b', baseline_admission)
assert baseline['exit'] == 0 and baseline['source'] == baseline['head_after'] == baseline_source and not baseline['changed_inputs']
assert baseline_admission['source'] == baseline_source and baseline_admission['mode'] == 'list'
assert baseline_admission['artifact'] == baseline['artifacts'][0]
assert baseline_admission['admission_helper_sha256'] == digest((base / '.local/admit-analysis-s2a-gate.py').read_bytes())
baseline_names = re.findall(r'^([^\r\n]+): test\r?$', raw('list-b2c970b', '.log').decode(), re.M)
assert baseline_names == baseline['listing_members'] == baseline_admission['names']
assert len(baseline_names) == len(set(baseline_names)) == 129
assert not (set(baseline_names) & new_names)
expected_names = set(baseline_names) | new_names
assert len(expected_names) == 142
name = sys.argv[1]
check_only = name == '--check-source'
current = subprocess.check_output(['git', 'rev-parse', 'HEAD'], cwd=root).decode().strip()
rec = None if check_only else record(name)
source = current if check_only else rec['source']
assert re.fullmatch(r'[0-9a-f]{40}', source)
assert current == source
subprocess.run(['git', 'merge-base', '--is-ancestor', baseline_source, source], cwd=root, check=True)
paths = subprocess.check_output(['git', 'ls-tree', '-r', '--name-only', source, *scopes], cwd=root).decode().splitlines()
assert paths and len(paths) == len(set(paths))
blobs = subprocess.check_output(['git', 'cat-file', '--batch'], cwd=root, input=''.join(f'{source}:{p}\n' for p in paths).encode())
offset, expected_inputs, lower_tests = 0, [], None
for path in paths:
end = blobs.index(b'\n', offset)
_, kind, size = blobs[offset:end].split(); size = int(size)
data = blobs[end + 1:end + 1 + size]
assert kind == b'blob' and (root / path).read_bytes() == data, path
expected_inputs.append({'path': path, 'bytes': size, 'sha256': digest(data)})
if path == 'crates/oa-core/src/language/analysis_source/lower/tests.rs': lower_tests = data.decode()
offset = end + size + 2
assert offset == len(blobs) and lower_tests is not None
authored_names = {'language::analysis_source::lower::tests::' + n for n in re.findall(r'#\[test\]\s*fn (\w+)\(', lower_tests)}
assert authored_names == new_names
if check_only:
assert len(sys.argv) == 2
print(json.dumps({'source': source, 'git_blob_verified_inputs': len(expected_inputs), 'baseline_members': 129, 'fixed_new_members': 13, 'expected_listing': 142, 'helper_sha256': digest(Path(__file__).read_bytes()), 'receipt_written': False}))
sys.exit(0)
assert rec['exit'] == 0 and not rec['changed_inputs'] and rec['head_after'] == source
assert rec['inputs'] == name + '.inputs.json'
inputs = json.loads(raw(name, '.inputs.json'))
assert inputs['source'] == source and inputs['inputs'] == expected_inputs
assert len(rec['artifacts']) == 1
artifact = rec['artifacts'][0]
data = Path(artifact['path']).read_bytes()
assert len(data) == artifact['bytes'] and digest(data) == artifact['sha256']
log = raw(name, '.log').decode()
executables = re.findall(r'Running unittests [^\r\n]+ \(([^\r\n]+\.exe)\)', log)
assert len(executables) == 1
executable = Path(executables[0])
if not executable.is_absolute(): executable = root / executable
assert executable.resolve() == Path(artifact['path']).resolve()
if rec['command'] == prefix + ['--', '--list']:
assert len(sys.argv) == 2
names = re.findall(r'^([^\r\n]+): test\r?$', log, re.M)
assert names == rec['listing_members'] and len(names) == len(set(names)) == rec['listing_count'] == 142
assert set(names) == expected_names
assert re.findall(r'^(\d+) tests, (\d+) benchmarks\s*$', log, re.M) == [('142', '0')]
mode = 'list'
else:
assert len(sys.argv) == 4, 'Only explicit focused selections can be admitted.'
listing_name, selector = sys.argv[2:]
assert selector and rec['command'] == prefix + [selector, '--', '--test-threads=1']
listing = record(listing_name); admission = receipt(listing_name)
verify_receipt(listing_name, admission)
assert admission['mode'] == 'list' and admission['source'] == listing['source'] == source
assert admission['artifact'] == artifact and listing['artifacts'] == [artifact]
assert admission['admission_helper_sha256'] == digest(Path(__file__).read_bytes())
assert listing['exit'] == 0 and set(listing['listing_members']) == expected_names
assert admission['names'] == listing['listing_members'] and len(admission['names']) == 142
names = [n for n in listing['listing_members'] if selector in n]
actual = re.findall(r'^test ([^\r\n]+) \.\.\. (ok|FAILED|ignored)\s*$', log, re.M)
assert names and len(actual) == len({n for n, _ in actual}) == len(names)
assert {n for n, _ in actual} == set(names) and all(status == 'ok' for _, status in actual)
assert re.findall(r'test result: ok\. (\d+) passed; (\d+) failed; (\d+) ignored; (\d+) measured; (\d+) filtered out;', log) == [(str(len(names)), '0', '0', '0', str(142 - len(names)))]
mode = 'focused'
admission = {'source': source, 'mode': mode, 'artifact': artifact, 'names': names,
'result_sha256': digest(raw(name, '.result.json')), 'inputs_sha256': digest(raw(name, '.inputs.json')),
'log_sha256': digest(raw(name, '.log')), 'verified_inputs': len(expected_inputs),
'admission_helper_sha256': digest(Path(__file__).read_bytes()),
'baseline_source': baseline_source, 'baseline_result_sha256': digest(raw('list-b2c970b', '.result.json')),
'baseline_admission_sha256': digest(raw('list-b2c970b', '.admission.json'))}
with (folder / (name + '.admission.json')).open('x', encoding='utf-8', newline='\n') as stream:
stream.write(json.dumps(admission, indent=2) + '\n')
print(json.dumps({'name': name, 'mode': mode, 'members': len(names), 'verified_inputs': len(expected_inputs), 'source': source}))