package-S5-completion.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. """Package verified closeout instructions and update only local progress docs."""
  2. from pathlib import Path
  3. from datetime import datetime, timezone
  4. import hashlib
  5. import json
  6. import zipfile
  7. ROOT = Path(__file__).resolve().parents[1]
  8. DOCS = Path('F:/文档/工作坊当前资料')
  9. OUT = ROOT / 'work/S5-classroom-completion-20261103'
  10. PACKAGE = DOCS / 'ksf-S5-classroom-completion-20261103.zip'
  11. BACKUP = ROOT / 'work/S5-progress-before-completion-preparation-20261103'
  12. audit = json.loads((ROOT / 'work/S5-completion-live-preflight-20261103.json').read_text(encoding='utf-8'))
  13. simulation = json.loads((ROOT / 'work/S5-completion-isolated-simulation-20261103.json').read_text(encoding='utf-8'))
  14. assert audit['ok'] and simulation['ok']
  15. assert audit['productionBusinessWrites'] == simulation['productionWrites'] == 0
  16. assert audit['checksPassed'] == simulation['checksPassed'] == 9
  17. assert audit['currentStage'] == 'S5' and audit['progressState'] == 'in_progress'
  18. assert not PACKAGE.exists() and not BACKUP.exists()
  19. sha = lambda data: hashlib.sha256(data).hexdigest()
  20. old_names = ['52-S5桌面方案审阅与定稿.md', '53-发给运维001-S5方案与报告准备.txt', '54-发给王刚001-S5方案与课堂报告保存.txt', '55-S5方案与课堂报告独立验收结果.md', 'ksf-S5-classroom-next-20261103.zip']
  21. old_hashes = {n: sha((DOCS / n).read_bytes()) for n in old_names}
  22. preflight_path = OUT / 'preflight.json'
  23. preflight = json.loads(preflight_path.read_text(encoding='utf-8'))
  24. preflight.pop('localStructureOnly')
  25. preflight.update({
  26. 'scope': 'Local material preparation plus separately recorded production reads and RAM simulation',
  27. '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},
  28. 'isolatedSimulation': {'at': simulation['at'], 'checksPassed': simulation['checksPassed'], 'commandSteps': 3, 'negativeControls': simulation['negativeControls'], 'idempotencyControls': simulation['idempotencyControls'], 'productionCalls': 0, 'productionWrites': 0, 'expectedAfter': simulation['expectedAfter']},
  29. 'currentMessageIdentityVerifiedByCodex': False, 'remoteFilesystemAndProcessesInspected': False,
  30. })
  31. preflight_path.write_text(json.dumps(preflight, ensure_ascii=False, indent=2) + '\n', encoding='utf-8', newline='\n')
  32. with (OUT / '55-S5方案与课堂报告独立验收结果.md').open('xb') as stream:
  33. stream.write((DOCS / '55-S5方案与课堂报告独立验收结果.md').read_bytes())
  34. with (OUT / '56-课堂总结与完成条件.md').open('a', encoding='utf-8', newline='\n') as stream:
  35. stream.write('''
  36. 独立准备结果:本轮生产只读预检9项通过,实际发起9次只读调用,项目仍S5/in_progress、3成果/1概念/7事件、13问题;未来完成写键没有成功审计。当前部署的转阶段和状态读取命令及相关会话/事件/幂等处理与核查实现一致。Codex未独立核远端文件/进程或本条企微身份。
  37. 用本次捕获的部署代码和字段表完成本地内存模拟9项:3步CLI流程、3个前提反向控制、2个幂等控制通过。模拟完成后仍3报告/1概念/13问题,只增加第8条completed事件与1条成功审计。模拟重放仅在隔离内存进行,不允许据此自动重试生产。没有生产完成写入或本轮生产浏览器完成态验收;后续仍按57/58执行和回读。
  38. 独立证据:F:/kangshifu-board/work/S5-completion-live-preflight-20261103.json、F:/kangshifu-board/work/S5-completion-isolated-simulation-20261103.json。历史55号及其首次失败/后续验收证据保持原样。
  39. ''')
  40. with (OUT / 'README.txt').open('a', encoding='utf-8', newline='\n') as stream:
  41. stream.write('已完成9项生产只读预检(9次只读调用)及9项内存模拟;未执行生产完成写入。57号远端落地预检和58号真实消息执行仍待完成。\n')
  42. names = sorted(p.name for p in OUT.iterdir() if p.is_file())
  43. assert len(names) == 8
  44. for name in names:
  45. text = (OUT / name).read_text(encoding='utf-8')
  46. for forbidden in ['-----BEGIN', 'X-Parse-Master-Key', 'signingSecret']:
  47. assert forbidden not in text
  48. manifest = ''.join(f'{sha((OUT / name).read_bytes())} {name}\n' for name in names)
  49. with (OUT / 'FILES.sha256').open('x', encoding='utf-8', newline='\n') as stream:
  50. stream.write(manifest)
  51. with zipfile.ZipFile(PACKAGE, 'x', compression=zipfile.ZIP_DEFLATED) as archive:
  52. for name in [*names, 'FILES.sha256']:
  53. archive.write(OUT / name, arcname=name)
  54. with zipfile.ZipFile(PACKAGE) as archive:
  55. assert len(archive.infolist()) == 9
  56. assert archive.testzip() is None
  57. for name in names:
  58. assert archive.read(name) == (OUT / name).read_bytes()
  59. assert sha(archive.read(name)) == sha((OUT / name).read_bytes())
  60. for name in ['56-课堂总结与完成条件.md', '57-发给运维001-课堂完成准备.txt', '58-发给王刚001-课堂完成与回读.txt']:
  61. assert not (DOCS / name).exists()
  62. with (DOCS / name).open('xb') as stream:
  63. stream.write((OUT / name).read_bytes())
  64. originals = {name: (DOCS / name).read_bytes() for name in ['01-工作进展汇报.txt', '02-后续待补资料.md', 'README.md']}
  65. BACKUP.mkdir()
  66. for name, content in originals.items():
  67. with (BACKUP / name).open('xb') as stream:
  68. stream.write(content)
  69. with (BACKUP / 'manifest.json').open('x', encoding='utf-8') as stream:
  70. json.dump({name: sha(content) for name, content in originals.items()}, stream, ensure_ascii=False, indent=2)
  71. progress = originals['01-工作进展汇报.txt'].decode('utf-8-sig')
  72. old = '下一步可整理课堂总结与完成条件,再执行相应状态操作;本次没有自动completed。'
  73. assert old in progress
  74. progress = progress.replace(old, '课堂总结与完成条件已整理为56号,1份完成模板、57号运维单、58号王刚执行单及固定材料包已备齐;9项生产只读预检和9项隔离模拟通过。本轮仍S5/in_progress,没有完成写入。下一步先交57号+收尾包给运维落地预检,再由王刚001按58号真实消息执行1写2读,最终由Codex核完成态。', 1)
  75. progress += f'\n课堂收尾固定包:{PACKAGE.name},{PACKAGE.stat().st_size}字节,SHA256={sha(PACKAGE.read_bytes())};9条目、清单8/8核验。更新前快照:{BACKUP.as_posix()}/。\n'
  76. needs = originals['02-后续待补资料.md'].decode('utf-8-sig')
  77. old = '下一步可整理课堂总结与完成条件;不重跑53/54号,不补存新版本。'
  78. assert old in needs
  79. needs = needs.replace(old, '56号已整理课堂总结,57/58号及收尾固定包已准备并通过9项生产只读预检、9项内存模拟;当前仍S5/in_progress,未完成写入。先交57号与包运维落地,通过后58号由王刚001在真实消息执行1写2读。预期只新增completed事件/成功审计,13问题不变;不重跑53/54号,不补存新版本。', 1)
  80. readme = originals['README.md'].decode('utf-8-sig')
  81. old = '下一步可整理课堂总结和完成条件。'
  82. assert old in readme
  83. readme = readme.replace(old, '56号课堂总结、57/58号和收尾固定包已准备;9项生产只读预检、9项内存模拟通过,尚未执行完成写入。下一步交57号+包运维落地预检,再按58号真实执行1写2读,预期S5/completed并保留13问题。', 1)
  84. line = '- 55-S5方案与课堂报告独立验收结果.md:'
  85. assert line in readme
  86. 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)
  87. for name, text in {'01-工作进展汇报.txt': progress, '02-后续待补资料.md': needs, 'README.md': readme}.items():
  88. assert '仍S5/in_progress' in text or 'S5 / in_progress' in text
  89. (DOCS / name).write_text(text, encoding='utf-8', newline='\n')
  90. for name, digest in old_hashes.items():
  91. assert sha((DOCS / name).read_bytes()) == digest
  92. 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}
  93. with (ROOT / 'work/S5-completion-package-receipt-20261103.json').open('x', encoding='utf-8') as stream:
  94. json.dump(receipt, stream, ensure_ascii=False, indent=2)
  95. print(json.dumps(receipt, ensure_ascii=True, indent=2))