register_round06.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. """Append the received research round while preserving raw dialogue and report versions."""
  2. from pathlib import Path
  3. import difflib
  4. import hashlib
  5. import json
  6. WORK = Path(__file__).resolve().parent
  7. ROOT = WORK.parents[1]
  8. def sha(path):
  9. return hashlib.sha256(path.read_bytes()).hexdigest()
  10. def main():
  11. case = json.loads((WORK / 'case.json').read_bytes())
  12. edits = json.loads((WORK / 'presentation-edits.json').read_bytes())
  13. for name, expected in edits['originalFileSha256'].items():
  14. assert sha(WORK / name) == expected, name
  15. changes = [
  16. ('rounds/R06/reply-verbatim.md', 'rounds/R06/reply-display.md',
  17. '线上回读校验通过:HTTP 200、16,907 B、sha256 双向一致,关键内容全部命中。\n\n', '',
  18. 'omit operational preface; raw received text remains unchanged'),
  19. ('rounds/R06/reply-verbatim.md', 'rounds/R06/reply-display.md',
  20. '报告:https://s3.fmode.cn/user/DpPsnlBm0K/report/ksf-consumer-research-r1-20261109.html',
  21. '报告见“研究成果”中的使用条件研究。', 'point to the received artifact in the same offline presentation'),
  22. ('rounds/R06/reply-verbatim.md', 'rounds/R06/reply-display.md',
  23. '本轮全程免费公开资料,未购样、未付费测试、未新增采集、未改 Skill、未改研究库。\n', '',
  24. 'omit operational tail; preserve all substantive research claims and limitations'),
  25. ]
  26. css = '''<style id="presentation-layout">
  27. body{font-size:16px}.lead,.g,.g th,.g td,.gs,.sr,.sr2,.bd2,.warn,.key,.ex li,.ex em,.exh,.st,.tag,.grd b{font-size:15px!important}
  28. h2{font-size:21px}h3{font-size:18px!important}.wrap,.ex,.key,.warn{min-width:0;overflow-wrap:anywhere}.sc{max-width:100%;overflow-x:auto}.g{min-width:1080px}.g th,.g td{min-width:150px;overflow-wrap:anywhere}.cond{min-width:145px}.ex li{line-height:1.85}.ex em{color:#52635b}.sr{color:#52635b}
  29. @media(max-width:640px){.wrap{padding:22px 14px 40px}.g th,.g td{padding:12px 10px}.key,.warn{padding:16px}.exh{line-height:1.7}}
  30. </style></head>'''
  31. changes.append(('rounds/R06/artifacts/consumer-research-received.html',
  32. 'rounds/R06/artifacts/consumer-research-display.html', '</head>', css,
  33. 'presentation-only readable type and internal table scrolling; no research text changed'))
  34. displays = {}
  35. for source, display, before, after, reason in changes:
  36. text = displays.get(display, (WORK / source).read_text(encoding='utf-8'))
  37. assert text.count(before) == 1, (source, before[:80])
  38. displays[display] = text.replace(before, after)
  39. edit = {'source': source, 'display': display, 'before': before, 'after': after, 'reason': reason}
  40. if edit not in edits['edits']:
  41. edits['edits'].append(edit)
  42. edits['originalFileSha256'][source] = sha(WORK / source)
  43. for name, text in displays.items():
  44. (WORK / name).write_text(text, encoding='utf-8', newline='\n')
  45. edits['originalFileSha256']['rounds/R06/prompt-verbatim.txt'] = sha(WORK / 'rounds/R06/prompt-verbatim.txt')
  46. downloaded = json.loads((WORK / 'rounds/R06/artifacts/download-receipt.json').read_bytes())
  47. sixth = next(r for r in case['rounds'] if r['roundId'] == 'R06')
  48. sixth.update({
  49. 'status': 'exploratory-reply-received-reviewed-sources-and-inferences-pending',
  50. 'forwardedConfirmed': None, 'executionConfirmed': True, 'replyReceived': True,
  51. 'replyPath': 'rounds/R06/reply-verbatim.md',
  52. 'replySha256': sha(WORK / 'rounds/R06/reply-verbatim.md'),
  53. 'replyComplete': True, 'reviewPath': 'rounds/R06/review.md',
  54. 'promptExecutionMatch': 'inferred-from-sequence-exact-prompt-not-verified',
  55. 'executionEvidence': 'user-relayed-complete-reply; no original VOC or query logs received',
  56. 'claimsIndependentlyVerified': False,
  57. 'interviewsConducted': False, 'innovationDirectionSelected': False,
  58. 'receivedArtifact': {
  59. 'path': 'rounds/R06/artifacts/consumer-research-received.html',
  60. 'presentationPath': 'rounds/R06/artifacts/consumer-research-display.html',
  61. 'url': downloaded['url'], 'httpStatus': downloaded['httpStatus'],
  62. 'bytes': downloaded['bytes'], 'sha256': downloaded['sha256'],
  63. 'sourceAnchorLinks': len(downloaded['sourceLinks']), 'embeddedImages': downloaded['images'],
  64. 'fileIndependentlyDownloaded': True,
  65. 'scope': 'received file and available text; original quotations, VOC execution and board not independently verified',
  66. },
  67. })
  68. if not any(r['roundId'] == 'R07' for r in case['rounds']):
  69. case['rounds'].append({
  70. 'roundId': 'R07', 'moduleId': 'D1-04',
  71. 'purpose': '收敛使用任务与取舍,准备有来源依据的后续研究',
  72. 'promptPath': 'rounds/R07/prompt-verbatim.txt',
  73. 'promptOrigin': 'authored-locally-for-user-forwarding',
  74. 'status': 'prepared-for-user-forwarding', 'forwardedConfirmed': False,
  75. 'executionConfirmed': False, 'replyReceived': False,
  76. 'reportIds': [], 'actualUserDecision': None,
  77. })
  78. case['status'] = 'R06-exploratory-consumer-material-received-R07-prepared'
  79. case['currentModuleId'] = 'D1-04'
  80. case['moduleComplete'] = False
  81. case['courseModules'][3]['status'] = 'exploratory-tasks-and-material-received-not-finalized-or-dispatched'
  82. case['courseModules'][4]['status'] = 'public-material-report-received-autonomous-execution-not-verified'
  83. case['demonstration'].update({'status': 'six-replies-five-artifacts-layout-pending', 'actualReplies': 6,
  84. 'latestReplyComplete': True})
  85. case['operatingContext']['platform'] = 'no fixed model or client; earlier Doubao note describes one example environment'
  86. case['operatingContext']['actualCapabilities'] = 'verify current integrations separately from installation or model choice'
  87. (WORK / 'case.json').write_text(json.dumps(case, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
  88. (WORK / 'presentation-edits.json').write_text(json.dumps(edits, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
  89. # This is a new local draft revision; leave the preceding report-design receipt as history.
  90. local = WORK / 'rounds/R06/local-skill-review'
  91. skill = ROOT / 'skills/ksf-workshop-runtime'
  92. baseline = json.loads((local / 'before-fingerprints.json').read_bytes())
  93. changed = [name for name, digest in baseline.items() if sha(skill / name) != digest]
  94. assert changed == ['references/workshop-innovation-reasoning.md'], changed
  95. runtime = [name for name in baseline if name.startswith('scripts/') or name == 'runtime-lock.json']
  96. assert len(runtime) == 7 and all(sha(skill / name) == baseline[name] for name in runtime)
  97. (skill / 'FILES.sha256').write_text(''.join(sha(skill / name) + ' ' + name + '\n' for name in baseline), encoding='utf-8', newline='\n')
  98. for name in changed + ['FILES.sha256']:
  99. before = (local / 'before' / name).read_text(encoding='utf-8')
  100. after = (skill / name).read_text(encoding='utf-8')
  101. target = local / 'diff' / (name + '.diff')
  102. target.parent.mkdir(parents=True, exist_ok=True)
  103. target.write_text(''.join(difflib.unified_diff(before.splitlines(True), after.splitlines(True),
  104. fromfile='before/' + name, tofile='local/' + name)), encoding='utf-8')
  105. sealed = ROOT / 'docs/workshop-skill-release-20261109-r6/ksf-workshop-skill-update-20261109-r6.zip'
  106. assert sha(sealed) == 'c329432b9773cfb0a8e5d4a3e5c162b3778eab28d576b79875da6854f33c4dc5'
  107. receipt = {'ok': True, 'changedInstructions': changed, 'manifestEntries': len(baseline),
  108. 'manifestSha256': sha(skill / 'FILES.sha256'), 'runtimeChanged': False,
  109. 'remoteInstalled': False, 'sealedR6Modified': False,
  110. 'reason': 'observed attitude/action confusion, overbroad counterevidence and monetary-only tradeoff framing',
  111. 'changes': [{'path': name, 'before': baseline[name], 'after': sha(skill / name)} for name in changed]}
  112. (local / 'receipt.json').write_text(json.dumps(receipt, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
  113. print(json.dumps({'receivedRound': 'R06', 'actualReplies': 6, 'artifacts': 5,
  114. 'nextPromptExecuted': False, 'localSkillUpdated': changed, 'remoteInstalled': False}, ensure_ascii=False))
  115. if __name__ == '__main__':
  116. main()