77 lines
4.4 KiB
Python
77 lines
4.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Integrate the approved owner record; preserve the unrelated staged brief."""
|
|
import hashlib
|
|
import json
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
HERE = Path(__file__).resolve().parent
|
|
REPO = Path('/home/worsch/access-engine')
|
|
WP = 'workplans/FLEX-WP-0024-decision-envelope-authenticity.md'
|
|
BRIEF = '.custodian-brief.md'
|
|
def git(*args):
|
|
return subprocess.check_output(['git', '-C', str(REPO), *args])
|
|
def sha(data):
|
|
return hashlib.sha256(data).hexdigest()
|
|
def save(name, data):
|
|
(HERE / name).write_text(json.dumps(data, indent=2) + '\n')
|
|
|
|
meta = json.loads((HERE / 'own-record-metadata.json').read_text())
|
|
assert sha((REPO / WP).read_bytes()) == meta['source_sha256'], 'Workplan preimage changed'
|
|
assert sha((HERE / 'own-record.patch').read_bytes()) == meta['patch_sha256']
|
|
assert git('diff', '--cached', '--name-only').decode().splitlines() == [BRIEF], 'Unexpected staged paths'
|
|
brief_index = git('ls-files', '--stage', '--', BRIEF).decode().strip()
|
|
brief_worktree = (REPO / BRIEF).read_bytes()
|
|
head_before = git('rev-parse', 'HEAD').decode().strip()
|
|
records_before = sha((REPO / 'WORK-RECORDS.md').read_bytes())
|
|
save('integration-preimage.json', {'head': head_before, 'workplan_sha256':meta['source_sha256'],
|
|
'brief_index':brief_index, 'brief_worktree_sha256':sha(brief_worktree),
|
|
'work_records_sha256':records_before, 'staged_paths':[BRIEF]})
|
|
(HERE / 'brief.preexisting.bytes').write_bytes(brief_worktree)
|
|
git('apply', '--check', str(HERE / 'own-record.patch'))
|
|
git('apply', str(HERE / 'own-record.patch'))
|
|
assert sha((REPO / WP).read_bytes()) == meta['proposed_result_sha256']
|
|
assert git('ls-files', '--stage', '--', BRIEF).decode().strip() == brief_index
|
|
assert (REPO / BRIEF).read_bytes() == brief_worktree
|
|
commit_output = git('commit', '--only', '-m', 'docs: record Access owner native execution plan review', '--', WP).decode()
|
|
owner_commit = git('rev-parse', 'HEAD').decode().strip()
|
|
assert git('diff-tree', '--no-commit-id', '--name-only', '-r', owner_commit).decode().splitlines() == [WP]
|
|
assert git('ls-files', '--stage', '--', BRIEF).decode().strip() == brief_index
|
|
assert (REPO / BRIEF).read_bytes() == brief_worktree
|
|
head_brief = git('ls-tree', 'HEAD', '--', BRIEF).decode().split()
|
|
git('update-index', '--cacheinfo', head_brief[0], head_brief[2], BRIEF)
|
|
assert git('diff', '--cached', '--name-only').decode().strip() == ''
|
|
try:
|
|
result = subprocess.run(['statehub', 'fix-consistency', '--repo', 'access-engine',
|
|
'--repo-path', str(REPO), '--no-writeback', '--json'],
|
|
capture_output=True, text=True)
|
|
(HERE / 'sync.stdout.json').write_text(result.stdout)
|
|
(HERE / 'sync.stderr.txt').write_text(result.stderr)
|
|
after_brief = (REPO / BRIEF).read_bytes()
|
|
after_index = git('ls-files', '--stage', '--', BRIEF).decode().strip()
|
|
# Restore only the captured unrelated brief; race-check both before writing.
|
|
assert (REPO / BRIEF).read_bytes() == after_brief
|
|
assert git('ls-files', '--stage', '--', BRIEF).decode().strip() == after_index
|
|
mode, blob, stage_path = brief_index.split(maxsplit=2)
|
|
assert stage_path == '0\t' + BRIEF
|
|
(REPO / BRIEF).write_bytes(brief_worktree)
|
|
git('update-index', '--cacheinfo', mode, blob, BRIEF)
|
|
assert (REPO / BRIEF).read_bytes() == brief_worktree
|
|
assert git('ls-files', '--stage', '--', BRIEF).decode().strip() == brief_index
|
|
save('integration-receipt.json', {'owner_commit':owner_commit,
|
|
'owner_commit_paths':[WP], 'sync_return_code':result.returncode,
|
|
'sync_stdout_sha256':sha(result.stdout.encode()),
|
|
'sync_stderr_sha256':sha(result.stderr.encode()),
|
|
'head_after_sync':git('rev-parse', 'HEAD').decode().strip(),
|
|
'upstream':git('rev-parse', '@{upstream}').decode().strip(),
|
|
'brief_index_exactly_restored':True, 'brief_worktree_exactly_restored':True,
|
|
'work_records_before_sha256':records_before,
|
|
'work_records_after_sha256':sha((REPO / 'WORK-RECORDS.md').read_bytes()),
|
|
'workplan_after_sha256':sha((REPO / WP).read_bytes()),
|
|
'status':git('status','--short').decode(), 'manual_push':False,
|
|
'no_writeback_scope':'Disables C15/C23 status repairs only; brief generation/auto-commit and normal publication still run.'})
|
|
print(json.dumps({'owner_commit':owner_commit,'sync_return_code':result.returncode,
|
|
'brief_restored':True,'manual_push':False}))
|
|
finally:
|
|
# No broad checkout/reset and no suppression of a failed publication.
|
|
pass
|