"""Build a strictly enumerated public Skill upgrade; never reads installed credentials.""" from pathlib import Path import datetime import hashlib import json import zipfile ROOT = Path(__file__).resolve().parents[1] OUT = ROOT / 'docs/workshop-skill-release-20261108-r2' NAME = 'ksf-workshop-unified-20261108-r2' sha = lambda body: hashlib.sha256(body).hexdigest() def main(): skill = ROOT / 'skills/ksf-workshop-runtime' candidate = {} files = {} for line in (skill / 'FILES.sha256').read_text(encoding='utf-8').splitlines(): digest, name = line.split(' ', 1) assert name not in candidate and '..' not in Path(name).parts and not Path(name).is_absolute() raw = (skill / name).read_bytes() assert sha(raw) == digest candidate[name] = digest files['skill/' + name] = raw assert len(candidate) == 37 raw = (skill / 'FILES.sha256').read_bytes() candidate['FILES.sha256'] = sha(raw) files['skill/FILES.sha256'] = raw received = ROOT / 'docs/workshop-skill-review-20261108/received-15ffc90f' export = json.loads((received / 'EXPORT.json').read_text(encoding='utf-8-sig')) baseline = {} for entry in export['files']: raw = (received / 'ksf-workshop-runtime' / entry['path']).read_bytes() assert sha(raw) == entry['sha256'] baseline[entry['path']] = entry['sha256'] assert len(baseline) == 14 prior_path = ROOT / 'docs/agent-library-read-repair-20261108/receipts/r2/agent-library-read-receipt.json' prior = json.loads(prior_path.read_text(encoding='utf-8-sig')) assert prior['ok'] and prior['installedFilesUnchanged'] assert prior['skillFingerprint'] == 'b4266efed78c19c0162aa2200cf0be83b0e7afa2473cef134459eb14c97ce69c' incoming = OUT / 'received-library-2773fc95' current_raw = (incoming / 'ksf-voc-library-SKILL.md').read_bytes() current_sha = sha(current_raw) assert current_sha == '2773fc95fd98fa2367390c72ac5de20435c4a6458cfea45e2b847657af56630a' incoming_zip_sha = sha((incoming / 'ksf-voc-library-current-20261108-v1.zip').read_bytes()) assert incoming_zip_sha == '6a9ab3e28cbc7ee53194d2be5c43a04e1bbc929a44c3d35eeb9055f9adf01aa3' # Names are the known installed layout. Only four runtime hashes have an # independent accepted read receipt; other members still require on-site manifest checks. declared = dict((name, digest) for digest, name in (line.split(' ', 1) for line in (ROOT / 'skills/ksf-voc-library/FILES.sha256').read_text(encoding='utf-8').splitlines())) assert len(declared) == 19 and declared['SKILL.md'] == prior['skillFingerprint'] runtime_pins = {'scripts/' + name: digest for name, digest in prior['installedFingerprints'].items()} assert len(runtime_pins) == 4 and all(declared[n] == h for n, h in runtime_pins.items()) expected = {'schema': 'ksf.agent-library-read-expected.v1', 'generation': prior['contract']['generation'], 'sourceReceiptSha256': sha(prior_path.read_bytes()), 'skillFingerprint': candidate['SKILL.md'], 'installedFingerprints': prior['installedFingerprints']} release = {'schema': 'ksf.unified-workshop-release.v1', 'releaseId': NAME, 'createdAt': datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=8))).isoformat(), 'baseline': baseline, 'candidate': candidate, 'legacySkillSha256': current_sha, 'legacyManifestPolicy': { 'entryNames': sorted(declared), 'verifiedRuntimeEntries': runtime_pins, 'knownStaleSkill': {'actualSha256': current_sha, 'declaredSha256': prior['skillFingerprint'], 'evidenceSha256': incoming_zip_sha}}, 'deliveryStage': 'dry-only-await-user-instruction', 'runtimeReplacementAllowed': False, 'paidCallsAllowed': False, 'businessWritesDuringUpgrade': False} files.update({ 'release.json': (json.dumps(release, ensure_ascii=False, indent=2) + '\n').encode(), 'expected-agent-read.json': (json.dumps(expected, ensure_ascii=False, indent=2) + '\n').encode(), 'upgrade-skill.mjs': (ROOT / 'scripts/upgrade-unified-workshop-skill.mjs').read_bytes(), 'probe-agent-library-read.py': (ROOT / 'scripts/probe-agent-library-read.py').read_bytes(), 'README.md': (OUT / '王刚001-仅dry预检.md').read_bytes(), 'merge-notes.md': (OUT / '经验合并与预检修正.md').read_bytes(), 'local-verification.json': (OUT / 'local-verification.json').read_bytes(), 'prior-r1-local-rehearsal-summary.json': (ROOT / 'docs/workshop-skill-release-20261108-r1/local-rehearsal-summary.json').read_bytes(), }) for name in ('scope-request.json', 'keyword-request.json'): files[name] = (prior_path.parent / name).read_bytes() for name in files: assert not any(term in name.lower() for term in ('credential-binding', 'private.pem', 'envelope', 'channel-config')) files['FILES.sha256'] = ''.join(sha(raw) + ' ' + name + '\n' for name, raw in sorted(files.items())).encode() dest = OUT / (NAME + '.zip') assert not dest.exists(), 'Use a new revision; do not overwrite a released archive' with zipfile.ZipFile(dest, 'x', zipfile.ZIP_DEFLATED) as archive: for name, raw in sorted(files.items()): info = zipfile.ZipInfo(name, (2026, 11, 8, 0, 0, 0)) info.external_attr = 0o100600 << 16 archive.writestr(info, raw, compress_type=zipfile.ZIP_DEFLATED) with zipfile.ZipFile(dest) as archive: assert archive.testzip() is None for line in archive.read('FILES.sha256').decode().splitlines(): digest, name = line.split(' ', 1) assert sha(archive.read(name)) == digest receipt = {'schema': 'ksf.unified-workshop-package-receipt.v1', 'ok': True, 'filename': dest.name, 'bytes': dest.stat().st_size, 'sha256': sha(dest.read_bytes()), 'entries': len(files), 'outerManifestMatched': len(files) - 1, 'skillManifestMatched': len(candidate) - 1, 'baselineFilesPinned': len(baseline), 'runtimeCodeReplaced': False, 'credentialsIncluded': False, 'deployed': False, 'agentLoaded': False, 'deliveryStage': release['deliveryStage'], 'legacyActualSkillSha256': current_sha, 'legacyKnownStaleDeclarationSha256': prior['skillFingerprint'], 'businessDatabaseWrites': 0, 'paidCalls': 0} (OUT / 'package-receipt.json').write_text(json.dumps(receipt, ensure_ascii=False, indent=2) + '\n', encoding='utf-8') print(json.dumps(receipt, ensure_ascii=False)) if __name__ == '__main__': main()