verify-query-skills.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. """Exercise the delivered CLI on the current local corpus, with no database writes."""
  2. import hashlib
  3. import importlib.util
  4. import json
  5. from pathlib import Path
  6. import shutil
  7. import subprocess
  8. import sys
  9. import tempfile
  10. ROOT = Path(__file__).resolve().parents[1]
  11. WORK = ROOT / 'work/agent-query-20261106'
  12. RELEASE = ROOT / 'artifacts/数据库精准检索规则-20261106/ksf-agent-query-rules-20261106-r1'
  13. sys.path.insert(0, str(ROOT / 'server/voc-library'))
  14. import voc_db
  15. import verify_retrieval
  16. spec = importlib.util.spec_from_file_location('query_installer', RELEASE / 'install-query-skills.py')
  17. installer = importlib.util.module_from_spec(spec)
  18. spec.loader.exec_module(installer)
  19. registry = ROOT / 'work/library-preview/registry'
  20. db = voc_db.registry_database(registry)
  21. before = installer.digest(db)
  22. pointer_before = installer.digest(registry / 'current.json')
  23. research = verify_retrieval.verify(db)
  24. with tempfile.TemporaryDirectory(prefix='query-skill-', dir=WORK) as temp:
  25. data = Path(temp) / 'data'
  26. for name in installer.NAMES:
  27. shutil.copytree(WORK / 'baseline-skills' / name, data / 'skills' / name)
  28. (data / 'skills/ksf-workshop-runtime/credential-binding.json').write_text('{"testSentinel":true}', encoding='utf-8')
  29. state = data / 'ksf-workshop-state/sessions'
  30. state.mkdir(parents=True)
  31. (state / 'test-session.json').write_text('{"testSentinel":true}', encoding='utf-8')
  32. old = installer.snapshot(data)
  33. plan = installer.install(RELEASE, data)
  34. assert installer.snapshot(data) == old
  35. expected_workshop = ['ksf-workshop-runtime/' + rel for rel in ('SKILL.md', 'references/workshop-tasks.md', 'FILES.sha256')]
  36. assert sorted(x for x in plan['changed'] if x.startswith('ksf-workshop-runtime/')) == sorted(expected_workshop)
  37. applied = installer.install(RELEASE, data, True)
  38. assert applied['filesystemVerified'] and applied['credentialBindingPreserved'] and applied['stateDirectoryPreserved']
  39. assert not installer.install(RELEASE, data, True)['applied']
  40. cli = data / 'skills/ksf-voc-library/scripts/query_voc.py'
  41. def call(command, *args, generation=None, ok=True):
  42. argv = [sys.executable, '-B', '-X', 'utf8', str(cli), command, '--registry', str(registry), *args]
  43. if generation:
  44. argv.extend(['--generation', generation])
  45. result = subprocess.run(argv, text=True, encoding='utf-8', capture_output=True, timeout=30)
  46. assert (result.returncode == 0) == ok, result.stderr
  47. payload = json.loads(result.stdout if ok else result.stderr)
  48. assert payload['readOnly'] and payload['databaseWrites'] == 0
  49. return payload
  50. contract = call('contract')
  51. generation = contract['generation']
  52. assert contract['retrieval']['agentRulesVersion'] == 'ksf.agent-data-rules.20261106.v1'
  53. examples = []
  54. first_product = first_review = None
  55. for path in sorted((RELEASE / 'examples').glob('*.json')):
  56. aggregate = path.name.startswith(('03-', '08-'))
  57. response = call('aggregate' if aggregate else 'search', '--input', str(path), generation=generation)
  58. assert response['generation'] == generation
  59. for row in response.get('records', []):
  60. if path.name.startswith(('01-', '02-', '06-', '07-', '09-')):
  61. assert (row['platform'], row['brand'], row['category']) == ('jd', 'ksf', 'banmian')
  62. if row['entity'] == 'products' and first_product is None:
  63. first_product = row
  64. if row['entity'] == 'reviews' and first_review is None:
  65. first_review = row
  66. examples.append(dict(file=path.name, command='aggregate' if aggregate else 'search',
  67. totalMatched=response.get('totalMatched'), groups=response.get('groups'), effectiveQuery=response['effectiveQuery']))
  68. citations = []
  69. for row in [first_product, first_review]:
  70. if row is None:
  71. continue
  72. record = call('get', '--entity', row['entity'], '--id', row['record_id'], generation=generation)['record']
  73. source = call('source', '--id', record['source_record_id'], generation=generation)
  74. assert source['citation']['id'] == row['source_record_id']
  75. citations.append(dict(entity=row['entity'], id=row['record_id'], sourceId=row['source_record_id'], archiveSha256=source['citation']['archiveSha256']))
  76. stale = call('get', '--entity', 'products', '--id', first_product['record_id'], generation='stale-generation', ok=False)
  77. assert stale['error']['code'] == 'LIBRARY_GENERATION_CHANGED'
  78. assert installer.digest(db) == before and installer.digest(registry / 'current.json') == pointer_before
  79. result = dict(ok=True, generation=generation, databaseSha256=before, queryExamples=examples, sourceChecks=citations,
  80. realCorpusScenarios=research['scenarios'], benchmark=research['benchmark'], installPlan=plan,
  81. installSimulationVerified=True, generationGuardVerified=True, databaseWrites=0,
  82. productionInstalled=False, realMessageVerified=False)
  83. (WORK / 'validation.json').write_text(json.dumps(result, ensure_ascii=False, indent=2) + '\n', encoding='utf-8')
  84. print(json.dumps(dict(ok=True, examples=len(examples), researchScenarios=len(research['scenarios']), sourceChecks=len(citations),
  85. benchmark=research['benchmark'], generation=generation, changed=plan['changed']), ensure_ascii=False, indent=2))