record_r03.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. """Record the received (truncated) third reply, without reconstructing missing text."""
  2. from pathlib import Path
  3. import hashlib
  4. import json
  5. import re
  6. import shutil
  7. WORK = Path(__file__).resolve().parent
  8. def sha(path):
  9. return hashlib.sha256((WORK / path).read_bytes()).hexdigest()
  10. def main():
  11. snapshot = WORK / 'internal-archive/R02-reviewed'
  12. snapshot.mkdir(parents=True, exist_ok=True)
  13. for path in ['案例样板演示.html', 'demo-build.json', 'browser-checks.json', 'case.json']:
  14. if not (snapshot / path).exists():
  15. shutil.copy2(WORK / path, snapshot / path)
  16. case = json.loads((WORK / 'case.json').read_bytes())
  17. third = next(r for r in case['rounds'] if r['roundId'] == 'R03')
  18. third.update({
  19. 'status': 'reply-received-reviewed-incomplete-tail', 'forwardedConfirmed': None,
  20. 'executionConfirmed': True, 'replyReceived': True,
  21. 'replyPath': 'rounds/R03/reply-verbatim.md', 'replySha256': sha('rounds/R03/reply-verbatim.md'),
  22. 'reviewPath': 'rounds/R03/review.md', 'replyComplete': False,
  23. 'completeness': 'message ends mid-token in section 10; no missing text reconstructed',
  24. 'executionEvidence': 'user-relayed-reply; prompt association inferred from conversation sequence',
  25. 'reportIds': ['KrWLO_yQ0b'], 'reportIdsEvidence': 'operator-reported only',
  26. 'claimsIndependentlyVerified': False,
  27. 'reportedArtifacts': [{'artifactId': 'KrWLO_yQ0b', 'version': 2,
  28. 'savedAndReadBack': 'reported', 'publicBoardVisible': 'reported',
  29. 'independentlyVerifiedHere': False}],
  30. 'receivedArtifact': {'path': 'rounds/R03/artifacts/atlas-received.html',
  31. 'presentationPath': 'rounds/R03/artifacts/atlas-display.html',
  32. **json.loads((WORK / 'rounds/R03/artifacts/download-receipt.json').read_bytes())},
  33. })
  34. fourth = {'roundId': 'R04', 'moduleId': 'D1-03',
  35. 'purpose': '在有限代表产品上比较面、酱、步骤与容器组合,形成可检验的研发问题',
  36. 'promptPath': 'rounds/R04/prompt-verbatim.txt',
  37. 'promptOrigin': 'authored-locally-for-user-forwarding',
  38. 'status': 'prepared-for-user-forwarding', 'forwardedConfirmed': False,
  39. 'executionConfirmed': False, 'replyReceived': False, 'reportIds': [],
  40. 'actualUserDecision': None}
  41. case['rounds'] = [r for r in case['rounds'] if r['roundId'] != 'R04'] + [fourth]
  42. case['status'] = 'R03-reviewed-product-comparison-prepared-not-executed'
  43. case['currentModuleId'] = 'D1-02'
  44. case['moduleComplete'] = False
  45. case['courseModules'][1]['status'] = 'rules-received-inconsistent-application-not-accepted'
  46. case['courseModules'][2]['status'] = 'bounded-product-comparison-prepared-not-executed'
  47. case['demonstration'].update({'actualReplies': 3, 'latestReplyComplete': False,
  48. 'status': 'three-replies-two-received-atlases-awaiting-layout-check'})
  49. edits = json.loads((WORK / 'presentation-edits.json').read_bytes())
  50. edits['edits'] = [e for e in edits['edits'] if e['source'] not in {
  51. 'rounds/R03/reply-verbatim.md', 'rounds/R03/artifacts/atlas-received.html'}]
  52. def present(source, destination, replacements):
  53. value = (WORK / source).read_text(encoding='utf-8')
  54. for before, after, reason in replacements:
  55. assert value.count(before) == 1, (source, before)
  56. value = value.replace(before, after, 1)
  57. edits['edits'].append({'source': source, 'display': destination,
  58. 'before': before, 'after': after, 'reason': reason})
  59. (WORK / destination).write_text(value, encoding='utf-8')
  60. original = (WORK / 'rounds/R03/reply-verbatim.md').read_text(encoding='utf-8')
  61. operational_tail = original[original.index('九、交付与核验\n'):]
  62. present('rounds/R03/reply-verbatim.md', 'rounds/R03/reply-display.md', [
  63. ('线上内容与实际文案完全一致。所有核验已完成,以下是完整答复。\n\n', '', 'remove operational consistency preface; preserve business reply'),
  64. (operational_tail, '', 'remove operational delivery/save receipt; incomplete tail retained verbatim privately, not reconstructed'),
  65. ('写成了 evidence-rules.json,核心五条:', '后续沿用以下五条:', 'remove implementation filename, preserve all stated evidence rules'),
  66. ])
  67. src = 'rounds/R03/artifacts/atlas-received.html'
  68. dst = 'rounds/R03/artifacts/atlas-display.html'
  69. original_atlas = (WORK / src).read_text(encoding='utf-8')
  70. assert not re.search(r'<script|<iframe|<link|<img|\bon\w+\s*=|@import|url\(', original_atlas, re.I)
  71. style = '''<style id="presentation-layout">
  72. body{font-size:16px}.kicker,.lead,.tag,.cross,.how,.lbl,li,.row,.row .k,li.q,.qt,.ev,table,th,td,.note,ul.plain li{font-size:15px}
  73. .grid{grid-template-columns:minmax(0,1fr)}.card,.tw{min-width:0}.card,.box{overflow-wrap:anywhere}.tw{max-width:100%;overflow-x:auto}table{min-width:540px}
  74. @media(max-width:640px){.wrap{padding:20px 14px 40px}.row{grid-template-columns:minmax(0,1fr)}.card{padding:16px 14px}.box{padding:15px}}
  75. </style>'''
  76. present(src, dst, [
  77. ('康师傅拌面 · S1 品类市场分析 · 复核版', '康师傅拌面 · 品类市场分析 · 复核版', 'remove internal stage identifier'),
  78. ('数据取自研究库代际 82b104fc 的 49 条评价', '数据取自现有资料的 49 条评价', 'remove internal generation only'),
  79. ('未改研究库与 Skill', '未改研究资料', 'remove operational tool identity'),
  80. ('本成果为 S1 阶段初稿', '本成果为研究初稿', 'remove internal stage identifier'),
  81. ('</head>', style + '</head>', 'presentation-only font and responsive layout adjustment'),
  82. ])
  83. for path in ['rounds/R03/reply-verbatim.md', src, 'rounds/R03/prompt-verbatim.txt']:
  84. edits['originalFileSha256'][path] = sha(path)
  85. (WORK / 'presentation-edits.json').write_text(json.dumps(edits, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
  86. (WORK / 'case.json').write_text(json.dumps(case, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
  87. print(json.dumps({'actualReplies': 3, 'thirdReplyComplete': False, 'fourthPromptExecuted': False}, ensure_ascii=False))
  88. if __name__ == '__main__':
  89. main()