| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- """Archive receipt metadata and presentation-only changes for the second reply."""
- from pathlib import Path
- import hashlib
- import json
- import re
- WORK = Path(__file__).resolve().parent
- def digest(path):
- return hashlib.sha256((WORK / path).read_bytes()).hexdigest()
- def main():
- edits = json.loads((WORK / 'presentation-edits.json').read_bytes())
- edits['edits'] = [e for e in edits['edits'] if e['source'] not in {
- 'rounds/R02/reply-verbatim.md', 'rounds/R02/artifacts/atlas-received.html'}]
- def presentation(source, destination, replacements):
- value = (WORK / source).read_text(encoding='utf-8')
- for before, after, reason in replacements:
- assert value.count(before) == 1, (source, before)
- value = value.replace(before, after, 1)
- edits['edits'].append({'source': source, 'display': destination,
- 'before': before, 'after': after, 'reason': reason})
- (WORK / destination).write_text(value, encoding='utf-8')
- original = (WORK / 'rounds/R02/reply-verbatim.md').read_text(encoding='utf-8')
- ops = original[original.index('已同步看板\n'):original.index('这轮我没做到的\n')]
- presentation('rounds/R02/reply-verbatim.md', 'rounds/R02/reply-display.md', [
- ('https://s3.fmode.cn/user/DpPsnlBm0K/report/ksf-atlas-s1-20261109.html**',
- '全景图见“研究成果”。', 'replace operational file URL with the local artifact view; source retained privately'),
- (ops, '', 'omit save/readback/HTTP/hash operational receipt; raw reply and claimed artifact retained privately'),
- ])
- atlas_source = 'rounds/R02/artifacts/atlas-received.html'
- atlas_display = 'rounds/R02/artifacts/atlas-display.html'
- original_atlas = (WORK / atlas_source).read_text(encoding='utf-8')
- assert not re.search(r'<script|<iframe|<link|<img|\bon\w+\s*=|@import|url\(', original_atlas, re.I)
- style = '''<style id="presentation-layout">
- body{font-size:16px}.sub,.lead,.row,.brands,.tag,.claim,.col h4,.reps h4,.col ul,.reps ul,.evid,table,th,td,.note,.q li,footer{font-size:15px}
- .cards{grid-template-columns:repeat(2,minmax(0,1fr))}.card,.col{min-width:0;overflow-wrap:anywhere}.table-scroll{max-width:100%;overflow-x:auto}table{min-width:540px}
- @media(max-width:820px){.cards{grid-template-columns:minmax(0,1fr)}.row b{flex-basis:auto}.row{align-items:flex-start}.wrap{padding:24px 16px 44px}}
- </style>'''
- presentation(atlas_source, atlas_display, [
- ('康师傅拌面品类全景 · S1 品类扫描', '康师傅拌面品类全景', 'remove internal stage label from title'),
- ('S1 品类扫描 · 开放探索(不锁现品、不假设产线可改造)· 数据代际 82b104fc',
- '开放探索(不锁现品、不假设产线可改造)', 'remove stage and internal generation from subtitle'),
- ('数据来源:ksf-voc-library 研究库(代际 82b104fc)', '数据来源:现有研究资料',
- 'remove runtime identity and internal generation; keep raw provenance privately'),
- ('S1 阶段初稿 · 供团队讨论,不构成新品方向结论', '初稿 · 供团队讨论,不构成新品方向结论',
- 'remove internal stage label from footer'),
- ('</head>', style + '</head>', 'presentation-only font and responsive layout adjustment'),
- ])
- atlas = (WORK / atlas_display).read_text(encoding='utf-8')
- wrapped = re.sub(r'(<table\b.*?</table>)', r'<div class="table-scroll">\1</div>', atlas, flags=re.S)
- assert wrapped != atlas
- (WORK / atlas_display).write_text(wrapped, encoding='utf-8')
- edits['edits'].append({'source': atlas_source, 'display': atlas_display,
- 'kind': 'wrap-each-table-in-scroll-container',
- 'reason': 'presentation layout only; table cell contents unchanged'})
- edits['originalFileSha256'] = {p: digest(p) for p in [
- 'rounds/R01/reply-verbatim.md', 'rounds/R02/prompt-verbatim.txt',
- 'rounds/R02/reply-verbatim.md', atlas_source]}
- (WORK / 'presentation-edits.json').write_text(json.dumps(edits, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
- case = json.loads((WORK / 'case.json').read_bytes())
- second = next(r for r in case['rounds'] if r['roundId'] == 'R02')
- second.update({
- 'purpose': '开放探索,形成产品方案与任务、收益、代价的初版对照',
- 'status': 'reply-received-reviewed', 'executionConfirmed': True, 'replyReceived': True,
- 'executionEvidence': 'user-relayed-full-reply; independent query/board responses unavailable',
- 'replyPath': 'rounds/R02/reply-verbatim.md', 'replySha256': digest('rounds/R02/reply-verbatim.md'),
- 'reviewPath': 'rounds/R02/review.md', 'reportIds': ['7lX5ZGTZaO'],
- 'reportIdsEvidence': 'operator-reported; not independently read back here',
- 'claimsIndependentlyVerified': False,
- 'reportedArtifacts': [{'artifactId': '7lX5ZGTZaO', 'savedAndReadBack': 'reported',
- 'publicBoardVisible': 'reported', 'independentlyVerifiedHere': False}],
- 'receivedArtifact': {'path': atlas_source, 'presentationPath': atlas_display,
- 'url': 'https://s3.fmode.cn/user/DpPsnlBm0K/report/ksf-atlas-s1-20261109.html',
- 'httpStatus': 200, 'bytes': (WORK / atlas_source).stat().st_size,
- 'sha256': digest(atlas_source), 'fileIndependentlyDownloaded': True,
- 'independentVerificationScope': 'file availability, bytes and reported hash; not research claims or board operations'},
- })
- third = {'roundId': 'R03', 'moduleId': 'D1-02',
- 'purpose': '复核影响产品选择的主张,固定可沿用的证据与统计规则',
- 'promptPath': 'rounds/R03/prompt-verbatim.txt',
- 'promptOrigin': 'authored-locally-for-user-forwarding',
- 'status': 'prepared-for-user-forwarding', 'forwardedConfirmed': False,
- 'executionConfirmed': False, 'replyReceived': False, 'reportIds': [],
- 'actualUserDecision': None}
- case['rounds'] = [r for r in case['rounds'] if r['roundId'] != 'R03'] + [third]
- case['status'] = 'R02-received-key-claims-under-review-R03-prepared'
- case['currentModuleId'] = 'D1-02'
- case['moduleComplete'] = False
- case['courseModules'][0]['status'] = 'initial-panorama-received-decision-critical-claims-pending'
- case['courseModules'][1]['status'] = 'targeted-verification-prepared-not-executed'
- case['demonstration'].update({'status': 'two-actual-replies-and-received-panorama',
- 'actualReplies': 2, 'completedModules': 0,
- 'preserveFullDialogue': False,
- 'preserveFullBusinessDialogue': True,
- 'preserveFullRawDialoguePrivately': True})
- (WORK / 'case.json').write_text(json.dumps(case, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
- print(json.dumps({'receivedReplies': 2, 'nextPrompt': 'prepared-not-forwarding-confirmed',
- 'rawFilesUnchanged': True}, ensure_ascii=False))
- if __name__ == '__main__':
- main()
|