the-custodian/docs/changes/netkingdom-target-2026-10-17/verify_rollout_close.py

60 lines
3.4 KiB
Python

"""Read back committed Custodian bindings and retain unrelated-work checks."""
from pathlib import Path
import hashlib
import json
import re
import subprocess
import urllib.request
import yaml
ROOT = Path('/home/worsch/the-custodian')
BASE = Path(__file__).resolve().parent
BACKUP = BASE / 'custodian-publication-backup'
def git(*args):
return subprocess.check_output(['git', '-C', str(ROOT), *args], stderr=subprocess.PIPE).decode().strip()
def get(path):
return json.load(urllib.request.urlopen('http://127.0.0.1:8000' + path, timeout=20))
head = git('rev-parse', 'HEAD')
assert git('ls-remote', 'origin', 'refs/heads/main').split()[0] == head
projection = json.loads((BASE / 'rollout-custodian-projection.json').read_text())
receipt = projection['receipt']
assert projection['status'] == 'applied' and projection['commit'] == head
assert receipt['instance_role'] == 'primary' and receipt['instance_label'] == 'railiance01'
assert receipt['expected_commit'] == receipt['derived_commit'] == head
health = get('/state/health')
assert health['instance_role'] == 'primary' and health['instance_label'] == 'railiance01'
path = ROOT / 'workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md'
raw = path.read_text()
assert git('show', head + ':' + str(path.relative_to(ROOT))) == raw.strip()
front = yaml.safe_load(raw.split('---', 2)[1])
tasks = [yaml.safe_load(value) for value in re.findall(r'```task\n(.*?)\n```', raw, re.S)]
snapshot = get('/repos/the-custodian/work-record-projection/snapshot')
plan = next(p for p in snapshot['workplans'] if p['id'] == front['state_hub_workstream_id'])
assert plan['status'] == front['status'] == 'active'
actual = {t['id']: t for t in snapshot['tasks'] if t.get('workplan_id', t.get('workstream_id')) == plan['id']}
assert len(actual) == len(tasks) == 6
for task in tasks:
row = actual[task['state_hub_task_id']]
assert row['record_id'] == task['id'] and row['status'] == task['status']
for name, entry in json.loads((BACKUP / 'originals.json').read_text()).items():
assert (ROOT / name).read_bytes() == (BACKUP / (name + '.worktree')).read_bytes()
assert git('ls-files', '--stage', '--', name) == entry.strip()
assert all(hashlib.sha256((ROOT / name).read_bytes()).hexdigest() == pin
for name, pin in json.loads((BACKUP / 'other-dirty-hashes.json').read_text()).items())
proposal = BASE / 'guard-successor-review-r2/proposal-metadata.json'
assert hashlib.sha256(proposal.read_bytes()).hexdigest() == '5d0ddebc21bcb035809cc8b57f4c2e1ba8ed09204be5b965460e178a90913f1e'
for bound in json.loads(proposal.read_text())['bound_receipts']:
assert hashlib.sha256(Path(bound['path']).read_bytes()).hexdigest() == bound['sha256']
pending = get('/decisions/df703266-6719-4c04-ae1b-ba9afd3bca1c')
assert pending['decision_type'] == 'pending' and pending['status'] == 'open'
assert pending['decided_by'] is None and pending['decided_at'] is None
result = {'status': 'verified', 'commit': head, 'remote_exact': True,
'primary': 'primary/railiance01', 'projection_expected_equals_derived': True,
'custodian_task_bindings': len(tasks), 'unrelated_index_and_worktree_preserved': True,
'pending_proposal_revision': 2, 'pending_proposal_not_approved_or_executed': True,
'proposal_bound_receipts_unchanged': True, 'native_target_gates_closed': 0}
(BASE / 'rollout-close-verification.json').write_text(json.dumps(result, indent=2) + '\n')
print(json.dumps(result))