| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- """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()
|