pi-dev-team 0.2.0

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 (780) hide show
  1. package/LICENSE +21 -0
  2. package/PORTING.md +134 -0
  3. package/README.md +207 -0
  4. package/UPSTREAM.json +64 -0
  5. package/agents/Explore.md +15 -0
  6. package/agents/a11y-review.md +118 -0
  7. package/agents/adr-author.md +70 -0
  8. package/agents/ai-provenance-review.md +120 -0
  9. package/agents/angular-reactivity-review.md +95 -0
  10. package/agents/arch-review.md +135 -0
  11. package/agents/architect.md +78 -0
  12. package/agents/autoship-batch-proposer.md +69 -0
  13. package/agents/claude-setup-review.md +136 -0
  14. package/agents/codebase-recon.md +184 -0
  15. package/agents/component-architecture-review.md +119 -0
  16. package/agents/concurrency-review.md +109 -0
  17. package/agents/correctness-review.md +290 -0
  18. package/agents/data-flow-tracer.md +120 -0
  19. package/agents/doc-review.md +165 -0
  20. package/agents/domain-review.md +136 -0
  21. package/agents/general-purpose.md +10 -0
  22. package/agents/gherkin-quality-critic.md +113 -0
  23. package/agents/js-fp-review.md +114 -0
  24. package/agents/mutation-kill.md +684 -0
  25. package/agents/naming-review.md +142 -0
  26. package/agents/orchestrator.md +339 -0
  27. package/agents/performance-review.md +105 -0
  28. package/agents/plan-review-acceptance.md +115 -0
  29. package/agents/plan-review-design.md +90 -0
  30. package/agents/plan-review-parallelization.md +84 -0
  31. package/agents/plan-review-strategic.md +96 -0
  32. package/agents/plan-review-ux.md +110 -0
  33. package/agents/platform-engineer.md +64 -0
  34. package/agents/product-manager.md +68 -0
  35. package/agents/progress-guardian.md +79 -0
  36. package/agents/qa-engineer.md +289 -0
  37. package/agents/quality-reviewer.md +132 -0
  38. package/agents/react-reactivity-review.md +102 -0
  39. package/agents/refactor-opportunity-review.md +128 -0
  40. package/agents/security-engineer.md +60 -0
  41. package/agents/security-review.md +218 -0
  42. package/agents/session-analysis.md +95 -0
  43. package/agents/software-engineer.md +105 -0
  44. package/agents/spec-compliance-review.md +100 -0
  45. package/agents/spec-reviewer.md +114 -0
  46. package/agents/structure-review.md +146 -0
  47. package/agents/tech-writer.md +84 -0
  48. package/agents/test-review.md +246 -0
  49. package/agents/test-smell-review.md +188 -0
  50. package/agents/token-efficiency-review.md +139 -0
  51. package/agents/ui-ux-designer.md +54 -0
  52. package/agents/vue-reactivity-review.md +95 -0
  53. package/bin/__pycache__/claudecpython-314.pyc +0 -0
  54. package/bin/claude +258 -0
  55. package/docs/upstream/.pages +1 -0
  56. package/docs/upstream/CHANGELOG.md +2586 -0
  57. package/docs/upstream/README.md +155 -0
  58. package/docs/upstream/agent-architecture.md +214 -0
  59. package/docs/upstream/agent_info.md +187 -0
  60. package/docs/upstream/artifact-migration.md +124 -0
  61. package/docs/upstream/code-intelligence-nudge.md +149 -0
  62. package/docs/upstream/code-review-process.md +294 -0
  63. package/docs/upstream/concurrent-use.md +73 -0
  64. package/docs/upstream/context-management.md +111 -0
  65. package/docs/upstream/developer-notes.md +280 -0
  66. package/docs/upstream/diagrams/architecture-overview.svg +101 -0
  67. package/docs/upstream/diagrams/review-dispatch.svg +139 -0
  68. package/docs/upstream/diagrams/team-agents.svg +128 -0
  69. package/docs/upstream/diagrams/test-improve-flow.svg +166 -0
  70. package/docs/upstream/diagrams/workflow-linear.svg +66 -0
  71. package/docs/upstream/diagrams/workflow-three-phase.svg +200 -0
  72. package/docs/upstream/eval-maintenance.md +95 -0
  73. package/docs/upstream/eval-running-guide.md +147 -0
  74. package/docs/upstream/eval-system.md +291 -0
  75. package/docs/upstream/session-review-oss-complements.md +75 -0
  76. package/docs/upstream/session-review.md +212 -0
  77. package/docs/upstream/skills.md +188 -0
  78. package/docs/upstream/team-structure.md +21 -0
  79. package/docs/upstream/telemetry-ci-access.md +129 -0
  80. package/docs/upstream/telemetry-repo-security.md +120 -0
  81. package/docs/upstream/test-evaluation.md +277 -0
  82. package/docs/upstream/test-improve.md +154 -0
  83. package/docs/upstream/triage-workflow.md +282 -0
  84. package/docs/upstream/workflows.md +289 -0
  85. package/extensions/dev-team/index.ts +539 -0
  86. package/extensions/dev-team/lib/agents.ts +272 -0
  87. package/extensions/dev-team/lib/ai-credits.ts +92 -0
  88. package/extensions/dev-team/lib/autocompact.ts +81 -0
  89. package/extensions/dev-team/lib/child-run.ts +102 -0
  90. package/extensions/dev-team/lib/config.ts +236 -0
  91. package/extensions/dev-team/lib/gh-command.ts +103 -0
  92. package/extensions/dev-team/lib/github-style.ts +307 -0
  93. package/extensions/dev-team/lib/hooks.ts +350 -0
  94. package/extensions/dev-team/lib/metrics.ts +115 -0
  95. package/extensions/dev-team/lib/safe-read.ts +49 -0
  96. package/extensions/dev-team/lib/session-files.ts +57 -0
  97. package/extensions/dev-team/lib/session-spend.ts +123 -0
  98. package/extensions/dev-team/lib/shell-scan.ts +205 -0
  99. package/extensions/dev-team/lib/skills.ts +213 -0
  100. package/extensions/dev-team/lib/subagent-render.ts +245 -0
  101. package/extensions/dev-team/lib/subagent-types.ts +164 -0
  102. package/extensions/dev-team/lib/subagent.ts +596 -0
  103. package/extensions/dev-team/lib/terminal-text.ts +54 -0
  104. package/extensions/dev-team/lib/tools-misc.ts +152 -0
  105. package/extensions/dev-team/lib/transcript.ts +110 -0
  106. package/extensions/dev-team/lib/trust.ts +52 -0
  107. package/extensions/dev-team/lib/usage-breakdown.ts +176 -0
  108. package/extensions/dev-team/lib/usage-chart.ts +153 -0
  109. package/extensions/dev-team/lib/usage-command.ts +107 -0
  110. package/extensions/dev-team/lib/usage-history.ts +203 -0
  111. package/extensions/dev-team/lib/usage-render.ts +225 -0
  112. package/extensions/dev-team/lib/usage-split-bar.ts +127 -0
  113. package/extensions/dev-team/lib/usage-state.ts +116 -0
  114. package/extensions/dev-team/lib/usage-text.ts +159 -0
  115. package/extensions/dev-team/lib/usage-view.ts +109 -0
  116. package/hooks/__pycache__/refactor_test_freeze_guard.cpython-314.pyc +0 -0
  117. package/hooks/agent_dispatch_ledger.py +190 -0
  118. package/hooks/autocompact_setup_nudge.py +99 -0
  119. package/hooks/bash_retry_guard.py +228 -0
  120. package/hooks/boundary_events_write_guard.py +352 -0
  121. package/hooks/code_intelligence_nudge.py +293 -0
  122. package/hooks/code_intelligence_turn_mark.py +317 -0
  123. package/hooks/codegraph_bootstrap.py +139 -0
  124. package/hooks/contract_version_guard.py +362 -0
  125. package/hooks/cost_meter.py +106 -0
  126. package/hooks/destructive-commands.json +62 -0
  127. package/hooks/destructive_guard.py +477 -0
  128. package/hooks/eval_compliance_check.py +440 -0
  129. package/hooks/guards.json +17 -0
  130. package/hooks/hooks.json +323 -0
  131. package/hooks/internal_double_gate.py +296 -0
  132. package/hooks/js_fp_review.py +212 -0
  133. package/hooks/knowledge_index.py +119 -0
  134. package/hooks/lib/__pycache__/artifact_paths.cpython-314.pyc +0 -0
  135. package/hooks/lib/__pycache__/atomic_state.cpython-314.pyc +0 -0
  136. package/hooks/lib/__pycache__/autocompact_config.cpython-314.pyc +0 -0
  137. package/hooks/lib/__pycache__/boundary_events.cpython-314.pyc +0 -0
  138. package/hooks/lib/__pycache__/doc_classification.cpython-314.pyc +0 -0
  139. package/hooks/lib/__pycache__/gh_pr_create_detect.cpython-314.pyc +0 -0
  140. package/hooks/lib/__pycache__/git_safe_diff.cpython-314.pyc +0 -0
  141. package/hooks/lib/__pycache__/instrument_log.cpython-314.pyc +0 -0
  142. package/hooks/lib/__pycache__/metrics_query.cpython-314.pyc +0 -0
  143. package/hooks/lib/__pycache__/plugin_version.cpython-314.pyc +0 -0
  144. package/hooks/lib/__pycache__/pre_commit_doc_classifier.cpython-314.pyc +0 -0
  145. package/hooks/lib/__pycache__/review_agent_registry.cpython-314.pyc +0 -0
  146. package/hooks/lib/__pycache__/review_gate_corroboration.cpython-314.pyc +0 -0
  147. package/hooks/lib/__pycache__/review_gate_hash.cpython-314.pyc +0 -0
  148. package/hooks/lib/__pycache__/review_verdicts.cpython-314.pyc +0 -0
  149. package/hooks/lib/__pycache__/stdin_json.cpython-314.pyc +0 -0
  150. package/hooks/lib/__pycache__/stryker_invocation.cpython-314.pyc +0 -0
  151. package/hooks/lib/__pycache__/telemetry_consent.cpython-314.pyc +0 -0
  152. package/hooks/lib/__pycache__/test_file_classify.cpython-314.pyc +0 -0
  153. package/hooks/lib/__pycache__/token_efficiency_limits.cpython-314.pyc +0 -0
  154. package/hooks/lib/__pycache__/verify_guard_state.cpython-314.pyc +0 -0
  155. package/hooks/lib/__pycache__/xunit_v3_operator_gate.cpython-314.pyc +0 -0
  156. package/hooks/lib/agent_skill_hints.py +74 -0
  157. package/hooks/lib/artifact_paths.py +263 -0
  158. package/hooks/lib/atomic_state.py +557 -0
  159. package/hooks/lib/autocompact_config.py +103 -0
  160. package/hooks/lib/autoship_log.py +106 -0
  161. package/hooks/lib/banned_scripts_policy.py +51 -0
  162. package/hooks/lib/boundary_events.py +436 -0
  163. package/hooks/lib/build_knowledge_index.py +504 -0
  164. package/hooks/lib/build_skills_index.py +361 -0
  165. package/hooks/lib/build_state.py +116 -0
  166. package/hooks/lib/classify_ship_outcome.py +126 -0
  167. package/hooks/lib/config_changelog_schema.py +115 -0
  168. package/hooks/lib/cost_meter.py +955 -0
  169. package/hooks/lib/doc_classification.py +116 -0
  170. package/hooks/lib/gh_pr_create_detect.py +136 -0
  171. package/hooks/lib/git_safe_diff.py +123 -0
  172. package/hooks/lib/instrument_log.py +66 -0
  173. package/hooks/lib/iteration_journal_gate.py +197 -0
  174. package/hooks/lib/knowledge_index_paths.py +88 -0
  175. package/hooks/lib/mcp_json_repowise.py +177 -0
  176. package/hooks/lib/metrics_query.py +202 -0
  177. package/hooks/lib/minimal_yaml.py +434 -0
  178. package/hooks/lib/plugin_version.py +142 -0
  179. package/hooks/lib/pre_commit_detect.py +537 -0
  180. package/hooks/lib/pre_commit_doc_classifier.py +126 -0
  181. package/hooks/lib/pricing.py +118 -0
  182. package/hooks/lib/report_pdf.py +371 -0
  183. package/hooks/lib/review_agent_registry.py +142 -0
  184. package/hooks/lib/review_dispatch_ledger.py +101 -0
  185. package/hooks/lib/review_gate_corroboration.py +521 -0
  186. package/hooks/lib/review_gate_hash.py +252 -0
  187. package/hooks/lib/review_gate_normalized_hash.py +1115 -0
  188. package/hooks/lib/review_verdicts.py +301 -0
  189. package/hooks/lib/run_report.py +160 -0
  190. package/hooks/lib/skill_categories.yaml +125 -0
  191. package/hooks/lib/stdin_json.py +57 -0
  192. package/hooks/lib/stryker_invocation.py +102 -0
  193. package/hooks/lib/telemetry_consent.py +41 -0
  194. package/hooks/lib/telemetry_report.py +108 -0
  195. package/hooks/lib/test_file_classify.py +160 -0
  196. package/hooks/lib/token_efficiency_limits.py +51 -0
  197. package/hooks/lib/turn_identity.py +77 -0
  198. package/hooks/lib/verify_guard_state.py +110 -0
  199. package/hooks/lib/workflow_state.py +206 -0
  200. package/hooks/lib/xunit_v3_operator_gate.py +596 -0
  201. package/hooks/mcp_json_repowise_nudge.py +74 -0
  202. package/hooks/mutation_adapters/__init__.py +7 -0
  203. package/hooks/mutation_adapters/__pycache__/__init__.cpython-314.pyc +0 -0
  204. package/hooks/mutation_adapters/__pycache__/lib.cpython-314.pyc +0 -0
  205. package/hooks/mutation_adapters/__pycache__/mutmut.cpython-314.pyc +0 -0
  206. package/hooks/mutation_adapters/__pycache__/pitest.cpython-314.pyc +0 -0
  207. package/hooks/mutation_adapters/__pycache__/stryker.cpython-314.pyc +0 -0
  208. package/hooks/mutation_adapters/__pycache__/stryker_net.cpython-314.pyc +0 -0
  209. package/hooks/mutation_adapters/lib.py +478 -0
  210. package/hooks/mutation_adapters/mutmut.py +188 -0
  211. package/hooks/mutation_adapters/pitest.py +266 -0
  212. package/hooks/mutation_adapters/stryker.py +157 -0
  213. package/hooks/mutation_adapters/stryker_net.py +264 -0
  214. package/hooks/mutation_gate.py +193 -0
  215. package/hooks/mutation_testing_smoke_gate.py +371 -0
  216. package/hooks/pending_review_notify.py +121 -0
  217. package/hooks/phase_marker.py +138 -0
  218. package/hooks/post_compact_state_reinject.py +180 -0
  219. package/hooks/post_format.py +115 -0
  220. package/hooks/pre_commit_knowledge_index.py +128 -0
  221. package/hooks/pre_commit_review.py +66 -0
  222. package/hooks/pre_pr_review.py +694 -0
  223. package/hooks/pre_tool_guard.py +405 -0
  224. package/hooks/py.sh +73 -0
  225. package/hooks/refactor-bash-write-patterns.json +29 -0
  226. package/hooks/refactor_test_bash_guard.py +253 -0
  227. package/hooks/refactor_test_freeze_guard.py +139 -0
  228. package/hooks/refactor_test_revert_guard.py +186 -0
  229. package/hooks/repo_review_nudge.py +287 -0
  230. package/hooks/review_verdict_recorder.py +464 -0
  231. package/hooks/scan_bash_command_for_banned_scripts.py +428 -0
  232. package/hooks/scan_worktree_for_banned_scripts.py +238 -0
  233. package/hooks/session_learning_trigger.py +248 -0
  234. package/hooks/skills_index.py +126 -0
  235. package/hooks/stryker_xunit_shim_guard.py +571 -0
  236. package/hooks/subagent_completion_guard.py +309 -0
  237. package/hooks/subagent_skill_context.py +139 -0
  238. package/hooks/task_completion_metrics.py +216 -0
  239. package/hooks/tdd_guard.py +229 -0
  240. package/hooks/telemetry.py +341 -0
  241. package/hooks/token_efficiency_review.py +194 -0
  242. package/hooks/verify_guard.py +183 -0
  243. package/hooks/verify_guard_edit_marker.py +73 -0
  244. package/hooks/version_check.py +173 -0
  245. package/knowledge/accepted-risks-schema.md +98 -0
  246. package/knowledge/adr-decision-criteria.md +64 -0
  247. package/knowledge/adversarial-review-protocol.md +139 -0
  248. package/knowledge/agent-registry.md +228 -0
  249. package/knowledge/agent-review-methodology.md +80 -0
  250. package/knowledge/ai-friendly-repo-guidelines.md +67 -0
  251. package/knowledge/architecture-assessment.md +96 -0
  252. package/knowledge/artifact-lifecycle.md +57 -0
  253. package/knowledge/cd-maturity-model.md +82 -0
  254. package/knowledge/cd-test-architecture.md +190 -0
  255. package/knowledge/ci-cd-file-scope.md +24 -0
  256. package/knowledge/codegraph-vs-graphify.md +192 -0
  257. package/knowledge/component-test-patterns.md +139 -0
  258. package/knowledge/database-change-management.md +80 -0
  259. package/knowledge/database-test-patterns.md +79 -0
  260. package/knowledge/decision-defaults.md +88 -0
  261. package/knowledge/dependency-breaking-techniques.md +116 -0
  262. package/knowledge/deployment-pipeline.md +86 -0
  263. package/knowledge/design-smells.md +122 -0
  264. package/knowledge/directory-enumeration.md +38 -0
  265. package/knowledge/domain-modeling.md +123 -0
  266. package/knowledge/evidence-bundle.md +90 -0
  267. package/knowledge/exploratory-testing-field-guide.md +122 -0
  268. package/knowledge/failure-routing.md +28 -0
  269. package/knowledge/fixture-construction.md +56 -0
  270. package/knowledge/frontend-component-architecture.md +139 -0
  271. package/knowledge/gherkin-quality-review-dispatch.md +135 -0
  272. package/knowledge/index.json +6766 -0
  273. package/knowledge/internal-collaborator-doubling.md +101 -0
  274. package/knowledge/legacy-test-strategy.md +71 -0
  275. package/knowledge/long-run-waiting.md +66 -0
  276. package/knowledge/microservice-testing.md +71 -0
  277. package/knowledge/model-pricing.json +23 -0
  278. package/knowledge/mutation-score-formulas.md +60 -0
  279. package/knowledge/object-calisthenics.md +147 -0
  280. package/knowledge/oracle-provenance.md +94 -0
  281. package/knowledge/orchestrator-script-implementation.md +185 -0
  282. package/knowledge/owasp-detection.md +148 -0
  283. package/knowledge/plan-review-rubric.md +56 -0
  284. package/knowledge/proxy-connectivity.md +62 -0
  285. package/knowledge/reactive-effect-patterns.md +73 -0
  286. package/knowledge/recon-inventory-excludes.txt +32 -0
  287. package/knowledge/references/bdd-value-guide.md +61 -0
  288. package/knowledge/references/csharp-http-client-testing.md +264 -0
  289. package/knowledge/release-strategies.md +74 -0
  290. package/knowledge/report-output-location.md +117 -0
  291. package/knowledge/report-pdf-integration.md +63 -0
  292. package/knowledge/report-print.css +129 -0
  293. package/knowledge/report-template.md +114 -0
  294. package/knowledge/report-to-pdf.md +69 -0
  295. package/knowledge/request-processing-flow.md +63 -0
  296. package/knowledge/result-verification.md +52 -0
  297. package/knowledge/review-agent-output-contract.md +121 -0
  298. package/knowledge/review-lens-classification.md +113 -0
  299. package/knowledge/review-rubric.md +62 -0
  300. package/knowledge/review-template.md +104 -0
  301. package/knowledge/rule-fixtures/A02.insecure-random-js/negative.js +1 -0
  302. package/knowledge/rule-fixtures/A02.insecure-random-js/positive.js +1 -0
  303. package/knowledge/rule-fixtures/A02.weak-hashing-md5/negative.py +1 -0
  304. package/knowledge/rule-fixtures/A02.weak-hashing-md5/positive.py +1 -0
  305. package/knowledge/rule-fixtures/A03.command-injection/negative.js +1 -0
  306. package/knowledge/rule-fixtures/A03.command-injection/positive.js +1 -0
  307. package/knowledge/rule-fixtures/A03.sql-injection/negative.js +1 -0
  308. package/knowledge/rule-fixtures/A03.sql-injection/positive.js +1 -0
  309. package/knowledge/rule-fixtures/A03.xss-innerhtml/negative.js +1 -0
  310. package/knowledge/rule-fixtures/A03.xss-innerhtml/positive.js +1 -0
  311. package/knowledge/rule-fixtures/A05.cors-wildcard/negative.js +1 -0
  312. package/knowledge/rule-fixtures/A05.cors-wildcard/positive.js +1 -0
  313. package/knowledge/rule-fixtures/A05.default-credentials/negative.js +1 -0
  314. package/knowledge/rule-fixtures/A05.default-credentials/positive.js +1 -0
  315. package/knowledge/rule-fixtures/A07.jwt-alg-none/negative.js +1 -0
  316. package/knowledge/rule-fixtures/A07.jwt-alg-none/positive.js +1 -0
  317. package/knowledge/rule-fixtures/A08.binary-formatter/negative.cs +1 -0
  318. package/knowledge/rule-fixtures/A08.binary-formatter/positive.cs +1 -0
  319. package/knowledge/rule-fixtures/A08.js-eval/negative.js +1 -0
  320. package/knowledge/rule-fixtures/A08.js-eval/positive.js +1 -0
  321. package/knowledge/rule-fixtures/A08.object-input-stream/negative.java +1 -0
  322. package/knowledge/rule-fixtures/A08.object-input-stream/positive.java +1 -0
  323. package/knowledge/schemas/disposition-register-v1.json +65 -0
  324. package/knowledge/schemas/recon-envelope-v1.json +198 -0
  325. package/knowledge/schemas/unified-finding-v1.json +72 -0
  326. package/knowledge/security-primitives-contract.md +301 -0
  327. package/knowledge/security-review-rule-map.yaml +107 -0
  328. package/knowledge/skills-registry.md +72 -0
  329. package/knowledge/task-size-classifier.md +103 -0
  330. package/knowledge/telemetry-schema.md +881 -0
  331. package/knowledge/test-automation-maturity.md +56 -0
  332. package/knowledge/test-automation-principles.md +71 -0
  333. package/knowledge/test-cadence-tradeoffs.md +68 -0
  334. package/knowledge/test-doubles.md +105 -0
  335. package/knowledge/test-file-indicators.md +22 -0
  336. package/knowledge/test-layer-gates.md +35 -0
  337. package/knowledge/test-matrix-examples/django-batch.md +24 -0
  338. package/knowledge/test-matrix-examples/dotnet-grpc-fronting-api.md +90 -0
  339. package/knowledge/test-matrix-examples/dotnet-http-consumer.md +131 -0
  340. package/knowledge/test-matrix-examples/react-node-spa.md +24 -0
  341. package/knowledge/test-matrix-examples/spring-boot-service.md +25 -0
  342. package/knowledge/test-matrix-examples/ssr-htmx.md +24 -0
  343. package/knowledge/test-organization.md +70 -0
  344. package/knowledge/test-pyramid.md +84 -0
  345. package/knowledge/test-refactoring.md +67 -0
  346. package/knowledge/test-review-division-of-labor.md +85 -0
  347. package/knowledge/test-smells.md +80 -0
  348. package/knowledge/test-stack-profiles/bdd-frameworks.md +235 -0
  349. package/knowledge/test-stack-profiles/django.md +13 -0
  350. package/knowledge/test-stack-profiles/dotnet.md +18 -0
  351. package/knowledge/test-stack-profiles/go.md +16 -0
  352. package/knowledge/test-stack-profiles/node.md +16 -0
  353. package/knowledge/test-stack-profiles/react.md +12 -0
  354. package/knowledge/test-stack-profiles/spring-boot.md +16 -0
  355. package/knowledge/test-stack-profiles/ssr-htmx.md +14 -0
  356. package/knowledge/test-stack-profiles/vue.md +12 -0
  357. package/knowledge/test-strategy.md +70 -0
  358. package/knowledge/testability-patterns.md +240 -0
  359. package/knowledge/testing-quadrants.md +44 -0
  360. package/knowledge/testing-techniques/approval.md +15 -0
  361. package/knowledge/testing-techniques/chaos.md +17 -0
  362. package/knowledge/testing-techniques/fuzz.md +15 -0
  363. package/knowledge/testing-techniques/property-based.md +15 -0
  364. package/knowledge/testing-techniques/schema-validation.md +15 -0
  365. package/knowledge/testing-techniques/screenshot.md +15 -0
  366. package/knowledge/three-phase-workflow.md +198 -0
  367. package/knowledge/value-patterns.md +55 -0
  368. package/knowledge/verification-mode.md +116 -0
  369. package/knowledge/virtual-service-libraries.md +75 -0
  370. package/knowledge/wave-consolidation-guidance.md +21 -0
  371. package/overrides/agents/Explore.md +15 -0
  372. package/overrides/agents/general-purpose.md +10 -0
  373. package/overrides/notes/autoship.md +6 -0
  374. package/overrides/notes/issues-from-assessment.md +3 -0
  375. package/overrides/notes/issues-from-plan.md +3 -0
  376. package/overrides/notes/mutation-night-watch.md +3 -0
  377. package/overrides/notes/mutation-testing.md +3 -0
  378. package/overrides/notes/pr.md +7 -0
  379. package/overrides/notes/project-init.md +6 -0
  380. package/overrides/notes/setup.md +13 -0
  381. package/overrides/notes/specs.md +3 -0
  382. package/overrides/skills/headless-run/SKILL.md +45 -0
  383. package/overrides/skills/upgrade/SKILL.md +30 -0
  384. package/overrides/skills/version/SKILL.md +25 -0
  385. package/package.json +36 -0
  386. package/scripts/authoring_digest.py +93 -0
  387. package/scripts/autoship_discover.py +121 -0
  388. package/scripts/autoship_group.py +409 -0
  389. package/scripts/autoship_proposals.py +494 -0
  390. package/scripts/autoship_queue.py +291 -0
  391. package/scripts/autoship_reclaim.py +495 -0
  392. package/scripts/build_jobs.py +108 -0
  393. package/scripts/build_rollback_point.py +240 -0
  394. package/scripts/build_slice_scope.py +157 -0
  395. package/scripts/build_wave.py +109 -0
  396. package/scripts/build_wave_reconcile.py +252 -0
  397. package/scripts/build_worktree_baseref.py +113 -0
  398. package/scripts/check_agent_scope.py +117 -0
  399. package/scripts/check_agent_tool_mapping.py +213 -0
  400. package/scripts/check_review_agent_mcp_tools.py +317 -0
  401. package/scripts/check_security_assessment_mcp_tools.py +165 -0
  402. package/scripts/checkpoint_abort.py +502 -0
  403. package/scripts/claude_setup_review.py +438 -0
  404. package/scripts/codebase_recon.py +556 -0
  405. package/scripts/coverage_config.py +623 -0
  406. package/scripts/coverage_delta_steering.py +330 -0
  407. package/scripts/coverage_discovery_dotnet.py +315 -0
  408. package/scripts/coverage_discovery_java.py +742 -0
  409. package/scripts/coverage_discovery_js.py +546 -0
  410. package/scripts/coverage_gap_ranking.py +556 -0
  411. package/scripts/coverage_readiness.py +455 -0
  412. package/scripts/coverage_report_parse.py +521 -0
  413. package/scripts/detect_bdd_convention.py +252 -0
  414. package/scripts/eval_ablation.py +376 -0
  415. package/scripts/gherkin_analysis_coverage_gate.py +306 -0
  416. package/scripts/gherkin_cross_feature_duplicate_titles_gate.py +173 -0
  417. package/scripts/gherkin_effectiveness_rollup.py +238 -0
  418. package/scripts/gherkin_failure_path_gate.py +206 -0
  419. package/scripts/gherkin_feature_merge.py +720 -0
  420. package/scripts/gherkin_stub_gate.py +163 -0
  421. package/scripts/gherkin_stub_merge.py +479 -0
  422. package/scripts/git_origin_host.py +88 -0
  423. package/scripts/install-java-static-analysis.py +110 -0
  424. package/scripts/issue_deps.py +74 -0
  425. package/scripts/lib/_bdd_markers.py +28 -0
  426. package/scripts/lib/_gherkin_text.py +93 -0
  427. package/scripts/lib/_vendored_tree.py +70 -0
  428. package/scripts/lib/autoship_state.py +397 -0
  429. package/scripts/lib/claude_md_guard.py +226 -0
  430. package/scripts/lib/deterministic_recon.py +446 -0
  431. package/scripts/lib/mcp_tool_grants.py +211 -0
  432. package/scripts/lib/plan_parse.py +386 -0
  433. package/scripts/lib/review_result.py +84 -0
  434. package/scripts/lib/review_roster.py +86 -0
  435. package/scripts/lib/session_log/__init__.py +34 -0
  436. package/scripts/lib/session_log/__pycache__/__init__.cpython-314.pyc +0 -0
  437. package/scripts/lib/session_log/__pycache__/records.cpython-314.pyc +0 -0
  438. package/scripts/lib/session_log/classify.py +231 -0
  439. package/scripts/lib/session_log/corrections.py +194 -0
  440. package/scripts/lib/session_log/discovery.py +108 -0
  441. package/scripts/lib/session_log/records.py +218 -0
  442. package/scripts/lib/session_log/redact.py +76 -0
  443. package/scripts/lib/session_log/signals.py +373 -0
  444. package/scripts/lib/session_report_downstream.py +614 -0
  445. package/scripts/lib/session_report_maintainer.py +1273 -0
  446. package/scripts/lib/session_report_shared.py +262 -0
  447. package/scripts/lib/settings_hook_guard.py +157 -0
  448. package/scripts/lib/slug.py +33 -0
  449. package/scripts/lib/stub_extractors/__init__.py +82 -0
  450. package/scripts/lib/stub_extractors/_common.py +328 -0
  451. package/scripts/lib/stub_extractors/csharp.py +19 -0
  452. package/scripts/lib/stub_extractors/go.py +173 -0
  453. package/scripts/lib/stub_extractors/java.py +18 -0
  454. package/scripts/lib/stub_extractors/jsts.py +126 -0
  455. package/scripts/mutation_stack_sections.py +149 -0
  456. package/scripts/mutation_yield_steering.py +345 -0
  457. package/scripts/orchestrator.py +895 -0
  458. package/scripts/plan_gherkin_export.py +227 -0
  459. package/scripts/plan_waves.py +208 -0
  460. package/scripts/pr_close_keyword_lint.py +108 -0
  461. package/scripts/progress_guardian.py +888 -0
  462. package/scripts/recon_inventory.py +273 -0
  463. package/scripts/review_findings_log.py +93 -0
  464. package/scripts/run_invariants.py +124 -0
  465. package/scripts/select_lenses.py +640 -0
  466. package/scripts/session_report.py +486 -0
  467. package/scripts/set_autocompact_env.py +221 -0
  468. package/scripts/ship_resume_guard.py +135 -0
  469. package/scripts/ship_review_gate.py +63 -0
  470. package/scripts/specs_convention_marker.py +103 -0
  471. package/scripts/test_improve_resume.py +277 -0
  472. package/scripts/test_review_mechanics.py +958 -0
  473. package/scripts/token_efficiency_review.py +322 -0
  474. package/scripts/verdict_scope.py +285 -0
  475. package/scripts/verify_gherkin_quality_critic_isolation.py +296 -0
  476. package/scripts/verify_tier.py +157 -0
  477. package/skills/adr-tools/SKILL.md +118 -0
  478. package/skills/agent-readiness/SKILL.md +105 -0
  479. package/skills/agent-readiness/ai_friendly_analyzers.py +326 -0
  480. package/skills/agent-readiness/scanner.py +441 -0
  481. package/skills/agent-readiness/scorecard.yaml +88 -0
  482. package/skills/api-design/SKILL.md +115 -0
  483. package/skills/apply-fixes/SKILL.md +171 -0
  484. package/skills/apply-test-doubles/SKILL.md +321 -0
  485. package/skills/artifact-lifecycle/SKILL.md +127 -0
  486. package/skills/autoship/SKILL.md +1124 -0
  487. package/skills/benchmark/SKILL.md +105 -0
  488. package/skills/branch-workflow/SKILL.md +89 -0
  489. package/skills/browse/SKILL.md +184 -0
  490. package/skills/browser-testing/SKILL.md +62 -0
  491. package/skills/browser-testing/references/playwright-patterns.md +216 -0
  492. package/skills/build/SKILL.md +422 -0
  493. package/skills/build/references/static-self-heal.md +245 -0
  494. package/skills/careful/SKILL.md +72 -0
  495. package/skills/cd-test-architecture/SKILL.md +371 -0
  496. package/skills/ci-debugging/SKILL.md +105 -0
  497. package/skills/co-evolution-audit/SKILL.md +269 -0
  498. package/skills/code-review/SKILL.md +1015 -0
  499. package/skills/code-review/examples/aggregated-sample.json +56 -0
  500. package/skills/code-review/examples/sample-report.md +41 -0
  501. package/skills/code-review/output-format.md +478 -0
  502. package/skills/code-review/scripts/activation.py +86 -0
  503. package/skills/code-review/scripts/change_impact.py +357 -0
  504. package/skills/code-review/scripts/change_shape.py +372 -0
  505. package/skills/code-review/scripts/change_size.py +212 -0
  506. package/skills/code-review/scripts/changed_file_list.py +141 -0
  507. package/skills/code-review/scripts/closing_pass.py +187 -0
  508. package/skills/code-review/scripts/consolidate.py +277 -0
  509. package/skills/code-review/scripts/contract_failure_report.py +185 -0
  510. package/skills/code-review/scripts/dispatch_reconcile.py +66 -0
  511. package/skills/code-review/scripts/dispatch_waves.py +164 -0
  512. package/skills/code-review/scripts/finding_signature.py +446 -0
  513. package/skills/code-review/scripts/ledger.py +283 -0
  514. package/skills/code-review/scripts/partition.py +169 -0
  515. package/skills/code-review/scripts/render_tiered_findings.py +274 -0
  516. package/skills/code-review/scripts/repo_invariants.py +1066 -0
  517. package/skills/code-review/scripts/review_context_pack.py +306 -0
  518. package/skills/code-review/scripts/review_round_log.py +345 -0
  519. package/skills/code-review/scripts/review_value_coverage.py +297 -0
  520. package/skills/code-review/scripts/validate_review_output.py +467 -0
  521. package/skills/code-review/sliced-mode.md +205 -0
  522. package/skills/competitive-analysis/SKILL.md +191 -0
  523. package/skills/context-loading-protocol/SKILL.md +157 -0
  524. package/skills/continue/SKILL.md +90 -0
  525. package/skills/cost-report/SKILL.md +178 -0
  526. package/skills/coverage-baseline/SKILL.md +335 -0
  527. package/skills/coverage-baseline/references/multi-project-discovery.md +202 -0
  528. package/skills/coverage-delta/SKILL.md +181 -0
  529. package/skills/coverage-delta/references/mutation-gate.md +70 -0
  530. package/skills/design-doc/SKILL.md +95 -0
  531. package/skills/design-interrogation/SKILL.md +89 -0
  532. package/skills/design-it-twice/SKILL.md +91 -0
  533. package/skills/docker-image-audit/SKILL.md +108 -0
  534. package/skills/docker-image-audit/references/install-guide.md +64 -0
  535. package/skills/docker-image-audit/references/report-template.md +73 -0
  536. package/skills/docker-image-create/SKILL.md +185 -0
  537. package/skills/domain-analysis/SKILL.md +183 -0
  538. package/skills/domain-driven-design/SKILL.md +194 -0
  539. package/skills/exploratory-testing/SKILL.md +108 -0
  540. package/skills/explore/SKILL.md +51 -0
  541. package/skills/farley-score/SKILL.md +165 -0
  542. package/skills/feature-file-validation/SKILL.md +78 -0
  543. package/skills/feature-file-validation/references/validation-rules.md +115 -0
  544. package/skills/feedback-learning/SKILL.md +414 -0
  545. package/skills/fix/SKILL.md +450 -0
  546. package/skills/freeze/SKILL.md +68 -0
  547. package/skills/frontend-architecture/SKILL.md +113 -0
  548. package/skills/gherkin-derive/SKILL.md +630 -0
  549. package/skills/gherkin-public/SKILL.md +266 -0
  550. package/skills/governance-compliance/SKILL.md +150 -0
  551. package/skills/guard/SKILL.md +75 -0
  552. package/skills/handoff/SKILL.md +139 -0
  553. package/skills/handoff/references/summary-templates.md +242 -0
  554. package/skills/harness-audit/SKILL.md +751 -0
  555. package/skills/harness-audit/scripts/lesson_validate.py +386 -0
  556. package/skills/harness-audit/scripts/redundancy_criterion.py +188 -0
  557. package/skills/headless-run/SKILL.md +45 -0
  558. package/skills/headless-run/scripts/isolated_dispatch.py +381 -0
  559. package/skills/help/SKILL.md +72 -0
  560. package/skills/hexagonal-architecture/SKILL.md +85 -0
  561. package/skills/human-oversight-protocol/SKILL.md +224 -0
  562. package/skills/issues-from-assessment/SKILL.md +223 -0
  563. package/skills/issues-from-plan/SKILL.md +133 -0
  564. package/skills/legacy-code/SKILL.md +132 -0
  565. package/skills/mermaid-diagramming/SKILL.md +120 -0
  566. package/skills/mutation-night-watch/SKILL.md +154 -0
  567. package/skills/mutation-night-watch/references/scheduling.md +135 -0
  568. package/skills/mutation-testing/SKILL.md +396 -0
  569. package/skills/mutation-testing/references/languages/csharp-stryker-net.md +676 -0
  570. package/skills/mutation-testing/references/languages/go-go-mutesting.md +95 -0
  571. package/skills/mutation-testing/references/languages/java-pitest.md +77 -0
  572. package/skills/mutation-testing/references/languages/javascript-stryker.md +188 -0
  573. package/skills/mutation-testing/references/languages/python-mutmut.md +97 -0
  574. package/skills/mutation-testing/references/time-estimation.md +34 -0
  575. package/skills/mutation-testing/references/tool-detection.md +15 -0
  576. package/skills/mutation-testing/references/workflow-callers.md +23 -0
  577. package/skills/mutation-testing/scripts/__pycache__/xunit_v3_feature_detector.cpython-314.pyc +0 -0
  578. package/skills/mutation-testing/scripts/csharp_stryker_net_slice_runner.py +635 -0
  579. package/skills/mutation-testing/scripts/csharp_stryker_net_status_loop.py +525 -0
  580. package/skills/mutation-testing/scripts/csharp_stryker_net_wrapper.py +681 -0
  581. package/skills/mutation-testing/scripts/mutation_baseline_reuse.py +292 -0
  582. package/skills/mutation-testing/scripts/mutation_exclude_policy.py +268 -0
  583. package/skills/mutation-testing/scripts/mutation_feasibility_gate.py +463 -0
  584. package/skills/mutation-testing/scripts/mutation_kill_headless.py +331 -0
  585. package/skills/mutation-testing/scripts/mutation_kill_insert.py +199 -0
  586. package/skills/mutation-testing/scripts/mutation_kill_insert_python.py +150 -0
  587. package/skills/mutation-testing/scripts/mutation_kill_loop.py +869 -0
  588. package/skills/mutation-testing/scripts/mutation_kill_loop_python.py +949 -0
  589. package/skills/mutation-testing/scripts/mutation_kill_retry.py +592 -0
  590. package/skills/mutation-testing/scripts/mutation_kill_shared.py +620 -0
  591. package/skills/mutation-testing/scripts/mutation_nightwatch.py +462 -0
  592. package/skills/mutation-testing/scripts/mutation_nightwatch_stacks.py +425 -0
  593. package/skills/mutation-testing/scripts/mutation_report.py +743 -0
  594. package/skills/mutation-testing/scripts/mutation_report_cli.py +175 -0
  595. package/skills/mutation-testing/scripts/mutation_safety_gate.py +69 -0
  596. package/skills/mutation-testing/scripts/stryker_shard_pipeline.py +847 -0
  597. package/skills/mutation-testing/scripts/stryker_shard_setup.py +440 -0
  598. package/skills/mutation-testing/scripts/stryker_timeout_retry.py +142 -0
  599. package/skills/mutation-testing/scripts/xunit_v3_feature_detector.py +341 -0
  600. package/skills/performance-benchmark/SKILL.md +174 -0
  601. package/skills/performance-benchmark/examples/report-format.md +43 -0
  602. package/skills/performance-benchmark/references/benchmark-script.md +169 -0
  603. package/skills/performance-metrics/SKILL.md +265 -0
  604. package/skills/plan/SKILL.md +199 -0
  605. package/skills/plan/references/gherkin-persistence.md +43 -0
  606. package/skills/plan/references/plan-template.md +182 -0
  607. package/skills/pr/SKILL.md +289 -0
  608. package/skills/pr/scripts/gate_retry_state.py +368 -0
  609. package/skills/project-init/README.md +141 -0
  610. package/skills/project-init/SKILL.md +1197 -0
  611. package/skills/project-init/evals/evals.json +200 -0
  612. package/skills/project-init/references/capability-tools.md +55 -0
  613. package/skills/project-init/references/configs.md +221 -0
  614. package/skills/property-based-testing/SKILL.md +121 -0
  615. package/skills/property-based-testing/fixtures/invariant_fixture.py +15 -0
  616. package/skills/property-based-testing/fixtures/js-roundtrip/README.md +42 -0
  617. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/LICENSE +21 -0
  618. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/README.md +263 -0
  619. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/fast-check.d.ts +5165 -0
  620. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/fast-check.js +12147 -0
  621. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/package.json +3 -0
  622. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/types57/fast-check.d.ts +5165 -0
  623. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/fast-check.d.ts +5165 -0
  624. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/fast-check.js +12011 -0
  625. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/rolldown-runtime-D7D4PA-g.js +13 -0
  626. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/types57/fast-check.d.ts +5165 -0
  627. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/package.json +94 -0
  628. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/LICENSE +21 -0
  629. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/README.md +168 -0
  630. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/RandomGenerator-DcXj09Ch.d.ts +14 -0
  631. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformBigInt.d.ts +15 -0
  632. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformBigInt.js +38 -0
  633. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat32.d.ts +15 -0
  634. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat32.js +18 -0
  635. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat64.d.ts +15 -0
  636. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat64.js +22 -0
  637. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformInt.d.ts +15 -0
  638. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformInt.js +134 -0
  639. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/RandomGenerator-DcXj09Ch.d.ts +14 -0
  640. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformBigInt.d.ts +15 -0
  641. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformBigInt.js +37 -0
  642. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat32.d.ts +15 -0
  643. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat32.js +17 -0
  644. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat64.d.ts +15 -0
  645. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat64.js +21 -0
  646. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformInt.d.ts +15 -0
  647. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformInt.js +133 -0
  648. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/congruential32.d.ts +7 -0
  649. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/congruential32.js +44 -0
  650. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/mersenne.d.ts +7 -0
  651. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/mersenne.js +90 -0
  652. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xoroshiro128plus.d.ts +7 -0
  653. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xoroshiro128plus.js +80 -0
  654. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xorshift128plus.d.ts +7 -0
  655. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xorshift128plus.js +78 -0
  656. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/package.json +3 -0
  657. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/JumpableRandomGenerator.d.ts +16 -0
  658. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/JumpableRandomGenerator.js +0 -0
  659. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/RandomGenerator.d.ts +2 -0
  660. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/RandomGenerator.js +0 -0
  661. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/generateN.d.ts +6 -0
  662. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/generateN.js +8 -0
  663. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/purify.d.ts +12 -0
  664. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/purify.js +9 -0
  665. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/skipN.d.ts +6 -0
  666. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/skipN.js +6 -0
  667. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/congruential32.d.ts +7 -0
  668. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/congruential32.js +46 -0
  669. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/mersenne.d.ts +7 -0
  670. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/mersenne.js +92 -0
  671. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xoroshiro128plus.d.ts +7 -0
  672. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xoroshiro128plus.js +82 -0
  673. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xorshift128plus.d.ts +7 -0
  674. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xorshift128plus.js +80 -0
  675. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/JumpableRandomGenerator.d.ts +16 -0
  676. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/JumpableRandomGenerator.js +0 -0
  677. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/RandomGenerator.d.ts +2 -0
  678. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/RandomGenerator.js +0 -0
  679. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/generateN.d.ts +6 -0
  680. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/generateN.js +9 -0
  681. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/purify.d.ts +12 -0
  682. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/purify.js +10 -0
  683. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/skipN.d.ts +6 -0
  684. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/skipN.js +7 -0
  685. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/package.json +133 -0
  686. package/skills/property-based-testing/fixtures/js-roundtrip/package-lock.json +1179 -0
  687. package/skills/property-based-testing/fixtures/js-roundtrip/package.json +14 -0
  688. package/skills/property-based-testing/fixtures/js-roundtrip/roundtrip.js +29 -0
  689. package/skills/property-based-testing/fixtures/js-roundtrip/roundtrip.properties.test.js +16 -0
  690. package/skills/property-based-testing/fixtures/no_property_fixture.py +10 -0
  691. package/skills/property-based-testing/fixtures/roundtrip_fixture.py +16 -0
  692. package/skills/property-based-testing/references/languages/javascript.md +54 -0
  693. package/skills/property-based-testing/scripts/detect_and_dispatch.py +80 -0
  694. package/skills/property-based-testing/scripts/hypothesis_scaffold.py +276 -0
  695. package/skills/proxy-resilience/SKILL.md +84 -0
  696. package/skills/quality-gate-pipeline/SKILL.md +184 -0
  697. package/skills/quality-targets-converge/SKILL.md +254 -0
  698. package/skills/repo-review/SKILL.md +159 -0
  699. package/skills/report-pdf/SKILL.md +66 -0
  700. package/skills/review/SKILL.md +47 -0
  701. package/skills/review-agent/SKILL.md +152 -0
  702. package/skills/review-summary/SKILL.md +73 -0
  703. package/skills/run-report/SKILL.md +70 -0
  704. package/skills/semantic-duplication-scan/SKILL.md +337 -0
  705. package/skills/semantic-scan/SKILL.md +53 -0
  706. package/skills/semgrep-analyze/SKILL.md +139 -0
  707. package/skills/setup/SKILL.md +1122 -0
  708. package/skills/ship/SKILL.md +240 -0
  709. package/skills/source-verification/SKILL.md +210 -0
  710. package/skills/source-verification/scripts/claim_extractor.py +155 -0
  711. package/skills/specs/.size-baseline.json +4 -0
  712. package/skills/specs/SKILL.md +243 -0
  713. package/skills/specs/references/completeness-checklist.md +83 -0
  714. package/skills/specs/references/extraction.md +58 -0
  715. package/skills/specs/references/glossary.md +59 -0
  716. package/skills/specs/references/persistence.md +115 -0
  717. package/skills/specs/references/predictability-check.md +77 -0
  718. package/skills/static-analysis-integration/SKILL.md +235 -0
  719. package/skills/static-analysis-integration/adapters/_envelope.py +26 -0
  720. package/skills/static-analysis-integration/adapters/jscpd-adapter.py +66 -0
  721. package/skills/static-analysis-integration/adapters/lizard-adapter.py +81 -0
  722. package/skills/static-analysis-integration/adapters/mypy-adapter.py +50 -0
  723. package/skills/static-analysis-integration/adapters/mypy-src-layout.py +93 -0
  724. package/skills/static-analysis-integration/adapters/security-review-adapter.py +212 -0
  725. package/skills/static-analysis-integration/maintenance.md +23 -0
  726. package/skills/static-analysis-integration/references/language-setup.md +228 -0
  727. package/skills/static-analysis-integration/references/sarif-parser.md +124 -0
  728. package/skills/static-analysis-integration/references/security-review-adapter.md +118 -0
  729. package/skills/static-analysis-integration/references/tool-configs.md +617 -0
  730. package/skills/static-analysis-integration/rulesets/pmd-quickstart.xml +24 -0
  731. package/skills/stryker-xunit-v2-shim/SKILL.md +274 -0
  732. package/skills/stryker-xunit-v2-shim/references/shim-howto.md +256 -0
  733. package/skills/stryker-xunit-v2-shim/scripts/generate_shim.py +143 -0
  734. package/skills/systematic-debugging/SKILL.md +130 -0
  735. package/skills/telemetry/SKILL.md +75 -0
  736. package/skills/test-audit-disable/SKILL.md +129 -0
  737. package/skills/test-design/SKILL.md +177 -0
  738. package/skills/test-design/scripts/__pycache__/internal_double_detector.cpython-314.pyc +0 -0
  739. package/skills/test-design/scripts/internal_double_detector.py +631 -0
  740. package/skills/test-design-advisor/SKILL.md +166 -0
  741. package/skills/test-driven-development/SKILL.md +169 -0
  742. package/skills/test-health/SKILL.md +262 -0
  743. package/skills/test-improve/SKILL.md +239 -0
  744. package/skills/test-improve/references/phase-0-approach-contract.md +228 -0
  745. package/skills/test-improve/references/phase-1-analyze.md +131 -0
  746. package/skills/test-improve/references/phase-2-baseline.md +121 -0
  747. package/skills/test-improve/references/phase-3-derive-gherkin.md +53 -0
  748. package/skills/test-improve/references/phase-4-plan-fixes.md +34 -0
  749. package/skills/test-improve/references/phase-5-improve.md +215 -0
  750. package/skills/test-improve/references/phase-6-refactor-decision.md +45 -0
  751. package/skills/test-improve/references/phase-7-refactor.md +44 -0
  752. package/skills/test-improve/references/phase-8-validate.md +66 -0
  753. package/skills/test-improve/references/phase-9-close-out-prompt.md +11 -0
  754. package/skills/test-improve/references/phase-9-report.md +62 -0
  755. package/skills/test-improve/references/review-loop.md +92 -0
  756. package/skills/test-improve/templates/executive-summary.md +123 -0
  757. package/skills/threat-modeling/SKILL.md +108 -0
  758. package/skills/triage/SKILL.md +211 -0
  759. package/skills/ubiquitous-language/SKILL.md +192 -0
  760. package/skills/ubiquitous-language/scripts/collect_domain_signals.py +300 -0
  761. package/skills/unfreeze/SKILL.md +37 -0
  762. package/skills/upgrade/SKILL.md +31 -0
  763. package/skills/upgrade/scripts/check_version_drift.py +113 -0
  764. package/skills/upgrade/scripts/enable_autoupdate.py +149 -0
  765. package/skills/version/SKILL.md +25 -0
  766. package/sync/__pycache__/sync_upstream.cpython-314.pyc +0 -0
  767. package/sync/sync_upstream.py +293 -0
  768. package/templates/ACCEPTED-RISKS.md.tmpl +46 -0
  769. package/templates/agents/agent-template.md +151 -0
  770. package/templates/agents/angular-testing.md +66 -0
  771. package/templates/agents/csharp-quality.md +63 -0
  772. package/templates/agents/esm-enforcer.md +52 -0
  773. package/templates/agents/front-end-testing.md +65 -0
  774. package/templates/agents/go-quality.md +65 -0
  775. package/templates/agents/python-quality.md +62 -0
  776. package/templates/agents/react-testing.md +61 -0
  777. package/templates/agents/ts-enforcer.md +60 -0
  778. package/templates/agents/twelve-factor-audit.md +49 -0
  779. package/tools/entropy-check.py +250 -0
  780. package/tools/model-hash-verify.py +213 -0
