"""Package verified closeout instructions and update only local progress docs.""" from pathlib import Path from datetime import datetime, timezone import hashlib import json import zipfile ROOT = Path(__file__).resolve().parents[1] DOCS = Path('F:/文档/工作坊当前资料') OUT = ROOT / 'work/S5-classroom-completion-20261103' PACKAGE = DOCS / 'ksf-S5-classroom-completion-20261103.zip' BACKUP = ROOT / 'work/S5-progress-before-completion-preparation-20261103' audit = json.loads((ROOT / 'work/S5-completion-live-preflight-20261103.json').read_text(encoding='utf-8')) simulation = json.loads((ROOT / 'work/S5-completion-isolated-simulation-20261103.json').read_text(encoding='utf-8')) assert audit['ok'] and simulation['ok'] assert audit['productionBusinessWrites'] == simulation['productionWrites'] == 0 assert audit['checksPassed'] == simulation['checksPassed'] == 9 assert audit['currentStage'] == 'S5' and audit['progressState'] == 'in_progress' assert not PACKAGE.exists() and not BACKUP.exists() sha = lambda data: hashlib.sha256(data).hexdigest() old_names = ['52-S5桌面方案审阅与定稿.md', '53-发给运维001-S5方案与报告准备.txt', '54-发给王刚001-S5方案与课堂报告保存.txt', '55-S5方案与课堂报告独立验收结果.md', 'ksf-S5-classroom-next-20261103.zip'] old_hashes = {n: sha((DOCS / n).read_bytes()) for n in old_names} preflight_path = OUT / 'preflight.json' preflight = json.loads(preflight_path.read_text(encoding='utf-8')) preflight.pop('localStructureOnly') preflight.update({ 'scope': 'Local material preparation plus separately recorded production reads and RAM simulation', 'liveReadOnlyPreflight': {'at': audit['at'], 'checksPassed': audit['checksPassed'], 'readCalls': audit['readCalls'], 'currentStage': 'S5', 'progressState': 'in_progress', 'artifactCount': 3, 'eventCount': 7, 'pendingQuestionCount': 13, 'futureWriteAuditMatches': 0, 'productionBusinessWrites': 0}, 'isolatedSimulation': {'at': simulation['at'], 'checksPassed': simulation['checksPassed'], 'commandSteps': 3, 'negativeControls': simulation['negativeControls'], 'idempotencyControls': simulation['idempotencyControls'], 'productionCalls': 0, 'productionWrites': 0, 'expectedAfter': simulation['expectedAfter']}, 'currentMessageIdentityVerifiedByCodex': False, 'remoteFilesystemAndProcessesInspected': False, }) preflight_path.write_text(json.dumps(preflight, ensure_ascii=False, indent=2) + '\n', encoding='utf-8', newline='\n') with (OUT / '55-S5方案与课堂报告独立验收结果.md').open('xb') as stream: stream.write((DOCS / '55-S5方案与课堂报告独立验收结果.md').read_bytes()) with (OUT / '56-课堂总结与完成条件.md').open('a', encoding='utf-8', newline='\n') as stream: stream.write(''' 独立准备结果:本轮生产只读预检9项通过,实际发起9次只读调用,项目仍S5/in_progress、3成果/1概念/7事件、13问题;未来完成写键没有成功审计。当前部署的转阶段和状态读取命令及相关会话/事件/幂等处理与核查实现一致。Codex未独立核远端文件/进程或本条企微身份。 用本次捕获的部署代码和字段表完成本地内存模拟9项:3步CLI流程、3个前提反向控制、2个幂等控制通过。模拟完成后仍3报告/1概念/13问题,只增加第8条completed事件与1条成功审计。模拟重放仅在隔离内存进行,不允许据此自动重试生产。没有生产完成写入或本轮生产浏览器完成态验收;后续仍按57/58执行和回读。 独立证据:F:/kangshifu-board/work/S5-completion-live-preflight-20261103.json、F:/kangshifu-board/work/S5-completion-isolated-simulation-20261103.json。历史55号及其首次失败/后续验收证据保持原样。 ''') with (OUT / 'README.txt').open('a', encoding='utf-8', newline='\n') as stream: stream.write('已完成9项生产只读预检(9次只读调用)及9项内存模拟;未执行生产完成写入。57号远端落地预检和58号真实消息执行仍待完成。\n') names = sorted(p.name for p in OUT.iterdir() if p.is_file()) assert len(names) == 8 for name in names: text = (OUT / name).read_text(encoding='utf-8') for forbidden in ['-----BEGIN', 'X-Parse-Master-Key', 'signingSecret']: assert forbidden not in text manifest = ''.join(f'{sha((OUT / name).read_bytes())} {name}\n' for name in names) with (OUT / 'FILES.sha256').open('x', encoding='utf-8', newline='\n') as stream: stream.write(manifest) with zipfile.ZipFile(PACKAGE, 'x', compression=zipfile.ZIP_DEFLATED) as archive: for name in [*names, 'FILES.sha256']: archive.write(OUT / name, arcname=name) with zipfile.ZipFile(PACKAGE) as archive: assert len(archive.infolist()) == 9 assert archive.testzip() is None for name in names: assert archive.read(name) == (OUT / name).read_bytes() assert sha(archive.read(name)) == sha((OUT / name).read_bytes()) for name in ['56-课堂总结与完成条件.md', '57-发给运维001-课堂完成准备.txt', '58-发给王刚001-课堂完成与回读.txt']: assert not (DOCS / name).exists() with (DOCS / name).open('xb') as stream: stream.write((OUT / name).read_bytes()) originals = {name: (DOCS / name).read_bytes() for name in ['01-工作进展汇报.txt', '02-后续待补资料.md', 'README.md']} BACKUP.mkdir() for name, content in originals.items(): with (BACKUP / name).open('xb') as stream: stream.write(content) with (BACKUP / 'manifest.json').open('x', encoding='utf-8') as stream: json.dump({name: sha(content) for name, content in originals.items()}, stream, ensure_ascii=False, indent=2) progress = originals['01-工作进展汇报.txt'].decode('utf-8-sig') old = '下一步可整理课堂总结与完成条件,再执行相应状态操作;本次没有自动completed。' assert old in progress progress = progress.replace(old, '课堂总结与完成条件已整理为56号,1份完成模板、57号运维单、58号王刚执行单及固定材料包已备齐;9项生产只读预检和9项隔离模拟通过。本轮仍S5/in_progress,没有完成写入。下一步先交57号+收尾包给运维落地预检,再由王刚001按58号真实消息执行1写2读,最终由Codex核完成态。', 1) progress += f'\n课堂收尾固定包:{PACKAGE.name},{PACKAGE.stat().st_size}字节,SHA256={sha(PACKAGE.read_bytes())};9条目、清单8/8核验。更新前快照:{BACKUP.as_posix()}/。\n' needs = originals['02-后续待补资料.md'].decode('utf-8-sig') old = '下一步可整理课堂总结与完成条件;不重跑53/54号,不补存新版本。' assert old in needs needs = needs.replace(old, '56号已整理课堂总结,57/58号及收尾固定包已准备并通过9项生产只读预检、9项内存模拟;当前仍S5/in_progress,未完成写入。先交57号与包运维落地,通过后58号由王刚001在真实消息执行1写2读。预期只新增completed事件/成功审计,13问题不变;不重跑53/54号,不补存新版本。', 1) readme = originals['README.md'].decode('utf-8-sig') old = '下一步可整理课堂总结和完成条件。' assert old in readme readme = readme.replace(old, '56号课堂总结、57/58号和收尾固定包已准备;9项生产只读预检、9项内存模拟通过,尚未执行完成写入。下一步交57号+包运维落地预检,再按58号真实执行1写2读,预期S5/completed并保留13问题。', 1) line = '- 55-S5方案与课堂报告独立验收结果.md:' assert line in readme readme = readme.replace(line, '- 56-课堂总结与完成条件.md:当前收尾范围,保留13问题、历史requestId偏差和研究/确认边界。\n- 57-发给运维001-课堂完成准备.txt:下一步;落地1份固定模板、核合同/归属/状态/回执/在途,不代跑完成。\n- 58-发给王刚001-课堂完成与回读.txt:57号通过后在真实消息执行3步;project-status→project-progress→project-status,1写2读,只更新课堂完成状态。\n- ksf-S5-classroom-completion-20261103.zip:9条目、清单8/8;模板两ID为null不可直接提交,生产未完成。\n' + line, 1) for name, text in {'01-工作进展汇报.txt': progress, '02-后续待补资料.md': needs, 'README.md': readme}.items(): assert '仍S5/in_progress' in text or 'S5 / in_progress' in text (DOCS / name).write_text(text, encoding='utf-8', newline='\n') for name, digest in old_hashes.items(): assert sha((DOCS / name).read_bytes()) == digest receipt = {'ok': True, 'at': datetime.now(timezone.utc).isoformat(), 'operation': 'prepare-S5-classroom-completion', 'package': str(PACKAGE), 'bytes': PACKAGE.stat().st_size, 'sha256': sha(PACKAGE.read_bytes()), 'entries': 9, 'manifestFilesVerified': 8, 'templateCount': 1, 'readOnlyPreflightChecks': 9, 'productionReadCalls': 9, 'isolatedSimulationChecks': 9, 'productionBusinessWrites': 0, 'currentStage': 'S5', 'progressState': 'in_progress', 'completionExecuted': False, 'backup': str(BACKUP), 'oldFilesUnchanged': old_hashes} with (ROOT / 'work/S5-completion-package-receipt-20261103.json').open('x', encoding='utf-8') as stream: json.dump(receipt, stream, ensure_ascii=False, indent=2) print(json.dumps(receipt, ensure_ascii=True, indent=2))