ai-kit-python 1.4.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. ai_kit_python-1.4.2.dist-info/METADATA +132 -0
  2. ai_kit_python-1.4.2.dist-info/RECORD +278 -0
  3. ai_kit_python-1.4.2.dist-info/WHEEL +5 -0
  4. ai_kit_python-1.4.2.dist-info/entry_points.txt +2 -0
  5. ai_kit_python-1.4.2.dist-info/licenses/LICENSE +21 -0
  6. ai_kit_python-1.4.2.dist-info/licenses/template/ai-kit/vendor/security-audit/LICENSE +21 -0
  7. ai_kit_python-1.4.2.dist-info/licenses/template/ai-kit/vendor/strix/LICENSE +201 -0
  8. ai_kit_python-1.4.2.dist-info/top_level.txt +1 -0
  9. aikit/.agents/skills/go-work/SKILL.md +8 -0
  10. aikit/.agents/skills/laravel-work/SKILL.md +8 -0
  11. aikit/.agents/skills/moodle-work/SKILL.md +8 -0
  12. aikit/.agents/skills/project-continuity/SKILL.md +34 -0
  13. aikit/.agents/skills/python-work/SKILL.md +8 -0
  14. aikit/.dockerignore +90 -0
  15. aikit/.gitattributes +3 -0
  16. aikit/.github/workflows/check-kit.yml +70 -0
  17. aikit/.github/workflows/publish-pypi.yml +108 -0
  18. aikit/.gitignore +60 -0
  19. aikit/BOOTSTRAP_PROMPT.md +18 -0
  20. aikit/CHANGELOG.md +85 -0
  21. aikit/CLAUDE.md +3 -0
  22. aikit/CONTRIBUTING.md +46 -0
  23. aikit/Dockerfile +44 -0
  24. aikit/KIMI.md +3 -0
  25. aikit/LICENSE +21 -0
  26. aikit/MANIFEST.in +22 -0
  27. aikit/MANUS.md +3 -0
  28. aikit/Makefile +70 -0
  29. aikit/README.md +1161 -0
  30. aikit/SECURITY.md +8 -0
  31. aikit/SKILL.md +105 -0
  32. aikit/VERSION +1 -0
  33. aikit/__init__.py +1 -0
  34. aikit/ai-kit/ADAPTERS.md +5 -0
  35. aikit/ai-kit/CONTAINERS.md +5 -0
  36. aikit/ai-kit/ENGINEERING.md +5 -0
  37. aikit/ai-kit/INTENT.md +5 -0
  38. aikit/ai-kit/MODELS.md +5 -0
  39. aikit/ai-kit/SKILLS.md +5 -0
  40. aikit/ai-kit/stacks/GO.md +5 -0
  41. aikit/ai-kit/stacks/LARAVEL.md +5 -0
  42. aikit/ai-kit/stacks/MOODLE.md +5 -0
  43. aikit/ai-kit/stacks/PYTHON.md +5 -0
  44. aikit/aikit_cli.py +59 -0
  45. aikit/deploy/k8s/install-preview-job.yaml +56 -0
  46. aikit/docker/build-requirements.txt +4 -0
  47. aikit/docker/check_version.py +29 -0
  48. aikit/docker/pypi-requirements.txt +3 -0
  49. aikit/docs/ADAPTER_PATH_FIX.md +23 -0
  50. aikit/docs/BENCHMARK.md +106 -0
  51. aikit/docs/CONTEXT7.md +33 -0
  52. aikit/docs/DECISIONS.md +22 -0
  53. aikit/docs/DEVELOPMENT_PLAN.md +16 -0
  54. aikit/docs/DIALOGUE_MEMORY.md +70 -0
  55. aikit/docs/DOCKER.md +74 -0
  56. aikit/docs/DOCKER_HUB_OVERVIEW.md +311 -0
  57. aikit/docs/EVALUATION.md +30 -0
  58. aikit/docs/IMPLEMENTATION.md +134 -0
  59. aikit/docs/MANUS_REVIEW.md +46 -0
  60. aikit/docs/PYPI.md +87 -0
  61. aikit/docs/PYPI_DESCRIPTION.md +103 -0
  62. aikit/docs/SECURITY_AUDIT.md +26 -0
  63. aikit/docs/STRIX.md +28 -0
  64. aikit/docs/V0_5_0.md +27 -0
  65. aikit/docs/V0_6_4.md +25 -0
  66. aikit/docs/V1_4_0.md +73 -0
  67. aikit/docs/V1_4_1.md +55 -0
  68. aikit/docs/V1_4_2.md +33 -0
  69. aikit/docs/WEB_DESIGN.md +72 -0
  70. aikit/docs/WINDOWS_CI_FIX.md +39 -0
  71. aikit/docs/adr/0000-template.md +24 -0
  72. aikit/docs/adr/0001-adaptive-model-routing.md +30 -0
  73. aikit/docs/adr/0002-template-separation.md +24 -0
  74. aikit/docs/adr/0003-agent-registry-and-router.md +24 -0
  75. aikit/docs/adr/0004-onboarding-and-project-facts.md +24 -0
  76. aikit/docs/adr/0005-client-settings-ownership.md +30 -0
  77. aikit/docs/adr/0006-routing-evidence-and-local-measurements.md +26 -0
  78. aikit/docs/adr/0007-generated-client-configuration-and-presets.md +34 -0
  79. aikit/docs/adr/0008-unified-cli-and-fact-drift.md +20 -0
  80. aikit/docs/adr/0009-provider-review-doctor-fix-and-ci-self-install.md +20 -0
  81. aikit/docs/adr/0010-metrics-analysis-and-gemini-verification.md +20 -0
  82. aikit/docs/adr/0011-evidence-lifecycle-and-evaluation.md +20 -0
  83. aikit/docs/adr/0012-measurement-led-routing.md +31 -0
  84. aikit/docs/adr/0013-docker-cli-image.md +24 -0
  85. aikit/docs/adr/0014-local-dialogue-memory.md +22 -0
  86. aikit/docs/history/original-bundle-checks.md +11 -0
  87. aikit/docs/history/v0.1-changelog.txt +37 -0
  88. aikit/docs/history/v0.10-changelog.md +12 -0
  89. aikit/docs/history/v0.2-changelog.md +35 -0
  90. aikit/docs/history/v0.3-changelog.md +25 -0
  91. aikit/docs/history/v0.4-changelog.md +31 -0
  92. aikit/docs/history/v0.5-changelog.md +14 -0
  93. aikit/docs/history/v0.6.4-changelog.md +12 -0
  94. aikit/docs/history/v0.6.5-v0.9-changelog.md +35 -0
  95. aikit/docs/history/v1.1.0-changelog.md +12 -0
  96. aikit/docs/history/v1.2.0-changelog.md +11 -0
  97. aikit/docs/history/verification-before-measurements.md +53 -0
  98. aikit/integrations/CONVENTIONS.md +3 -0
  99. aikit/integrations/README.md +7 -0
  100. aikit/integrations/agents.json +136 -0
  101. aikit/integrations/ai-kit-check.yml +66 -0
  102. aikit/integrations/ai-kit-cline.md +4 -0
  103. aikit/integrations/ai-kit-roo.md +4 -0
  104. aikit/integrations/ai-kit-windsurf.md +4 -0
  105. aikit/integrations/ai-kit.mdc +6 -0
  106. aikit/integrations/claude-settings.data-ask.json +23 -0
  107. aikit/integrations/claude-settings.git-ask.json +10 -0
  108. aikit/integrations/copilot-instructions.md +3 -0
  109. aikit/integrations/security-audit.json +135 -0
  110. aikit/integrations/strix.json +69 -0
  111. aikit/pyproject.toml +60 -0
  112. aikit/scripts/__init__.py +1 -0
  113. aikit/scripts/adapters.py +184 -0
  114. aikit/scripts/adaptive.py +167 -0
  115. aikit/scripts/adr.py +61 -0
  116. aikit/scripts/benchmark.py +543 -0
  117. aikit/scripts/changelog.py +55 -0
  118. aikit/scripts/check_distribution.py +178 -0
  119. aikit/scripts/check_kit.py +406 -0
  120. aikit/scripts/context.py +184 -0
  121. aikit/scripts/docker_test_usage.py +55 -0
  122. aikit/scripts/doctor.py +313 -0
  123. aikit/scripts/evaluate.py +125 -0
  124. aikit/scripts/install.py +1584 -0
  125. aikit/scripts/learning.py +260 -0
  126. aikit/scripts/memory.py +344 -0
  127. aikit/scripts/memory_import.py +177 -0
  128. aikit/scripts/memory_store.py +125 -0
  129. aikit/scripts/metrics.py +351 -0
  130. aikit/scripts/router.py +399 -0
  131. aikit/template/.agents/hooks/session-start.md +3 -0
  132. aikit/template/.agents/hooks/session-start.sh +21 -0
  133. aikit/template/.agents/skills/ai-kit-bootstrap/SKILL.md +14 -0
  134. aikit/template/.agents/skills/ai-kit-review/SKILL.md +11 -0
  135. aikit/template/.agents/skills/ai-kit-sync-context/SKILL.md +12 -0
  136. aikit/template/.agents/skills/context7-docs/SKILL.md +11 -0
  137. aikit/template/.agents/skills/design-extract/SKILL.md +9 -0
  138. aikit/template/.agents/skills/dotnet-work/SKILL.md +9 -0
  139. aikit/template/.agents/skills/filament-work/SKILL.md +9 -0
  140. aikit/template/.agents/skills/frontend-work/SKILL.md +9 -0
  141. aikit/template/.agents/skills/go-work/SKILL.md +9 -0
  142. aikit/template/.agents/skills/infra-work/SKILL.md +9 -0
  143. aikit/template/.agents/skills/java-work/SKILL.md +9 -0
  144. aikit/template/.agents/skills/laravel-blade-ui/SKILL.md +9 -0
  145. aikit/template/.agents/skills/laravel-work/SKILL.md +10 -0
  146. aikit/template/.agents/skills/library-work/SKILL.md +9 -0
  147. aikit/template/.agents/skills/moodle-work/SKILL.md +9 -0
  148. aikit/template/.agents/skills/php-work/SKILL.md +9 -0
  149. aikit/template/.agents/skills/project-continuity/SKILL.md +21 -0
  150. aikit/template/.agents/skills/python-work/SKILL.md +9 -0
  151. aikit/template/.agents/skills/rust-work/SKILL.md +9 -0
  152. aikit/template/.agents/skills/security-audit/SKILL.md +16 -0
  153. aikit/template/.agents/skills/security-audit/agents/openai.yaml +2 -0
  154. aikit/template/.agents/skills/strix/SKILL.md +16 -0
  155. aikit/template/.agents/skills/strix/agents/openai.yaml +2 -0
  156. aikit/template/.agents/skills/ui-review/SKILL.md +9 -0
  157. aikit/template/.agents/skills/web-design/SKILL.md +9 -0
  158. aikit/template/AGENTS.md +16 -0
  159. aikit/template/CHANGELOG.md +6 -0
  160. aikit/template/CLAUDE.md +5 -0
  161. aikit/template/GEMINI.md +4 -0
  162. aikit/template/KIMI.md +4 -0
  163. aikit/template/MANUS.md +4 -0
  164. aikit/template/PROJECT_CONTEXT.md +35 -0
  165. aikit/template/README.md +6 -0
  166. aikit/template/WIKI.md +37 -0
  167. aikit/template/ai-kit/ADAPTERS.md +100 -0
  168. aikit/template/ai-kit/BOOTSTRAP.md +15 -0
  169. aikit/template/ai-kit/CONTAINERS.md +63 -0
  170. aikit/template/ai-kit/CONTEXT7.md +96 -0
  171. aikit/template/ai-kit/CORE.md +23 -0
  172. aikit/template/ai-kit/ENGINEERING.md +34 -0
  173. aikit/template/ai-kit/MCP.md +17 -0
  174. aikit/template/ai-kit/METRICS.md +83 -0
  175. aikit/template/ai-kit/SECURITY-AUDIT.md +21 -0
  176. aikit/template/ai-kit/SECURITY.md +34 -0
  177. aikit/template/ai-kit/SKILLS.md +37 -0
  178. aikit/template/ai-kit/STRIX.md +44 -0
  179. aikit/template/ai-kit/UPSTREAM.md +38 -0
  180. aikit/template/ai-kit/WEB-DESIGN.md +37 -0
  181. aikit/template/ai-kit/profiles/OWNER.md +19 -0
  182. aikit/template/ai-kit/project.json +14 -0
  183. aikit/template/ai-kit/router/POLICY.md +79 -0
  184. aikit/template/ai-kit/router/providers/anthropic.json +44 -0
  185. aikit/template/ai-kit/router/providers/anthropic.md +14 -0
  186. aikit/template/ai-kit/router/providers/gemini.json +13 -0
  187. aikit/template/ai-kit/router/providers/gemini.md +10 -0
  188. aikit/template/ai-kit/router/providers/kimi.json +26 -0
  189. aikit/template/ai-kit/router/providers/kimi.md +13 -0
  190. aikit/template/ai-kit/router/providers/local.json +18 -0
  191. aikit/template/ai-kit/router/providers/local.md +10 -0
  192. aikit/template/ai-kit/router/providers/openai.json +48 -0
  193. aikit/template/ai-kit/router/providers/openai.md +14 -0
  194. aikit/template/ai-kit/router/routing.json +11 -0
  195. aikit/template/ai-kit/router/selection.json +14 -0
  196. aikit/template/ai-kit/settings.json +11 -0
  197. aikit/template/ai-kit/stacks/DOTNET.md +13 -0
  198. aikit/template/ai-kit/stacks/FILAMENT.md +18 -0
  199. aikit/template/ai-kit/stacks/FRONTEND.md +9 -0
  200. aikit/template/ai-kit/stacks/GO.md +19 -0
  201. aikit/template/ai-kit/stacks/INFRA.md +12 -0
  202. aikit/template/ai-kit/stacks/JAVA.md +13 -0
  203. aikit/template/ai-kit/stacks/LARAVEL.md +15 -0
  204. aikit/template/ai-kit/stacks/LIBRARY.md +9 -0
  205. aikit/template/ai-kit/stacks/MOODLE.md +12 -0
  206. aikit/template/ai-kit/stacks/PHP.md +11 -0
  207. aikit/template/ai-kit/stacks/PYTHON.md +11 -0
  208. aikit/template/ai-kit/stacks/RUST.md +18 -0
  209. aikit/template/ai-kit/vendor/security-audit/AI-AND-LLM.md +83 -0
  210. aikit/template/ai-kit/vendor/security-audit/ATTACK-CLASSES.md +130 -0
  211. aikit/template/ai-kit/vendor/security-audit/CLIENT-SIDE.md +83 -0
  212. aikit/template/ai-kit/vendor/security-audit/CLOUD-AND-DEPLOYMENT.md +86 -0
  213. aikit/template/ai-kit/vendor/security-audit/DATA-ISOLATION-AND-LIFECYCLE.md +84 -0
  214. aikit/template/ai-kit/vendor/security-audit/DESKTOP-MOBILE-AND-LOCAL-IPC.md +89 -0
  215. aikit/template/ai-kit/vendor/security-audit/HUNTING.md +251 -0
  216. aikit/template/ai-kit/vendor/security-audit/LICENSE +21 -0
  217. aikit/template/ai-kit/vendor/security-audit/MEMORY-SAFETY-AND-BINARY.md +101 -0
  218. aikit/template/ai-kit/vendor/security-audit/PROTOCOLS-RPC-AND-MESSAGING.md +81 -0
  219. aikit/template/ai-kit/vendor/security-audit/RECONNAISSANCE.md +156 -0
  220. aikit/template/ai-kit/vendor/security-audit/RESOURCE-EXHAUSTION-AND-AVAILABILITY.md +78 -0
  221. aikit/template/ai-kit/vendor/security-audit/SKILL.md +192 -0
  222. aikit/template/ai-kit/vendor/security-audit/SUPPLY-CHAIN-AND-RELEASE.md +73 -0
  223. aikit/template/ai-kit/vendor/security-audit/VALIDATION-AND-REPORTING.md +186 -0
  224. aikit/template/ai-kit/vendor/security-audit/WEB-PROTOCOL-AND-AUTH.md +105 -0
  225. aikit/template/ai-kit/vendor/security-audit/report-schema.json +461 -0
  226. aikit/template/ai-kit/vendor/security-audit/validate-coverage-ledger.cjs +872 -0
  227. aikit/template/ai-kit/vendor/security-audit/validate-coverage-ledger.test.cjs +740 -0
  228. aikit/template/ai-kit/vendor/security-audit/validate-findings.cjs +773 -0
  229. aikit/template/ai-kit/vendor/security-audit/validate-findings.test.cjs +652 -0
  230. aikit/template/ai-kit/vendor/strix/LICENSE +201 -0
  231. aikit/template/ai-kit/vendor/strix/api-security-testing/SKILL.md +61 -0
  232. aikit/template/ai-kit/vendor/strix/application-security-testing/SKILL.md +66 -0
  233. aikit/template/ai-kit/vendor/strix/ci-security-scanning-with-strix/SKILL.md +149 -0
  234. aikit/template/ai-kit/vendor/strix/find-security-vulnerabilities-in-code/SKILL.md +62 -0
  235. aikit/template/ai-kit/vendor/strix/fix-security-vulnerabilities-with-strix/SKILL.md +77 -0
  236. aikit/template/ai-kit/vendor/strix/managed-pentesting-with-strix/SKILL.md +321 -0
  237. aikit/template/ai-kit/vendor/strix/owasp-top-10-testing/SKILL.md +64 -0
  238. aikit/template/ai-kit/vendor/strix/penetration-testing-with-strix/SKILL.md +162 -0
  239. aikit/template/ai-kit/vendor/strix/web-app-penetration-testing/SKILL.md +54 -0
  240. aikit/template/ai-kit/web-design/LARAVEL.md +51 -0
  241. aikit/template/ai-kit/web-design/LIBRARIES.md +39 -0
  242. aikit/template/ai-kit/web-design/REVIEW.md +37 -0
  243. aikit/template/ai-kit/web-design/TOOLS.md +43 -0
  244. aikit/template/docs/DECISIONS.md +7 -0
  245. aikit/template/docs/adr/0000-template.md +20 -0
  246. aikit/template/docs/design/ACCEPTANCE.md +24 -0
  247. aikit/template/docs/design/BRIEF.md +26 -0
  248. aikit/template/docs/design/SYSTEM.md +30 -0
  249. aikit/templates/agent-secrets.ignore +19 -0
  250. aikit/templates/gitignore.private +160 -0
  251. aikit/templates/gitignore.team +139 -0
  252. aikit/tests/build_distribution.py +73 -0
  253. aikit/tests/docker_smoke.py +172 -0
  254. aikit/tests/fixtures/create-junction.ps1 +18 -0
  255. aikit/tests/fixtures/golden/claude-settings-local.json +58 -0
  256. aikit/tests/test_adapters.py +105 -0
  257. aikit/tests/test_aikit.py +79 -0
  258. aikit/tests/test_benchmark.py +241 -0
  259. aikit/tests/test_check_kit.py +203 -0
  260. aikit/tests/test_context.py +76 -0
  261. aikit/tests/test_context7.py +153 -0
  262. aikit/tests/test_context_selection.py +70 -0
  263. aikit/tests/test_distribution.py +181 -0
  264. aikit/tests/test_docker_image.py +63 -0
  265. aikit/tests/test_docker_test_usage.py +54 -0
  266. aikit/tests/test_doctor.py +148 -0
  267. aikit/tests/test_evaluate.py +66 -0
  268. aikit/tests/test_install.py +939 -0
  269. aikit/tests/test_learning.py +247 -0
  270. aikit/tests/test_memory.py +371 -0
  271. aikit/tests/test_metrics.py +209 -0
  272. aikit/tests/test_native.py +342 -0
  273. aikit/tests/test_onboarding.py +301 -0
  274. aikit/tests/test_router.py +336 -0
  275. aikit/tests/test_security_audit.py +237 -0
  276. aikit/tests/test_strix.py +245 -0
  277. aikit/tests/test_web_design.py +219 -0
  278. aikit/tests/wheel_smoke.py +104 -0
