| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- """Build a fixed three-file site patch. No site or database writes."""
- from pathlib import Path
- import hashlib
- import json
- import zipfile
- ROOT=Path(__file__).resolve().parents[1]
- DELIVERY=Path('F:/文档/工作坊当前资料')
- FILES=['src/core/report.js','src/core/evidence/chain.js','src/layout/kf-app.js']
- def sha(body):
- return hashlib.sha256(body).hexdigest()
- def main():
- baseline=json.loads((ROOT/'work/report-evidence-before.json').read_text(encoding='utf-8'))
- by_path={row['path']:row for row in baseline['files']}
- manifest={
- 'version':'ksf.report-evidence.publish.v1',
- 'release':'ksf.report-evidence.20261102.v1',
- 'homepageSha256':by_path['index.html']['sha256'],
- 'baselineObservedAt':baseline['at'],
- 'files':[{'path':name,'sha256':sha((ROOT/name).read_bytes()),
- 'priorNormalizedSha256':[by_path[name]['normalizedSha256']],'allowMissing':False} for name in FILES],
- }
- manifest_path=ROOT/'deploy/report-evidence-files-20261102.json'
- manifest_path.write_text(json.dumps(manifest,ensure_ascii=False,indent=2)+'\n',encoding='utf-8')
- instructions='''运维001:发布报告引文显示修复,只改三个前端文件,无业务数据写入。
- 原因:S1第2版G8IrkkDG7X的正文、五段引文和六条待补问题已独立回读通过;但报告是表格/段落结构,旧页面未生成引用入口。修复补齐所有report.evidence的入口,并保留引用的sourceId,避免已入库原文误标为“未落入知识库”。不修改报告内容、不补造消费者结论。
- 包:ksf-report-evidence-ui-20261102.zip。先核FILES.sha256六项。发布器为独立新文件scripts/publish-report-evidence.mjs,旧九文件发布器不变。
- 只允许三个文件:
- src/core/report.js
- src/core/evidence/chain.js
- src/layout/kf-app.js
- 原首页SHA-256=dfeb6a6d0b63e8e1190f9308bf6619a5ca523a5a2f91af5f7ca5ad5fc9642db3。
- 旧文件基线来自2026-11-02线上独立只读读取,并已与本地原件逐字核对;manifest记载完整旧/新指纹。任何未知版本或首页不符都停止,不改指纹放行。
- 1. 解压到与站点目录互不嵌套的独立目录,核对6/6。由站点维护人使用此前核实的kangshifu.fmode.cn实际静态文件目录;不能用数字人容器/opt/data冒充站点目录,也不能根据域名猜目录。
- 2. 在解包根目录以Node执行只读计划(把占位符替换为维护人已核实的绝对目录):
- node scripts/publish-report-evidence.mjs --target-dir <实际站点绝对目录>
- 检查filesChecked=3、homepageModified=false,changes仅上述三文件。如果全部unchanged,直接回读,不重复发布。
- 3. 计划通过,执行一次:
- node scripts/publish-report-evidence.mjs --target-dir <同一实际站点绝对目录> --apply
- 发布器在站点目录外先备份三个旧文件,然后逐个原子替换并回读;同时保护首页与目标指纹。失败会尝试回退且不覆盖别人的并发改动,保留backup和journal,不循环重试。
- 4. 回报计划/apply退出码、changes、三个文件回读hash、首页hash、备份路径、filesystemVerified。站点文件更新不等于域名已更新,CDN缓存如存在需由维护人按既有方式处理,并如实回报;由Codex再验正常URL的三个模块指纹和匿名浏览器。
- 回退:从本次backup读取journal,在恢复每个旧文件前先确认目标仍是journal里本次afterSha256;不符就保留现场报告并发变化。仅恢复这三文件,不动index.html,不清空或重建站点目录。备份保留。
- 边界:不跑完整deploy.sh、不改首页/样式/登录流程、不改Skill、Function或schema,不重启网关,不重新保存S1或导入资料。王刚001当前没有待执行的业务命令。
- Codex隔离浏览器已使用真实线上公开数据、仅替换上述三模块进行桌面和390px检查:五段引文均可点击查看、六条问题可见、旧报告保留、页面无横向溢出。该结果不代表生产站点已应用修复,线上browserVerified仍待本次发布后的独立验收。
- '''
- payload={name:(ROOT/name).read_bytes() for name in FILES}
- payload['scripts/publish-report-evidence.mjs']=(ROOT/'scripts/publish-report-evidence.mjs').read_bytes()
- payload['deploy/report-evidence-files-20261102.json']=manifest_path.read_bytes()
- payload['INSTALL.txt']=instructions.encode('utf-8')
- payload['FILES.sha256']=''.join(sha(body)+' '+name+'\n' for name,body in payload.items()).encode('utf-8')
- DELIVERY.mkdir(parents=True,exist_ok=True)
- target=DELIVERY/'ksf-report-evidence-ui-20261102.zip'
- with zipfile.ZipFile(target,'w',compression=zipfile.ZIP_DEFLATED) as archive:
- for name,body in payload.items():
- archive.writestr(name,body)
- with zipfile.ZipFile(target) as archive:
- assert archive.testzip() is None
- for line in archive.read('FILES.sha256').decode('utf-8').splitlines():
- expected,name=line.split(' ',1)
- assert sha(archive.read(name))==expected
- (DELIVERY/'07-发给运维001-报告引文显示修复.txt').write_text(instructions,encoding='utf-8')
- receipt={'file':str(target),'bytes':target.stat().st_size,'sha256':sha(target.read_bytes()),'manifestChecked':'6/6',
- 'frontendFiles':FILES,'sitePublished':False,'businessWrites':0,'homepageModified':False}
- (ROOT/'work/report-evidence-ui-package-receipt.json').write_text(json.dumps(receipt,ensure_ascii=False,indent=2)+'\n',encoding='utf-8')
- print(json.dumps(receipt,ensure_ascii=True,indent=2))
- if __name__=='__main__':
- main()
|