| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768 |
- from pathlib import Path
- import hashlib
- import json
- import zipfile
- ROOT=Path(__file__).resolve().parents[1]
- SRC=ROOT/'work/first-live-sources-20261102'
- DEST=ROOT/'work/delivery-by-recipient-20261102'
- KEY='KSF-真实资料-20261102-01'
- OPS='''运维001:开始第一批真实官网资料入库准备。不是重跑K轮/查重样例,不改旧目录,不升级Skill/Function,不重启。
- 1. 核验ZIP与FILES.sha256全部项。包内采集者为Codex:两页统一官网公开页面,取得时间、响应原始字节、解码HTML、全文和指纹均已留存。不是王刚001亲自抓取,也不是消费者调查。
- 2. 建 /opt/data/ksf-executor-20261102/first-live-01,放入包内 scripts/workshop-first-live-import.mjs 和同目录 scripts/first-live-batch.json,两者root:root 0644、hermes可读。保持同目录,执行器内置批次JSON的SHA-256;不修改JSON、脚本或清单。node --check脚本。
- 3. archives/与采集汇总.md归档到受控交付目录,保留原件与清单。包内不存在密钥或私有身份值。
- 4. 用context-first-live.example.json生成 /opt/data/ksf-workshop-private/context-first-live-01.json;模板agentProfileKey=null不可原样安装,仅填现有已核实Agent档案键并与registration.json核对。hermes(10000)/HOME=/opt/data写,0600;不复制员工账号/会话键,不新登记身份。
- 5. 以hermes建 /opt/data/ksf-workshop-private/first-live 父目录0700。检查目标 /opt/data/ksf-workshop-private/first-live/KSF-live-20261102-01 不存在,并查本任务键历史/在途;有痕迹则停下回读,不删除、换键或换目录。
- 6. 回报脚本指纹/语法、批次JSON指纹、输入权限和无历史后,交王刚001在新真实消息任务中执行,不由运维冒跑。
- 会写两份live来源,最多9条产品口味、9条证据和1个研究工作分类;以实际created/unchanged回执为准。不是9个SKU,也不保证在售。分类是明确标注的研究工作分类。9段引文来自两份官网口味/包装列表,不是9个独立来源或消费者评价。
- 执行只做入库与回读,不创建会话/项目/报告、不触碰sample K记录。第一批成功后才基于真实返回sourceId做S1课堂小结。
- '''
- WANG='''王刚001:待运维落地完成后,在新真实消息授权任务中,以hermes(10000)、HOME=/opt/data执行一次:
- node /opt/data/ksf-executor-20261102/first-live-01/workshop-first-live-import.mjs --input /opt/data/ksf-workshop-private/context-first-live-01.json --state-dir /opt/data/ksf-workshop-private/first-live/KSF-live-20261102-01 --execute
- 固定任务键KSF-真实资料-20261102-01。导入的是Codex已实际采集并归档的两份官网资料,dataMode=live;你执行归档资料导入,不声称自己刚在平台抓取。9个口味条目,分别是统一酱拌面4种和巧面馆拌面5种;附官网原文证据。
- 预期operation=first-live-official-sources-imported,2来源/9产品口味/9证据/1研究工作分类并完成逐条回读。已有相同资料可unchanged,按实际回执报计数,不为凑新增换键。不是SKU粒度,不填未知净含量/价格/消费者评价。
- 成功回报ok/operation/taskKey、两批sourceId、categoryId、各itemKey/className/objectId/operation及created/unchanged;保存完整两层调用回执与日志,不贴完整私有上下文。没有会话或报告是预期行为。
- 失败立即停:报错误码、最后一步、已返回编号,保留目录和回执;不重试、不删记录、不换键、不重跑K轮,不手工造身份。入库完成后把回执交Codex核对,再组织S1真实资料小结和待补问题。
- '''
- def main():
- bundle=json.loads((SRC/'batch.json').read_text(encoding='utf-8'))
- lines=['# 第一批真实官网资料采集汇总','', '任务键:'+KEY, '', '本批由Codex通过HTTPS读取并归档,尚未写入目标业务库。只包含公开官网产品自述,不代表消费者研究、当前在售或独立验证。', '', '## 已取得资料', '', '| 产品口味条目 | 官网包装说明(系列级) | 来源 |', '|---|---|---|']
- for f in bundle['facts']:
- lines.append('|'+f['name']+'|'+f['packagingStatement']+'|'+f['sourceUrl']+'|')
- lines+=['', '本批9个口味条目来自统一同一厂商的2个系列页,不是9个独立来源,也不是完整竞品样本。每个口味关联一段口味/包装列表引文;包装为系列级,不假设每种口味均有所有包装。未填写价格、净含量、配方比例、销量或消费痛点。', '', '## 来源归档']
- for b in bundle['batches']:
- lines+=['', '- '+b['capture']['url'], '- 取得时间:'+b['capture']['collectedAt'], '- 字符集:gb18030,严格解码;未知发布日期', '- 原始响应SHA-256:'+b['capture']['responseSha256'], '- 提取全文SHA-256:'+b['capture']['rawTextSha256']]
- lines+=['', '## 下一步需要补充的细节', '']
- lines += [str(i)+'. '+q for i,q in enumerate(bundle['pendingQuestions'],1)]
- lines+=['', '建议先完成此批入库及独立回读,再补康师傅同口径产品、包装规格/渠道价格和逐字消费者评价,保存真实S1课堂小结。不要把sample K会话改成live,不根据官网营销句生成需求已验证结论。', '', '本地工作坊测试77/77通过;目标实例导入与看板呈现仍待实际执行、回读。']
- report='\n'.join(lines)+'\n'
- files={'scripts/workshop-first-live-import.mjs':(ROOT/'scripts/workshop-first-live-import.mjs').read_bytes(), 'scripts/first-live-batch.json':(SRC/'batch.json').read_bytes(), 'context-first-live.example.json':(json.dumps({'version':'ksf.first-live-import.v1','taskKey':KEY,'agentProfileKey':None},ensure_ascii=False,indent=2)+'\n').encode(), '给运维001-真实资料落地.txt':OPS.encode(), '给王刚001-真实资料入库.txt':WANG.encode(), '采集汇总.md':report.encode()}
- for b in bundle['batches']:
- for suffix in ['response.bin','html','txt','capture.json']:
- p=SRC/(b['key']+'.'+suffix)
- files['archives/'+p.name]=p.read_bytes()
- sha=lambda b:hashlib.sha256(b).hexdigest()
- files['FILES.sha256']=''.join(sha(b)+' '+n+'\n' for n,b in files.items()).encode()
- DEST.mkdir(parents=True,exist_ok=True)
- target=DEST/'ksf-first-live-sources-20261102.zip'
- with zipfile.ZipFile(target,'w',compression=zipfile.ZIP_DEFLATED) as z:
- for n,b in files.items():z.writestr(n,b)
- with zipfile.ZipFile(target) as z:
- assert z.testzip() is None
- for line in z.read('FILES.sha256').decode().splitlines():
- expected,n=line.split(' ',1)
- assert sha(z.read(n))==expected
- assert sha(z.read('scripts/first-live-batch.json'))=='0118c861ae9a7da5e4d361497050200a2e4e595c7a2d76c733a22970cd179326'
- for n in ['给运维001-真实资料落地.txt','给王刚001-真实资料入库.txt','采集汇总.md']:(DEST/n).write_bytes(files[n])
- (ROOT/'docs/first-live-sources-20261102.md').write_text(report,encoding='utf-8')
- receipt={'file':target.name,'bytes':target.stat().st_size,'sha256':sha(target.read_bytes()),'manifestChecked':str(len(files)-1)+'/'+str(len(files)-1),'executorSha256':sha(files['scripts/workshop-first-live-import.mjs']),'batchSha256':sha(files['scripts/first-live-batch.json']),'sourcePages':2,'productFlavorEntries':9,'databaseWrites':0,'targetExecuted':False}
- (DEST/'ksf-first-live-sources-20261102.receipt.json').write_text(json.dumps(receipt,ensure_ascii=False,indent=2),encoding='utf-8')
- print(json.dumps(receipt,ensure_ascii=False,indent=2))
- if __name__=='__main__':main()
|