| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- """Freeze historical recovery additions on sealed r9; never touch a deployed service."""
- import argparse
- from contextlib import closing
- from datetime import datetime, timezone
- import hashlib
- import json
- from pathlib import Path
- import shutil
- import sqlite3
- import zipfile
- ROOT = Path(__file__).resolve().parents[1]
- BASE = ROOT / 'artifacts/ksf-industry-monitor-20261107-r9/package'
- WORK = ROOT / 'work/industry-mainline-continuation-20261107-r1'
- RELEASE = 'ksf-industry-monitor-20261107-r10'
- SOURCES = ['src/pages/industry-pipeline-view.js', 'server/voc-library/monitoring_ledger.py',
- 'server/voc-library/monitoring_dispatch.py', 'server/voc-library/test_monitoring_ledger.py',
- 'scripts/manage-industry-dispatch.py', 'scripts/prepare-industry-handoff.py',
- 'scripts/audit-industry-archived-details.py', 'scripts/reuse-industry-archived-details.py',
- 'scripts/verify-industry-monitor.py', 'scripts/verify-industry-recovery-release.py',
- 'scripts/verify-industry-recovered-data.py', 'scripts/package-industry-recovery.py']
- DOCUMENTS = ['agent-queries.md', 'deployment.md', 'request-guard.md', '主线待决策清单.md',
- 'r10本地实现与未完成条件.md']
- def sha(raw): return hashlib.sha256(raw).hexdigest()
- def save(path, value):
- path.parent.mkdir(parents=True, exist_ok=True)
- path.write_text(json.dumps(value, ensure_ascii=False, indent=2) + '\n', 'utf-8')
- def build(out):
- if out.exists(): raise ValueError('RELEASE_DIRECTORY_MUST_BE_NEW')
- for line in (BASE/'FILES.sha256').read_text('utf-8').splitlines():
- digest, name = line.split(' ', 1)
- if sha((BASE/name).read_bytes()) != digest: raise ValueError('FROZEN_R9_CHANGED')
- captured = {name:(ROOT/name).read_bytes() for name in SOURCES}
- shutil.copytree(BASE, out)
- for name, raw in captured.items():
- target = out/('payload/'+name if name.startswith('src/') else name)
- target.parent.mkdir(parents=True, exist_ok=True); target.write_bytes(raw)
- if any((ROOT/name).read_bytes() != raw for name, raw in captured.items()):
- raise ValueError('SOURCE_CHANGED_DURING_FREEZE')
- save(out/'evidence/r10-source-capture.json', {'release':RELEASE,
- 'sourceFilesSha256':{name:sha(raw) for name, raw in captured.items()},
- 'viewIndustrySource':'sealed r9; concurrent workspace innovation edits excluded'})
- store = ROOT/'work/industry-monitoring-20261107-r1/monitoring-registry'
- with closing(sqlite3.connect((store/'monitoring.sqlite').resolve().as_uri()+'?mode=ro', uri=True)) as source:
- with closing(sqlite3.connect(out/'data/monitoring-registry/monitoring.sqlite')) as destination:
- source.backup(destination)
- destination.execute("UPDATE pipeline_workers SET state='ARCHIVED_COPY'")
- destination.execute("UPDATE dispatch_audits SET state='ARCHIVED_COPY'"); destination.commit()
- for file in (store/'assets').iterdir():
- if sha(file.read_bytes()) != file.stem: raise ValueError('AUXILIARY_ASSET_CHANGED')
- target = out/'data/monitoring-registry/assets'/file.name
- if not target.exists(): shutil.copyfile(file, target)
- # Replace only the bounded scope; preserve all sealed source evidence and receipts.
- for file in (WORK/'handoff').iterdir():
- if file.is_file(): shutil.copyfile(file, out/'handoff'/file.name)
- target = out/'evidence/r10-recovery'; target.mkdir()
- for name in ['ledger-import.json', 'detail-reuse-receipt.json', 'detail-reuse-replay.json', 'connector-capabilities.json']:
- shutil.copyfile(WORK/name, target/name)
- inventory = json.loads((WORK/'archived-details/inventory.json').read_bytes())
- save(target/'archive-inventory-summary.json', {k:v for k,v in inventory.items()
- if k not in ('details','unboundDetailCandidates','rankingEndpointCandidates')})
- save(target/'public-access-status.json', {'rankingUrlSource':'verified historical JD detail rankInfo h5JumpUrl',
- 'ordinaryFreshBrowserTitle':'京东登录注册','loginRequired':True,'loginAttempted':False,
- 'challengeHandling':False,'completeTop100Or400':0,'newOfficialMetadataVerified':0,
- 'paidCalls':0,'privateBrowserDiagnosticsIncluded':False})
- release = json.loads((out/'RELEASE.json').read_bytes())
- release.update(release=RELEASE,createdAt=datetime.now(timezone.utc).isoformat(),
- builtFromFrozenRelease='ksf-industry-monitor-20261107-r9',
- settledCloseoutIdentifiedRows=154,parameterBoundSettledRows=139,
- unboundSettledParameterRows=15,serverLedgerRefetched=False,
- detailObservations=52,productsWithDetailText=13,primaryDetailsWithResponse=41,
- primaryDetailsWithText=12,nativePython39Verified=False,
- overallComplete=False,productionDeployed=False,paidCalls=0)
- release['backendFiles'].append('server/voc-library/monitoring_ledger.py')
- save(out/'RELEASE.json',release)
- mpath = out/'deploy/industry-ui-files.json'; manifest = json.loads(mpath.read_bytes()); manifest['release']=RELEASE
- for entry in manifest['files']:
- old = sha((BASE/'payload'/entry['path']).read_bytes().replace(b'\r\n',b'\n'))
- if old not in entry['priorNormalizedSha256']: entry['priorNormalizedSha256'].append(old)
- entry['sha256']=sha((out/'payload'/entry['path']).read_bytes().replace(b'\r\n',b'\n'))
- save(mpath,manifest)
- publisher=out/'scripts/publish-industry-ui.mjs'
- publisher.write_text(publisher.read_text('utf-8').replace('ksf-industry-monitor-20261107-r9',RELEASE),'utf-8')
- for file in (out/'deploy').iterdir():
- if file.suffix=='.example':
- file.write_text(file.read_text('utf-8').replace('ksf-industry-monitor-20261107-r9',RELEASE),'utf-8')
- for name in DOCUMENTS: shutil.copyfile(ROOT/'docs/industry-monitoring-20261107'/name,out/'docs'/name)
- (out/'docs/README.md').write_text('''# 方便面行业 VOC 后台 r10 本地验收版
- 当前版本基于封存r9,补齐154行附件账本身份对齐、139行商品页防重核对,以及历史详情响应复用。14个前端模块、16个独立后端文件。
- 主店165件中41件有详情响应、12件有商品文字卖点;全库52/13。历史观察不冒充新采集,宣称不冒充实证。政策8类用法和创新工作区沿用已验版本。当前细节见r10本地实现与未完成条件.md。
- 本包没有活动研究库、私有详情原件、完整账本ZIP、登录页诊断或凭据。历史文档/回执仅保留出处,当前执行入口和数量以本页、RELEASE与implementation-receipt-v10.json为准。
- 当前未部署生产、未恢复付费采集、未转发。全量当前目录/评价、完整Top100/400与跨期监听、16份官方状态及生产接通仍有真实外部缺口,overallComplete=false。封存r5至r9不变。
- ''','utf-8')
- print(json.dumps({'ok':True,'candidate':str(out),'staticFiles':14,'backendFiles':16,'sealed':False}))
- def seal(out):
- receipt=json.loads((out/'evidence/implementation-receipt-v10.json').read_bytes())
- if not receipt['accepted'] or not receipt['packageVerificationPassed']: raise ValueError('ACCEPTANCE_REQUIRED')
- for name, digest in receipt['testedFilesSha256'].items():
- if sha((out/name).read_bytes())!=digest: raise ValueError('TESTED_FILE_CHANGED')
- archive=out.parent/(RELEASE+'.zip')
- if archive.exists(): raise ValueError('ARCHIVE_EXISTS')
- files=sorted(f for f in out.rglob('*') if f.is_file() and f!=out/'FILES.sha256')
- (out/'FILES.sha256').write_text(''.join(sha(f.read_bytes())+' '+f.relative_to(out).as_posix()+'\n' for f in files),'utf-8')
- with zipfile.ZipFile(archive,'x',zipfile.ZIP_DEFLATED) as z:
- for f in sorted(out.rglob('*')):
- if f.is_file(): z.write(f,f.relative_to(out).as_posix())
- print(json.dumps({'ok':True,'archive':str(archive),'bytes':archive.stat().st_size,
- 'sha256':sha(archive.read_bytes()),'productionDeployed':False,'paidCalls':0}))
- if __name__=='__main__':
- p=argparse.ArgumentParser(description=__doc__);p.add_argument('--out',type=Path,required=True);p.add_argument('--seal',action='store_true')
- a=p.parse_args();(seal if a.seal else build)(a.out.resolve())
|