@@ -0,0 +1,148 @@
1
+ """Exercise the installed-project health check."""
2
+ import contextlib
3
+ import io
4
+ import json
5
+ from pathlib import Path
6
+ import shutil
7
+ import sys
8
+ import tempfile
9
+ import unittest
10
+
11
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts"))
12
+ import doctor
13
+ import install
14
+
15
+
16
+ class DoctorTests(unittest.TestCase):
17
+ def setUp(self):
18
+ self.temp = tempfile.TemporaryDirectory(prefix="ai-kit-doctor-")
19
+ self.addCleanup(self.temp.cleanup)
20
+ self.base = Path(self.temp.name).resolve()
21
+ self.target = self.base / "project with spaces"
22
+ self.source = self.base / "reference"
23
+ shutil.copytree(install.ROOT, self.source, ignore=shutil.ignore_patterns("__pycache__", ".git"))
24
+ self.initial_version = (self.source / "VERSION").read_text(encoding="utf-8").strip()
25
+
26
+ def apply(self, **options):
27
+ plan = install.build_plan(self.target, root=self.source, **options)
28
+ self.assertTrue(install.apply_plan(plan))
29
+ return plan
30
+
31
+ def write(self, path, data):
32
+ destination = self.target / path
33
+ destination.parent.mkdir(parents=True, exist_ok=True)
34
+ destination.write_bytes(data)
35
+
36
+ def examine(self):
37
+ return doctor.examine(self.target, root=self.source)
38
+
39
+ def test_healthy_installation_reports_no_errors_or_warnings(self):
40
+ self.apply()
41
+ # Runtime experiment notes are private data, not managed instruction/link sources.
42
+ self.write("ai-kit/.metrics/private-notes.md", b"[Runtime reference](missing.md)\n\xff")
43
+ report = self.examine()
44
+ self.assertEqual(report["errors"], [])
45
+ self.assertEqual(report["warnings"], [])
46
+ self.assertEqual(report["installed_version"], self.initial_version)
47
+
48
+ def test_module_map_drift_is_reported(self):
49
+ self.write("go.mod", b"module example.test/app\n\ngo 1.21\n")
50
+ self.apply()
51
+ report = self.examine()
52
+ self.assertFalse(any("module maps differ" in warning for warning in report["warnings"]))
53
+ project = json.loads((self.target / "ai-kit/project.json").read_text(encoding="utf-8"))
54
+ project["modules"][0]["path"] = "/api/"
55
+ (self.target / "ai-kit/project.json").write_text(json.dumps(project) + "\n", encoding="utf-8")
56
+ report = self.examine()
57
+ self.assertTrue(any("module maps differ" in warning for warning in report["warnings"]))
58
+
59
+ def test_user_edits_to_client_settings_are_not_reported(self):
60
+ self.apply(agents=["claude"], extras=["guards", "session-start"])
61
+ path = self.target / ".claude/settings.local.json"
62
+ settings = json.loads(path.read_text(encoding="utf-8"))
63
+ settings["model"] = "user-choice"
64
+ path.write_text(json.dumps(settings) + "\n", encoding="utf-8")
65
+ self.assertEqual(self.examine()["warnings"], [])
66
+
67
+ def test_removed_managed_client_entry_is_reported(self):
68
+ self.apply(agents=["claude"], extras=["guards"])
69
+ path = self.target / ".claude/settings.local.json"
70
+ settings = json.loads(path.read_text(encoding="utf-8"))
71
+ settings["permissions"]["ask"].remove("Bash(git push *)")
72
+ path.write_text(json.dumps(settings) + "\n", encoding="utf-8")
73
+ self.assertIn("AI-KIT entry missing from .claude/settings.local.json: permissions.ask Bash(git push *)",
74
+ self.examine()["warnings"])
75
+ path.write_text("[]\n", encoding="utf-8")
76
+ self.assertTrue(any(w.startswith("Cannot read AI-KIT entries") for w in self.examine()["warnings"]))
77
+
78
+ def test_missing_installation_is_reported(self):
79
+ self.target.mkdir(parents=True)
80
+ report = self.examine()
81
+ self.assertTrue(any("No installer state" in error for error in report["errors"]))
82
+
83
+ def test_modified_managed_file_is_reported(self):
84
+ self.apply()
85
+ self.write("ai-kit/CORE.md", b"Locally edited core\n")
86
+ report = self.examine()
87
+ self.assertTrue(any("Modified after installation" in warning and "ai-kit/CORE.md" in warning
88
+ for warning in report["warnings"]))
89
+
90
+ def test_accepted_local_adaptation_is_not_a_modification_warning(self):
91
+ self.apply()
92
+ self.write("ai-kit/CORE.md", b"Reviewed semantic merge\n")
93
+ self.apply(accept_local=["ai-kit/CORE.md"])
94
+ report = self.examine()
95
+ self.assertEqual(report["errors"], [])
96
+ self.assertFalse(any("Modified after installation" in warning for warning in report["warnings"]))
97
+
98
+ def test_missing_owned_document_is_reported(self):
99
+ self.apply()
100
+ (self.target / "WIKI.md").unlink()
101
+ report = self.examine()
102
+ self.assertTrue(any("Owned project document missing: WIKI.md" in warning
103
+ for warning in report["warnings"]))
104
+
105
+ def test_broken_kit_link_is_reported(self):
106
+ self.apply()
107
+ self.write("WIKI.md", b"[Missing](no-such-file.md)\n")
108
+ report = self.examine()
109
+ self.assertTrue(any("missing link" in warning and "WIKI.md" in warning
110
+ for warning in report["warnings"]))
111
+
112
+ def test_stale_provider_verification_is_reported(self):
113
+ self.apply()
114
+ provider = self.target / "ai-kit" / "router" / "providers" / "openai.json"
115
+ config = json.loads(provider.read_text(encoding="utf-8"))
116
+ config["verified_documentation_date"] = "2025-01-01"
117
+ provider.write_text(json.dumps(config, indent=2) + "\n", encoding="utf-8")
118
+ report = self.examine()
119
+ self.assertTrue(any("older than" in warning for warning in report["warnings"]))
120
+
121
+ def test_main_returns_one_when_errors_exist(self):
122
+ with contextlib.redirect_stdout(io.StringIO()):
123
+ self.assertEqual(doctor.main([str(self.target), "--root", str(self.source)]), 1)
124
+
125
+ def test_main_returns_zero_for_healthy_installation(self):
126
+ self.apply()
127
+ with contextlib.redirect_stdout(io.StringIO()):
128
+ self.assertEqual(doctor.main([str(self.target), "--root", str(self.source)]), 0)
129
+
130
+ def test_fix_restores_missing_managed_file(self):
131
+ self.apply()
132
+ (self.target / "ai-kit/CORE.md").unlink()
133
+ self.assertTrue(any("Missing managed file: ai-kit/CORE.md" in error
134
+ for error in self.examine()["errors"]))
135
+ with contextlib.redirect_stdout(io.StringIO()):
136
+ code = doctor.main([str(self.target), "--root", str(self.source), "--fix"])
137
+ self.assertEqual(code, 0)
138
+ self.assertTrue((self.target / "ai-kit/CORE.md").is_file())
139
+ self.assertEqual(self.examine()["errors"], [])
140
+
141
+ def test_fix_is_a_noop_for_a_healthy_installation(self):
142
+ self.apply()
143
+ with contextlib.redirect_stdout(io.StringIO()):
144
+ self.assertEqual(doctor.main([str(self.target), "--root", str(self.source), "--fix"]), 0)
145
+
146
+
147
+ if __name__ == "__main__":
148
+ unittest.main()
@@ -0,0 +1,66 @@
1
+ """Exercise private task packs and measurement-pair coverage reports."""
2
+ import contextlib
3
+ import io
4
+ import json
5
+ from pathlib import Path
6
+ import sys
7
+ import tempfile
8
+ import unittest
9
+
10
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts"))
11
+ import evaluate
12
+ import metrics
13
+
14
+
15
+ def record(task_id, arm, outcome="correct"):
16
+ return {"schema": 2, "task_id": task_id, "experiment": "trial", "arm": arm,
17
+ "kit_version": "test", "outcome": outcome, "checks": "passed" if outcome == "correct" else "failed",
18
+ "rework": 0, "escalations": 0,
19
+ "attempts": [{"provider": "provider", "model": "model", "effort": None,
20
+ "disposition": "succeeded" if outcome == "correct" else "failed",
21
+ "duration_seconds": None, "input_tokens": None, "cached_input_tokens": None,
22
+ "output_tokens": None, "reasoning_tokens": None, "cost": None}]}
23
+
24
+
25
+ class EvaluationTests(unittest.TestCase):
26
+ def setUp(self):
27
+ self.temp = tempfile.TemporaryDirectory(prefix="ai-kit-evaluate-")
28
+ self.addCleanup(self.temp.cleanup)
29
+ self.root = Path(self.temp.name).resolve()
30
+ self.project = self.root / "project"
31
+ self.project.mkdir()
32
+ self.pack_path = self.root / "tasks.json"
33
+
34
+ def test_scaffold_is_preview_first_and_refuses_overwrite(self):
35
+ plan = evaluate.scaffold_plan(self.pack_path, "trial", ["task-01", "task-02"])
36
+ self.assertTrue(plan["changed"])
37
+ self.assertFalse(self.pack_path.exists())
38
+ self.assertTrue(evaluate.apply_scaffold(plan))
39
+ self.assertTrue(self.pack_path.is_file())
40
+ with self.assertRaises(ValueError):
41
+ evaluate.scaffold_plan(self.pack_path, "other", ["task-01"])
42
+
43
+ def test_coverage_reports_missing_baseline_kit_pairs_and_unexpected_records(self):
44
+ plan = evaluate.scaffold_plan(self.pack_path, "trial", ["task-01", "task-02"])
45
+ evaluate.apply_scaffold(plan)
46
+ metrics.record_task(self.project, record("task-01", "baseline"), apply=True)
47
+ metrics.record_task(self.project, record("task-01", "kit"), apply=True)
48
+ metrics.record_task(self.project, record("task-02", "baseline", "incorrect"), apply=True)
49
+ metrics.record_task(self.project, record("other", "kit"), apply=True)
50
+ report = evaluate.coverage(self.project, self.pack_path)
51
+ self.assertEqual(report["complete_pairs"], 1)
52
+ self.assertEqual(report["missing"], [{"task_id": "task-02", "arms": ["kit"]}])
53
+ self.assertEqual(report["unexpected_records"], [{"task_id": "other", "arm": "kit"}])
54
+ self.assertEqual(report["reviewed_outcomes"], {"correct": 2, "incorrect": 1, "incomplete": 0})
55
+
56
+ def test_validation_and_cli_reject_nonopaque_task_content(self):
57
+ with self.assertRaises(ValueError):
58
+ evaluate.validate_pack({"schema": 1, "experiment": "trial", "arms": ["baseline", "kit"],
59
+ "tasks": [{"task_id": "please fix payment bug"}]})
60
+ with contextlib.redirect_stderr(io.StringIO()):
61
+ self.assertEqual(evaluate.main(["scaffold", "--output", str(self.pack_path), "--experiment", "trial",
62
+ "--task", "task one"]), 1)
63
+
64
+
65
+ if __name__ == "__main__":
66
+ unittest.main()