@@ -0,0 +1,101 @@
1
+ """hooks/lib/review_dispatch_ledger.py — shared review-dispatch-ledger reading (#1998).
2
+
3
+ `review_value_coverage.py` and `contract_failure_report.py` both need the
4
+ same denominator: how many times each review agent was actually dispatched.
5
+ Both hand-rolled an identical `read_jsonl()` + `dispatch_counts()` pair over
6
+ `boundary-events.jsonl`'s `hook == "agent_dispatch_ledger"` / `decision ==
7
+ "record"` rows (see `agent_dispatch_ledger.py`) — the predicate "this row IS
8
+ a review dispatch" had three homes (the emitter plus two independent
9
+ readers) before this module. Per this repo's CLAUDE.md ratchet rule ("a
10
+ mechanical finding reported twice becomes a check"), two independent review
11
+ agents (arch-review, structure-review; #1998 wave 1) plus a third
12
+ (domain-review; #1998 wave 2) flagged the same duplication — this module is
13
+ the single extraction point, so a hook never reaches into `scripts/` (the
14
+ correct dependency direction is `scripts/` -> `hooks/lib/`, never the
15
+ reverse, per `review_agent_registry.py`'s own docstring) and neither reader
16
+ re-derives the ledger's wire shape by hand again.
17
+
18
+ Stdlib only. See ADR 0014 / ADR 0015.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import json
24
+ import sys
25
+ from collections import Counter
26
+ from pathlib import Path
27
+
28
+ _LIB_DIR = Path(__file__).resolve().parent
29
+ if str(_LIB_DIR) not in sys.path:
30
+ sys.path.insert(0, str(_LIB_DIR))
31
+
32
+ import artifact_paths
33
+ import boundary_events
34
+
35
+ #: The stream every review dispatch is deterministically recorded to. An
36
+ #: alias of `boundary_events.LOG_NAME` (the module that actually writes the
37
+ #: ledger and owns its filename), not a fresh literal — kept as this
38
+ #: module's own public name for its existing callers (backstop review
39
+ #: finding, #2166 + #2171: this filename previously had three independent
40
+ #: homes; `repo_invariants.check_ledger_filename_single_sourced` asserts
41
+ #: this stays an identity, not just an equal value).
42
+ LEDGER_STREAM = boundary_events.LOG_NAME
43
+
44
+ #: The ledger rows that denote a review dispatch.
45
+ _LEDGER_HOOK = "agent_dispatch_ledger"
46
+ _LEDGER_DECISION = "record"
47
+
48
+
49
+ def resolve_stream(category: str, stream: str, cwd: Path, *, migrate: bool = False) -> Path:
50
+ """Resolve a `.claude/<category>/<stream>` metrics path.
51
+
52
+ `migrate=False` by default: every current caller of this helper is a
53
+ read-only report/query, so a mere read must never migrate a legacy file
54
+ or create `.claude/<category>/` as a side effect (mirrors
55
+ `hooks/lib/metrics_query.py::_stream_path`'s same reasoning). Pass
56
+ `migrate=True` explicitly for a writer.
57
+ """
58
+ return artifact_paths.resolve_file(category, stream, cwd, migrate=migrate)
59
+
60
+
61
+ def read_jsonl(path: Path) -> tuple[list[dict], int]:
62
+ """Return (rows, malformed_count). Malformed lines are skipped but
63
+ counted — silently dropping unreadable telemetry is the same class of
64
+ defect #1998 exists to surface, so the count is reported, not swallowed.
65
+ """
66
+ rows: list[dict] = []
67
+ malformed = 0
68
+ try:
69
+ text = path.read_text(encoding="utf-8")
70
+ except (OSError, UnicodeDecodeError):
71
+ return rows, malformed
72
+ for line in text.splitlines():
73
+ if not line.strip():
74
+ continue
75
+ try:
76
+ parsed = json.loads(line)
77
+ except ValueError:
78
+ malformed += 1
79
+ continue
80
+ if isinstance(parsed, dict):
81
+ rows.append(parsed)
82
+ else:
83
+ malformed += 1
84
+ return rows, malformed
85
+
86
+
87
+ def dispatch_counts(ledger_rows) -> Counter:
88
+ """Per-agent dispatch counts from the deterministic ledger."""
89
+ counts: Counter = Counter()
90
+ for row in ledger_rows:
91
+ if row.get("hook") != _LEDGER_HOOK:
92
+ continue
93
+ if row.get("decision") != _LEDGER_DECISION:
94
+ continue
95
+ agent = row.get("matched_rule")
96
+ if isinstance(agent, str) and agent.strip():
97
+ counts[agent.strip()] += 1
98
+ return counts
99
+
100
+
101
+ __all__ = ("LEDGER_STREAM", "dispatch_counts", "read_jsonl", "resolve_stream")
@@ -0,0 +1,521 @@
1
+ """hooks/lib/review_gate_corroboration.py — fail-CLOSED dispatch-ledger
2
+ corroboration reader for the review-corroboration gate (#1461).
3
+
4
+ Read by `hooks/pre_pr_review.py`'s `.pr-review-passed` gate (#1886) — the
5
+ gate's hash-match check alone proves the branch-diff content hasn't changed
6
+ since that file was written; it does NOT prove an independent review
7
+ actually produced that write (see `hooks/lib/review_gate_hash.py`'s own
8
+ docstring for the full account of that residual gap). This module reads
9
+ `hooks/agent_dispatch_ledger.py`'s `"record"` events from
10
+ `.claude/metrics/boundary-events.jsonl` to corroborate that a hash-matching
11
+ write was backed by genuine, recent, distinct review-agent dispatches.
12
+ (`hooks/pre_commit_review.py`'s own `.review-passed` gate was this module's
13
+ original consumer at #1461; that hook is now a documented no-op — see its
14
+ own module docstring — following #1886's PR-time gate migration. This
15
+ module's own `evaluate()`/`has_doc_only_exemption()`/
16
+ `has_single_agent_exemption()` transferred to the new gate as-is; the
17
+ cosmetic-delta carry-forward machinery specific to the old commit-time gate
18
+ — `evaluate_cosmetic_carry_forward()`, `distinct_normalized_dispatches()`,
19
+ `distinct_review_agent_dispatches()`, `CosmeticCarryForwardEvidence` — was
20
+ deleted in #1904 once confirmed to have zero remaining production callers.)
21
+
22
+ Kept as a separate sibling module rather than folded into
23
+ `review_gate_hash.py` (design feedback, #1461): `review_gate_hash.py` is
24
+ deliberately minimal — a single pure hash function with no registry or
25
+ metrics-stream knowledge. This module's registry-cross-referencing,
26
+ metrics-reading responsibility is a different concern and belongs on its own;
27
+ each module's docstring names the other so the split stays intentional, not
28
+ accidental.
29
+
30
+ Built on `hooks/lib/metrics_query.py`'s existing generic JSONL
31
+ reader/filter (`load_stream` + `filter_entries`) rather than a bespoke
32
+ second parser — this repo already has one malformed-line-tolerant reader for
33
+ exactly this metrics-directory shape.
34
+
35
+ FAIL-CLOSED (the deliberate opposite of `hooks/lib/boundary_events.py`'s own
36
+ fail-open write side): any inability to prove genuine dispatch happened —
37
+ a missing ledger file, an unreadable one, or genuinely no qualifying
38
+ entries — is treated the same way a security gate must treat "can't prove
39
+ it" — as "didn't happen". `boundary_events.py` fails open on the *write*
40
+ side because a broken telemetry write must never block a real tool call;
41
+ this module fails closed on the *read* side because a broken/absent
42
+ corroboration read must never let an uncorroborated `.review-passed` write
43
+ pass the gate. Do not "fix" this asymmetry to match the write side — it is
44
+ intentional; see `boundary_events.py`'s own module docstring for its side of
45
+ the contrast.
46
+
47
+ A missing `boundary-events.jsonl` is bucketed as a **read failure**, not as
48
+ "genuinely no entries": that stream is written by many always-on guard
49
+ hooks (destructive_guard, verify_guard, pre_pr_review, telemetry,
50
+ agent_dispatch_ledger, ...), so in any real session that reaches a `gh pr
51
+ create` attempt the file will almost always already exist — its total absence is
52
+ itself a signal that hook registration is broken, which is an infra
53
+ problem the caller should surface distinctly from "the ledger is fine, it
54
+ just has no qualifying dispatches". Malformed *individual* JSON lines are
55
+ NOT a read failure here — matching `metrics_query.load_stream`'s own
56
+ documented precedent, a single corrupt line is skipped, never fatal, and
57
+ every other consumer of that stream relies on the same tolerance. "Unreadable"
58
+ covers a ledger file that exists but can't be read as text at all (permission
59
+ error, undecodable bytes, or the path is not a regular file).
60
+
61
+ Stdlib only. See ADR 0014 / ADR 0015.
62
+ """
63
+
64
+ from __future__ import annotations
65
+
66
+ import sys
67
+ from datetime import datetime, timedelta, timezone
68
+ from pathlib import Path
69
+ from typing import NamedTuple
70
+
71
+ _LIB_DIR = Path(__file__).resolve().parent
72
+ if str(_LIB_DIR) not in sys.path:
73
+ sys.path.insert(0, str(_LIB_DIR))
74
+
75
+ import artifact_paths
76
+ import metrics_query
77
+ import review_agent_registry
78
+ from boundary_events import LOG_NAME as _LEDGER_STREAM_NAME
79
+ from boundary_events import TS_FORMAT as _TS_FORMAT
80
+
81
+ _EVENT_TYPE = "agent_dispatch_ledger"
82
+ _DECISION = "record"
83
+
84
+ # Dispatch-failure negative evidence (#1763): emitted by
85
+ # `hooks/lib/boundary_events.py`'s `--event dispatch-failure` CLI (a
86
+ # different hook/tool/decision tuple than the "record" events above — see
87
+ # that module's `_CLI_AGENT_EVENTS`) when a dispatched review agent still
88
+ # fails to return a contract-valid result after its single retry.
89
+ _DISPATCH_FAILURE_HOOK = "code-review"
90
+ _DISPATCH_FAILURE_DECISION = "dispatch-failure"
91
+
92
+ # `dispatch_failure_agents` (#1904 item 2) is modeled as `frozenset | None` —
93
+ # `None` means "cannot prove no dispatch failure exists" (a ledger or
94
+ # registry read failure); a `frozenset()` means "provably no dispatch
95
+ # failures"; a non-empty frozenset names the failing agents. Prior to this,
96
+ # the unprovable case was smuggled into the frozenset value space as a fake
97
+ # sentinel MEMBER (`_UNPROVABLE_DISPATCH_FAILURE`, a string no real agent
98
+ # name could equal) — a control state encoded inside the value type, guarded
99
+ # only by an `==`/`any(...)` check and caller convention rather than the type
100
+ # system. Modeling it as `None` instead mirrors `_registered_agents()`'s own
101
+ # `frozenset | None` pattern (#1461/#1866) and makes "cannot prove this" and
102
+ # "no registered review agents" the same *shape* of unprovable-ness, checked
103
+ # with `is None` rather than an equality comparison against a magic value.
104
+
105
+ # The doc-only / single-agent short-circuit exemption events (#1461): emitted
106
+ # directly by `skills/code-review/SKILL.md`'s write sites via
107
+ # `boundary_events.py`'s purpose-locked CLI (`--event doc-only` /
108
+ # `--event single-agent`), not by a PreToolUse hook — see that module's
109
+ # `_main()` docstring and its `_CLI_EVENTS` mapping.
110
+ _DOC_ONLY_HOOK = "code-review"
111
+ _DOC_ONLY_DECISION = "bypass"
112
+ _DOC_ONLY_RULE = "doc-only-review-exempt"
113
+ _SINGLE_AGENT_RULE = "single-agent-review-exempt"
114
+
115
+
116
+ class LedgerEvidence(NamedTuple):
117
+ """Full corroboration-read result — everything a caller needs to pick
118
+ the correct one of the pinned rejection messages (Step 1.3, #1461).
119
+
120
+ Attributes:
121
+ agents_in_window: distinct registered review-agent names
122
+ (`matched_rule` values) dispatched inside the recency window,
123
+ for THIS subject_hash. Empty on any read failure or when
124
+ nothing qualifies.
125
+ any_dispatch_ever: True if at least one genuine `"record"` event
126
+ exists anywhere in the ledger, for ANY subject_hash, regardless
127
+ of the recency window. False on any read failure.
128
+ same_subject_dispatch_ever: True if at least one genuine `"record"`
129
+ event exists anywhere in the ledger for THIS SAME subject_hash,
130
+ regardless of the recency window (#1461 second security
131
+ re-review) — distinguishes genuinely STALE evidence (a review
132
+ of this exact content happened, just too long ago) from
133
+ evidence that only exists for DIFFERENT staged content
134
+ (`any_dispatch_ever` true but this one false): the caller picks
135
+ the "outside the window" message only when this is true, and a
136
+ "reviewed different content" message when it's false but
137
+ `any_dispatch_ever` is true — otherwise "outside the window"
138
+ would misreport a same-window dispatch for unrelated content as
139
+ if it were this content, just late. False on any read failure.
140
+ read_failure_reason: `None` when the ledger was read successfully
141
+ (whether or not it has qualifying entries); `"missing"` or
142
+ `"unreadable"` when it could not be read at all — see module
143
+ docstring for what each means.
144
+ dispatch_failure_agents: registered review-agent names (live-
145
+ registry re-validated, same as `agents_in_window`) whose MOST
146
+ RECENT qualifying event for THIS `subject_hash` — comparing
147
+ "record" events against "dispatch-failure" events (#1763) by
148
+ each event's own `ts` — is a dispatch-failure rather than a
149
+ later "record"; a later "record" for that same agent+hash
150
+ supersedes and removes it from this set, regardless of either
151
+ event's age. Deliberately UNBOUNDED by `window_seconds`, unlike
152
+ `agents_in_window`: a genuine, never-fixed dispatch-failure
153
+ coverage gap for this exact staged content must not silently
154
+ expire just because time passed — only a genuine superseding
155
+ dispatch clears it, never the clock. Empty `frozenset()` on a
156
+ successful read with no qualifying dispatch-failure events.
157
+ `None` on a ledger OR registry READ FAILURE (#1904 item 2) —
158
+ "cannot prove no dispatch failure exists" — never collapsed to
159
+ an empty/all-clear set.
160
+
161
+ KNOWN RESIDUAL GAP (#1763 security review, same class as
162
+ `agent_dispatch_ledger.py`'s own disclosed gap): the superseding
163
+ "record" is a PreToolUse dispatch-START signal, not proof the
164
+ new dispatch itself returned a valid result — `record` events
165
+ fire before any result exists, the same property that made the
166
+ original dispatch-failure mechanism necessary in the first
167
+ place. A gate check that lands in the narrow window between a
168
+ re-dispatch's own "record" and its eventual outcome (success:
169
+ nothing new emitted; failure: a fresh dispatch-failure event)
170
+ could therefore see a stale failure as already-superseded. Not
171
+ fixed here: doing so would need a completion signal this
172
+ harness has no way to emit today, and the plan's own adversarial
173
+ review (three rounds) deliberately chose "superseded by ANY
174
+ later record, regardless of age" as this field's semantics —
175
+ narrowing it now would reopen a settled design decision, not
176
+ fix an implementation bug. Disclosed rather than silently
177
+ assumed away, matching this codebase's own convention for a
178
+ residual gap that raises the bar without claiming to close it.
179
+ """
180
+
181
+ agents_in_window: frozenset
182
+ any_dispatch_ever: bool
183
+ same_subject_dispatch_ever: bool
184
+ read_failure_reason: str | None
185
+ dispatch_failure_agents: frozenset | None
186
+
187
+
188
+ def mtime_to_iso(mtime: float) -> str:
189
+ """Convert a `Path.stat().st_mtime` epoch float to this stream's
190
+ `%Y-%m-%dT%H:%M:%SZ` UTC timestamp format.
191
+
192
+ Shared here (rather than duplicated in `pre_commit_review.py`) so the
193
+ gate hook and this module never drift on timestamp formatting — the
194
+ hook anchors `before_ts` on `.claude/memory/.review-passed`'s own mtime
195
+ and must format it identically to how every emitter in this repo
196
+ stamps `ts` (confirmed against `boundary_events.py`).
197
+ """
198
+ return datetime.fromtimestamp(mtime, tz=timezone.utc).strftime(_TS_FORMAT)
199
+
200
+
201
+ def _parse_ts(ts: str) -> datetime:
202
+ return datetime.strptime(ts, _TS_FORMAT).replace(tzinfo=timezone.utc)
203
+
204
+
205
+ def _since_bound(before_ts: str, window_seconds: int) -> str:
206
+ return (_parse_ts(before_ts) - timedelta(seconds=window_seconds)).strftime(_TS_FORMAT)
207
+
208
+
209
+ def _ledger_path(cwd) -> Path:
210
+ base = Path(cwd) if cwd else Path.cwd()
211
+ # Read-only: migrate=False so a corroboration read never migrates a
212
+ # legacy file or creates .claude/metrics/ as a side effect.
213
+ return artifact_paths.resolve_file("metrics", _LEDGER_STREAM_NAME, base, migrate=False)
214
+
215
+
216
+ def _registered_agents() -> frozenset | None:
217
+ """Re-validate against the live registry at READ time too (#1461 security
218
+ review), not just at write time in `agent_dispatch_ledger.py` — defense
219
+ in depth against a stale ledger (written by an older plugin version, or
220
+ copied from another checkout) supplying names no longer registered.
221
+
222
+ Delegates to `review_agent_registry.read_registered_review_agent_names()`
223
+ (#1904 item 1), which owns the read-failure-vs-empty distinction this
224
+ function used to implement locally — see that function's own docstring
225
+ for the full "why `None` vs `frozenset()`" account. `None` on any read
226
+ error, never an empty frozenset (#1763 correctness/security review):
227
+ "registry read failed" and "registry read fine, genuinely zero agents
228
+ registered" require OPPOSITE treatment depending on which side of the
229
+ evidence they narrow (see `_agents_with_unsuperseded_failure`, which
230
+ checks for `None` explicitly rather than treating it as "no agents
231
+ registered").
232
+ """
233
+ return review_agent_registry.read_registered_review_agent_names(
234
+ review_agent_registry.default_agents_dir()
235
+ )
236
+
237
+
238
+ def _read_ledger(cwd) -> tuple:
239
+ """Return `(entries, failure_reason)`.
240
+
241
+ `failure_reason` is `None` on a successful read (file exists and is
242
+ decodable — even if it yields zero entries); `"missing"` when the
243
+ ledger file does not exist; `"unreadable"` when it exists but raised on
244
+ read. See module docstring for the missing-vs-unreadable rationale and
245
+ why malformed individual lines are not a failure here.
246
+ """
247
+ path = _ledger_path(cwd)
248
+ if not path.is_file():
249
+ return [], "missing"
250
+ try:
251
+ entries = list(metrics_query.load_stream(path))
252
+ except (OSError, UnicodeDecodeError):
253
+ return [], "unreadable"
254
+ return entries, None
255
+
256
+
257
+ def _extract_timeline_entries(entries: list, decision: str, ts_sentinel: str) -> list:
258
+ """Build `(ts, agent, decision)` tuples for one entry kind — shared by
259
+ both loops in `_agents_with_unsuperseded_failure` (#1799), which
260
+ duplicated this exact loop body twice, differing only in the ts-less
261
+ sentinel default and the `decision` constant.
262
+
263
+ `ts_sentinel` is the value substituted when an entry has no usable
264
+ `ts` (resolved via `metrics_query`'s own `_TS_FIELDS` fallback, never a
265
+ bare `entry.get("ts")`, and never a raw non-str value). Records and
266
+ failures pass opposite sentinels on purpose — see
267
+ `_agents_with_unsuperseded_failure`'s own docstring for the rationale;
268
+ this helper is deliberately unopinionated about which sentinel is
269
+ "correct" and just applies whatever the caller passes.
270
+ """
271
+ result = []
272
+ for entry in entries:
273
+ agent = entry.get("matched_rule")
274
+ if not isinstance(agent, str):
275
+ continue
276
+ ts = metrics_query._first_present(entry, metrics_query._TS_FIELDS)
277
+ ts = ts if isinstance(ts, str) else ts_sentinel
278
+ result.append((ts, agent, decision))
279
+ return result
280
+
281
+
282
+ def _agents_with_unsuperseded_failure(
283
+ records: list, failures: list, registered: frozenset | None
284
+ ) -> frozenset | None:
285
+ """Per agent, compare the most recent qualifying event — a "record" from
286
+ `records` or a "dispatch-failure" from `failures`, both already narrowed
287
+ to the SAME `subject_hash` by the caller — by each event's own `ts`,
288
+ unbounded by any recency window (#1763; see `LedgerEvidence.
289
+ dispatch_failure_agents` for the rationale). Returns the agents whose
290
+ most-recent event is a dispatch-failure; a later "record" for that same
291
+ agent removes it, regardless of either event's age. On an exact `ts` tie
292
+ the dispatch-failure wins (fail CLOSED), since `records` is folded into
293
+ the timeline before `failures` and Python's sort is stable.
294
+
295
+ `registered` being `None` (a registry READ FAILURE, per
296
+ `_registered_agents()` — never "genuinely zero agents registered", which
297
+ is a real `frozenset()`) fails CLOSED by returning `None` immediately
298
+ (#1904 item 2: modeled as `frozenset | None` rather than a fake sentinel
299
+ MEMBER of the frozenset value space), without inspecting `records`/
300
+ `failures` at all (#1763 security/correctness review). Filtering
301
+ negative evidence through an empty set here — the same collapse that
302
+ safely narrows `agents_in_window` — would instead WIDEN the gate: every
303
+ genuine dispatch-failure would be excluded by "not in an empty set",
304
+ producing an all-clear indistinguishable from "provably no failures".
305
+
306
+ An entry with no usable `ts` (checked via `metrics_query`'s own
307
+ `_TS_FIELDS` fallback, the same resolution `filter_entries` already
308
+ applies elsewhere in this module — not a bare `entry.get("ts")`, which
309
+ would silently miss a `timestamp`-keyed entry, and never a raw non-str
310
+ value, which would otherwise crash the sort below on a mixed-type
311
+ comparison) is likewise never dropped, and the two entry KINDS are
312
+ defaulted in OPPOSITE directions on purpose: a ts-less **failure**
313
+ sorts as `"￿"` (after every real ISO timestamp), so it can never
314
+ be superseded by anything — the safe default for negative evidence we
315
+ cannot chronologically place. A ts-less **record** sorts as `""`
316
+ (before every real timestamp), so it can never supersede a real
317
+ failure — the safe default for positive evidence we cannot place. Do
318
+ NOT default both kinds to the same sentinel (an earlier draft used
319
+ `ts or ""` for both, which let ANY ts-bearing record silently supersede
320
+ a ts-less failure — the opposite of "ordered last, never superseded"
321
+ this docstring promises; #1763 correctness review).
322
+
323
+ Live-registry re-validated (`registered`) exactly like `agents_in_window`
324
+ — an unregistered/fabricated agent name is excluded, so a forged event
325
+ can only ever narrow evidence, never widen it.
326
+ """
327
+ if registered is None:
328
+ return None
329
+
330
+ # A ts-less (or non-str-ts) RECORD defaults to the minimum sort key
331
+ # ("") — it can never supersede a real failure, the safe default for
332
+ # positive evidence we cannot chronologically place. A ts-less FAILURE
333
+ # defaults to the maximum sort key ("￿" sorts after every real
334
+ # ISO-8601 timestamp string) — it can never be superseded, the safe
335
+ # default for negative evidence we cannot chronologically place.
336
+ # Deliberately the OPPOSITE default from the record case.
337
+ timeline = _extract_timeline_entries(records, _DECISION, "")
338
+ timeline += _extract_timeline_entries(failures, _DISPATCH_FAILURE_DECISION, "￿")
339
+ timeline.sort(key=lambda item: item[0])
340
+
341
+ latest_decision: dict = {}
342
+ for _ts, agent, decision in timeline:
343
+ latest_decision[agent] = decision
344
+
345
+ return frozenset(
346
+ agent
347
+ for agent, decision in latest_decision.items()
348
+ if decision == _DISPATCH_FAILURE_DECISION and agent in registered
349
+ )
350
+
351
+
352
+ def _binding_evidence(
353
+ dispatches: list,
354
+ failures: list,
355
+ since: str,
356
+ before_ts: str,
357
+ registered: frozenset | None,
358
+ ) -> tuple:
359
+ """Compute `(agents_in_window, dispatch_failure_agents)` from dispatch/
360
+ failure entries ALREADY narrowed to one hash binding by the caller.
361
+
362
+ Shared by `evaluate()` and `evaluate_cosmetic_carry_forward()` (once per
363
+ hash binding it evaluates) — each independently re-implemented this exact
364
+ window-filter + positive-frozenset + `_agents_with_unsuperseded_failure`
365
+ sequence before this extraction (#1836 perf finding), which risked the
366
+ fail-closed positive/negative asymmetry — `registered_for_positive`'s
367
+ `None`-to-empty collapse is safe ONLY for positive evidence, never for
368
+ negative — silently drifting out of sync across independently
369
+ maintained copies.
370
+ """
371
+ in_window = metrics_query.filter_entries(dispatches, since=since, until=before_ts)
372
+ registered_for_positive = registered if registered is not None else frozenset()
373
+ agents = frozenset(
374
+ e["matched_rule"]
375
+ for e in in_window
376
+ if isinstance(e.get("matched_rule"), str) and e["matched_rule"] in registered_for_positive
377
+ )
378
+ dispatch_failure_agents = _agents_with_unsuperseded_failure(dispatches, failures, registered)
379
+ return agents, dispatch_failure_agents
380
+
381
+
382
+ def _load_ledger_pipeline(cwd, before_ts: str, window_seconds: int) -> tuple:
383
+ """Shared read-ledger -> since-bound -> registered-agents -> filtered-
384
+ dispatches/failures pipeline (#1799) — `evaluate()` and
385
+ `evaluate_cosmetic_carry_forward()` each independently re-implemented
386
+ this exact sequence before this extraction.
387
+
388
+ Returns `(failure, since, registered, all_dispatches, all_failures)`.
389
+ `failure` is `None` on a successful ledger read; when it is non-`None`
390
+ (`"missing"`/`"unreadable"` — see `_read_ledger`'s own docstring), every
391
+ other element is `None` and the caller must build its own fail-closed
392
+ result immediately, matching each function's own `LedgerEvidence`/
393
+ `CosmeticCarryForwardEvidence` shape — this helper does not build either
394
+ result type itself, since the two callers' failure shapes differ.
395
+ """
396
+ entries, failure = _read_ledger(cwd)
397
+ if failure is not None:
398
+ return failure, None, None, None, None
399
+ since = _since_bound(before_ts, window_seconds)
400
+ registered = _registered_agents()
401
+ all_dispatches = list(
402
+ metrics_query.filter_entries(entries, event_type=_EVENT_TYPE, gate_outcome=_DECISION)
403
+ )
404
+ all_failures = list(
405
+ metrics_query.filter_entries(
406
+ entries, event_type=_DISPATCH_FAILURE_HOOK, gate_outcome=_DISPATCH_FAILURE_DECISION
407
+ )
408
+ )
409
+ return None, since, registered, all_dispatches, all_failures
410
+
411
+
412
+ def evaluate(cwd, before_ts: str, window_seconds: int, subject_hash: str) -> LedgerEvidence:
413
+ """Single-read-pass corroboration evaluation — the primary entry point.
414
+
415
+ `before_ts` anchors the recency window (typically the gate file's own
416
+ mtime, converted via `mtime_to_iso`); qualifying dispatches must fall in
417
+ `(before_ts - window_seconds, before_ts]`, inclusive of both bounds via
418
+ `metrics_query.filter_entries`'s `since`/`until` semantics.
419
+
420
+ `subject_hash` (#1461 security review) is `.review-passed`'s own
421
+ `review_gate_hash()` value — required, not optional. Dispatch events are
422
+ stamped with the `review_gate_hash()` value in effect at dispatch time
423
+ (`agent_dispatch_ledger.py`); only events whose `subject_hash` matches
424
+ THIS gate's current hash count as evidence. Without this, a genuine
425
+ review of one changeset (file A) would satisfy the gate for an unrelated
426
+ later changeset (file B) staged and self-hashed within the same recency
427
+ window — this binds "a review happened recently" to "a review of THIS
428
+ staged content happened recently". An event missing `subject_hash`
429
+ entirely (e.g. written before this field existed) never matches.
430
+
431
+ Also re-validates each dispatch's `matched_rule` against the LIVE
432
+ registered-agent set (`_registered_agents()`), not just trusting
433
+ whatever the ledger says — defense in depth against a stale or
434
+ hand-edited ledger.
435
+ """
436
+ failure, since, registered, all_dispatches, all_failures = _load_ledger_pipeline(
437
+ cwd, before_ts, window_seconds
438
+ )
439
+ if failure is not None:
440
+ return LedgerEvidence(frozenset(), False, False, failure, None)
441
+
442
+ # `any_ever` intentionally reads the UNFILTERED dispatch set (#1461
443
+ # security review) — it means "a genuine dispatch exists somewhere in
444
+ # the ledger, for ANY subject", which is what `_STALE_MESSAGE` vs
445
+ # `_NO_DISPATCH_MESSAGE` needs to distinguish. Computing it after the
446
+ # subject_hash narrowing below would silently redefine it to "a
447
+ # dispatch for THIS exact hash exists somewhere" — collapsing the
448
+ # common, legitimate case (a real review of slightly different staged
449
+ # content) into the same "no dispatch ever" message a genuinely
450
+ # unreviewed changeset gets.
451
+ any_ever = any(isinstance(e.get("matched_rule"), str) for e in all_dispatches)
452
+ dispatches = [e for e in all_dispatches if e.get("subject_hash") == subject_hash]
453
+ # Same-subject existence, independent of the recency window (#1461
454
+ # second security re-review) — see the LedgerEvidence docstring for why
455
+ # this must be tracked separately from `any_ever`.
456
+ same_subject_ever = any(isinstance(e.get("matched_rule"), str) for e in dispatches)
457
+
458
+ # Dispatch-failure negative evidence (#1763) — unbounded by the recency
459
+ # window, per the field's own docstring. `dispatches` above is already
460
+ # narrowed to THIS subject_hash and carries every qualifying "record"
461
+ # regardless of age, so it doubles as the "records" side of the
462
+ # supersession comparison with no extra filtering needed.
463
+ same_subject_failures = [e for e in all_failures if e.get("subject_hash") == subject_hash]
464
+ agents, dispatch_failure_agents = _binding_evidence(
465
+ dispatches, same_subject_failures, since, before_ts, registered
466
+ )
467
+
468
+ return LedgerEvidence(agents, any_ever, same_subject_ever, None, dispatch_failure_agents)
469
+
470
+
471
+ def _has_exemption(cwd, before_ts: str, window_seconds: int, subject_hash: str, rule: str) -> bool:
472
+ entries, failure = _read_ledger(cwd)
473
+ if failure is not None:
474
+ return False
475
+ since = _since_bound(before_ts, window_seconds)
476
+ matched = metrics_query.filter_entries(
477
+ entries,
478
+ event_type=_DOC_ONLY_HOOK,
479
+ gate_outcome=_DOC_ONLY_DECISION,
480
+ since=since,
481
+ until=before_ts,
482
+ )
483
+ return any(
484
+ e.get("matched_rule") == rule and e.get("subject_hash") == subject_hash for e in matched
485
+ )
486
+
487
+
488
+ def has_doc_only_exemption(cwd, before_ts: str, window_seconds: int, subject_hash: str) -> bool:
489
+ """True if the doc-only short-circuit's `"doc-only-review-exempt"`
490
+ bypass event was recorded inside the recency window before `before_ts`,
491
+ bound to `subject_hash` — the doc-only path's auditable alternative to
492
+ dispatch-ledger evidence (#1461). Fails CLOSED like every other read in
493
+ this module: any read failure returns False, same as "no exemption
494
+ found". The `subject_hash` requirement means an exemption emitted for
495
+ one changeset cannot be replayed to pass the gate for a different one.
496
+ """
497
+ return _has_exemption(cwd, before_ts, window_seconds, subject_hash, _DOC_ONLY_RULE)
498
+
499
+
500
+ def has_single_agent_exemption(cwd, before_ts: str, window_seconds: int, subject_hash: str) -> bool:
501
+ """True if `--agent <name>`'s `"single-agent-review-exempt"` bypass
502
+ event was recorded inside the recency window before `before_ts`, bound
503
+ to `subject_hash` (#1461) — a sanctioned single-agent `/code-review`
504
+ run only ever dispatches 1 distinct agent. Historically this could never
505
+ clear the (then-2) distinct-dispatch floor on its own, so this exemption
506
+ existed to keep that documented workflow from regressing to an
507
+ always-blocked gate; #2147 lowered the floor to 1, so a single dispatch
508
+ now clears it unaided and this exemption is no longer load-bearing for
509
+ that case — kept as an explicit, auditable alternate path rather than
510
+ removed. Fails CLOSED like every other read in this module.
511
+ """
512
+ return _has_exemption(cwd, before_ts, window_seconds, subject_hash, _SINGLE_AGENT_RULE)
513
+
514
+
515
+ __all__ = (
516
+ "LedgerEvidence",
517
+ "evaluate",
518
+ "has_doc_only_exemption",
519
+ "has_single_agent_exemption",
520
+ "mtime_to_iso",
521
+ )