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,306 @@
1
+ #!/usr/bin/env python3
2
+ """One shared context pack for a review panel (#2006). OPT-IN, off by default.
3
+
4
+ **This is not the default dispatch path.** `code-review/SKILL.md` step 4 uses
5
+ the per-agent context payload unless the caller sets
6
+ `DEV_TEAM_REVIEW_CONTEXT_PACK=on`. ADR 0034 declined a shared-context pre-pass
7
+ after measuring duplicate full-file reads at 0.38%-4.86% of a round's total
8
+ input spend (median 0.8%); a later re-measurement with the same tool put it at
9
+ 0.22%. The 4.31x multiplier quoted for this problem is a read-volume ratio, a
10
+ different denominator from the one that decision turns on. #2024 tracks
11
+ measuring panels of >= 8 agents, the shape that could change the answer.
12
+
13
+ The pack ships complete file bodies, not the structural skeleton ADR 0034
14
+ warned would starve line-level lenses, so it carries no known quality risk —
15
+ it simply has not been shown to pay for its complexity.
16
+
17
+ Every lens in a `/code-review` panel is handed the same changed files and then
18
+ reads them itself. Measured across 148 panels of >= 8 agents: **180 MB of Read
19
+ volume covering 41.8 MB of unique content — a 4.31x re-read multiplier**, with
20
+ one file opened by 38 agents in the worst case. Those panels are 73% of all
21
+ review spend.
22
+
23
+ The multiplier is not only cross-agent duplication. A lens that opens a file,
24
+ greps around it, and opens it again pays for it each time, and the panel pays
25
+ that per lens. What removes it is giving every lens the same prepared bytes
26
+ once, so reading is a single addressed fetch instead of an exploration.
27
+
28
+ ## Why one pack serves nearly the whole panel
29
+
30
+ Of the 18 review lenses that declare a `Context needs` value, **17 need the
31
+ full bodies of the changed files** (13 `full-file`, 4 `project-structure`);
32
+ one needs the diff alone. So the union of what the panel needs is: the changed
33
+ file list, the diff, and the full bodies — which is exactly this pack. Each
34
+ lens reads the section its declaration calls for.
35
+
36
+ ## What this deliberately does NOT do
37
+
38
+ It does not stop a lens from reading anything else. A lens tracing a caller
39
+ into an unchanged file still should, and still can. The pack removes the
40
+ *repeated* read of the *same* changed files, which is the measured cost; it is
41
+ not a sandbox.
42
+
43
+ ## Truncation is always visible
44
+
45
+ A pack over its byte cap omits **whole files**, names every one of them in the
46
+ pack body and in the manifest, and tells the reader to open those directly.
47
+ Silently truncating would hand a lens a file that looks complete and is not —
48
+ a finding-shaped hole that reads as "reviewed". Per this repo's rule, a bound
49
+ that drops coverage says so out loud.
50
+
51
+ Stdlib-only. See docs/python-hook-contract.md.
52
+ """
53
+
54
+ from __future__ import annotations
55
+
56
+ import argparse
57
+ import hashlib
58
+ import json
59
+ import subprocess
60
+ import sys
61
+ from pathlib import Path
62
+
63
+ _PLUGIN_ROOT = Path(__file__).resolve().parents[3]
64
+ _HOOKS_LIB_DIR = _PLUGIN_ROOT / "hooks" / "lib"
65
+ if str(_HOOKS_LIB_DIR) not in sys.path:
66
+ sys.path.insert(0, str(_HOOKS_LIB_DIR))
67
+
68
+ try:
69
+ import artifact_paths # type: ignore[import-not-found]
70
+ except ImportError: # pragma: no cover - degraded fallback, hooks/lib unreachable
71
+ # Same guarded-import shape as the sibling scripts in this directory, which
72
+ # is not in ruff.toml's E402 per-file-ignore list.
73
+ artifact_paths = None
74
+
75
+ #: Default ceiling on the pack body. A pack is read by every lens in the panel,
76
+ #: so bytes here are multiplied by the roster size — the cap is what keeps a
77
+ #: large diff from costing more shared than it saved duplicated.
78
+ DEFAULT_MAX_BYTES = 400_000
79
+
80
+ #: Files above this size are omitted individually rather than crowding out the
81
+ #: rest of the pack. A single generated or vendored file can exceed the whole
82
+ #: budget on its own.
83
+ DEFAULT_MAX_FILE_BYTES = 60_000
84
+
85
+ _CATEGORY = "review-context"
86
+
87
+
88
+ def _git(args, cwd: Path) -> str:
89
+ try:
90
+ result = subprocess.run(
91
+ ["git", "-c", "core.quotePath=false", *args],
92
+ cwd=str(cwd), capture_output=True, text=True, timeout=60, check=False,
93
+ )
94
+ except (OSError, subprocess.SubprocessError):
95
+ return ""
96
+ return result.stdout if result.returncode == 0 else ""
97
+
98
+
99
+ def read_file_text(path: Path) -> tuple[str | None, str]:
100
+ """Return (text, reason). `text` is None when the body cannot be included."""
101
+ try:
102
+ if not path.exists():
103
+ return None, "not present in the working tree (deleted or renamed)"
104
+ if path.is_dir():
105
+ return None, "directory"
106
+ raw = path.read_bytes()
107
+ except OSError as exc:
108
+ return None, f"unreadable ({exc.__class__.__name__})"
109
+ if b"\x00" in raw[:8192]:
110
+ return None, "binary"
111
+ try:
112
+ return raw.decode("utf-8"), ""
113
+ except UnicodeDecodeError:
114
+ return None, "not valid UTF-8"
115
+
116
+
117
+ def number_lines(text: str) -> str:
118
+ """Line-numbered body, matching how the Read tool presents a file so a lens
119
+ can cite `file:line` from the pack without re-opening the file to count."""
120
+ lines = text.splitlines()
121
+ width = len(str(len(lines))) if lines else 1
122
+ return "\n".join(f"{str(i).rjust(width)}\t{line}" for i, line in enumerate(lines, 1))
123
+
124
+
125
+ def select_bodies(files, cwd: Path, max_bytes: int, max_file_bytes: int):
126
+ """Include file bodies in the given order until the budget is spent.
127
+
128
+ Returns (included, omitted) where each entry is a dict. Selection walks the
129
+ caller's order and skips anything that does not fit, rather than stopping
130
+ at the first oversized file — one huge file must not hide every smaller one
131
+ behind it.
132
+ """
133
+ included, omitted = [], []
134
+ used = 0
135
+ for rel in files:
136
+ text, reason = read_file_text(cwd / rel)
137
+ if text is None:
138
+ omitted.append({"file": rel, "reason": reason})
139
+ continue
140
+ body = number_lines(text)
141
+ size = len(body.encode("utf-8"))
142
+ if size > max_file_bytes:
143
+ omitted.append({"file": rel, "reason": f"exceeds per-file cap ({size} bytes)"})
144
+ continue
145
+ if used + size > max_bytes:
146
+ omitted.append({"file": rel, "reason": "pack byte budget exhausted"})
147
+ continue
148
+ included.append({"file": rel, "body": body, "bytes": size})
149
+ used += size
150
+ return included, omitted
151
+
152
+
153
+ def render_pack(*, changed, diff_text, included, omitted, base_ref) -> str:
154
+ parts = [
155
+ "# Review context pack",
156
+ "",
157
+ (
158
+ "Prepared once for this panel. Read the section your `Context needs` "
159
+ "declaration calls for instead of opening these files individually — "
160
+ "the bodies below are complete and line-numbered, so `file:line` "
161
+ "citations from this pack are accurate."
162
+ ),
163
+ "",
164
+ (
165
+ "You may still open anything NOT listed here (a caller in an unchanged "
166
+ "file, a sibling module). This pack removes the repeated read of the "
167
+ "changed set; it does not limit what you may consult."
168
+ ),
169
+ "",
170
+ "## Changed files",
171
+ "",
172
+ ]
173
+ if changed:
174
+ # A status is optional: the caller may know the paths without knowing
175
+ # how each changed. Claiming "full-repository scope" in that case (the
176
+ # original behavior) tells a lens the diff is empty when it is not.
177
+ parts += [
178
+ f"- `{status}` {path}" if status else f"- {path}"
179
+ for path, status in changed
180
+ ]
181
+ else:
182
+ parts.append("_(no change list — full-repository scope)_")
183
+ parts += ["", "## Diff", ""]
184
+ parts += [f"_(vs `{base_ref}`)_", "", "```diff", diff_text.rstrip("\n") or "(empty)", "```"] \
185
+ if diff_text.strip() else ["_(no diff — full-repository scope)_"]
186
+
187
+ parts += ["", "## File bodies", ""]
188
+ if not included:
189
+ parts.append("_(none included — see omissions below)_")
190
+ for entry in included:
191
+ parts += [f"### {entry['file']}", "", "```", entry["body"], "```", ""]
192
+
193
+ if omitted:
194
+ parts += [
195
+ "## NOT included in this pack",
196
+ "",
197
+ (
198
+ "These files are part of the change but their bodies are not "
199
+ "above. **Open them directly** — do not treat their absence as "
200
+ "'nothing to review here'."
201
+ ),
202
+ "",
203
+ ]
204
+ parts += [f"- {o['file']} — {o['reason']}" for o in omitted]
205
+ parts.append("")
206
+ return "\n".join(parts) + "\n"
207
+
208
+
209
+ def _pack_dir(cwd: Path) -> Path:
210
+ if artifact_paths is not None:
211
+ return artifact_paths.category_dir(_CATEGORY, cwd)
212
+ return cwd / ".claude" / _CATEGORY
213
+
214
+
215
+ def build(
216
+ *, files, cwd: Path, base_ref: str, max_bytes: int, max_file_bytes: int,
217
+ diff_text: str | None = None, changed=None,
218
+ ) -> dict:
219
+ ordered = sorted(dict.fromkeys(files))
220
+ if changed is None:
221
+ changed = [(path, "") for path in ordered]
222
+ if diff_text is None:
223
+ diff_text = _git(["-c", "diff.relative=false", "diff", base_ref, "--", *ordered], cwd) \
224
+ if ordered else ""
225
+ included, omitted = select_bodies(ordered, cwd, max_bytes, max_file_bytes)
226
+ text = render_pack(
227
+ changed=changed or [], diff_text=diff_text, included=included,
228
+ omitted=omitted, base_ref=base_ref,
229
+ )
230
+ digest = hashlib.sha256(text.encode("utf-8")).hexdigest()[:16]
231
+ out_dir = _pack_dir(cwd)
232
+ out_dir.mkdir(parents=True, exist_ok=True)
233
+ out_path = out_dir / f"pack-{digest}.md"
234
+ out_path.write_text(text, encoding="utf-8")
235
+
236
+ unique_bytes = sum(e["bytes"] for e in included)
237
+ return {
238
+ "path": str(out_path),
239
+ "pack_bytes": len(text.encode("utf-8")),
240
+ "unique_body_bytes": unique_bytes,
241
+ "files_requested": len(ordered),
242
+ "files_included": [e["file"] for e in included],
243
+ "files_omitted": omitted,
244
+ "complete": not omitted,
245
+ "base_ref": base_ref,
246
+ }
247
+
248
+
249
+ def parse_name_status(lines) -> list[tuple[str, str]]:
250
+ """Parse `git diff --name-status` rows into (path, status) pairs.
251
+
252
+ Rename and copy rows carry two paths (`R100\told\tnew`); the NEW path is
253
+ the one that exists on disk and the one findings are cited against, so it
254
+ is the one kept.
255
+ """
256
+ out: list[tuple[str, str]] = []
257
+ for line in lines:
258
+ parts = line.split("\t")
259
+ if len(parts) < 2 or not parts[0].strip():
260
+ continue
261
+ status = parts[0].strip()[0].upper()
262
+ path = parts[-1].strip() if status in {"R", "C"} else parts[1].strip()
263
+ if path:
264
+ out.append((path, status))
265
+ return out
266
+
267
+
268
+ def _read_file_list(source: str | None) -> list[str]:
269
+ if not source:
270
+ return []
271
+ text = sys.stdin.read() if source == "-" else Path(source).read_text(encoding="utf-8")
272
+ return [line.strip() for line in text.splitlines() if line.strip()]
273
+
274
+
275
+ def main(argv=None) -> int:
276
+ parser = argparse.ArgumentParser(
277
+ description="Build one shared context pack for a review panel (#2006)."
278
+ )
279
+ parser.add_argument("--files-from", default="-",
280
+ help="file with one changed path per line, or '-' for stdin")
281
+ parser.add_argument("--name-status-from", default=None,
282
+ help="file of `git diff --name-status` lines (or '-'), "
283
+ "so the pack can label each path A/M/D/R/C")
284
+ parser.add_argument("--base", default="HEAD", dest="base_ref")
285
+ parser.add_argument("--cwd", default=None)
286
+ parser.add_argument("--max-bytes", type=int, default=DEFAULT_MAX_BYTES)
287
+ parser.add_argument("--max-file-bytes", type=int, default=DEFAULT_MAX_FILE_BYTES)
288
+ args = parser.parse_args(argv)
289
+
290
+ cwd = Path(args.cwd) if args.cwd else Path.cwd()
291
+ changed = parse_name_status(_read_file_list(args.name_status_from)) \
292
+ if args.name_status_from else None
293
+ files = [p for p, _ in changed] if changed else _read_file_list(args.files_from)
294
+ if not files:
295
+ print(json.dumps({"error": "no files given", "path": None}))
296
+ return 1
297
+ manifest = build(
298
+ files=files, cwd=cwd, base_ref=args.base_ref, changed=changed,
299
+ max_bytes=args.max_bytes, max_file_bytes=args.max_file_bytes,
300
+ )
301
+ print(json.dumps(manifest, indent=2, sort_keys=True))
302
+ return 0
303
+
304
+
305
+ if __name__ == "__main__":
306
+ sys.exit(main())
@@ -0,0 +1,345 @@
1
+ #!/usr/bin/env python3
2
+ """Round-level review-value instrumentation for `/code-review` (#1624).
3
+
4
+ `metrics/review-value.jsonl` today is written only by `/build`'s inline
5
+ checkpoints (#348) and records nothing about `/code-review`'s OWN fix-loop
6
+ rounds. That gap is why #1623's central question — is `correctness-review`'s
7
+ 24-dispatch frequency delivering proportional value, or is it churn? — is
8
+ unanswerable, and why no churn-reduction mechanism can prove it worked.
9
+
10
+ This module writes one row per `/code-review` round to the same stream, with
11
+ `source: "code-review"` (the value `/harness-audit` Step 4 already knows to
12
+ exclude from fix-rate drop-candidate logic — see `knowledge/telemetry-schema.md`).
13
+
14
+ ## The one judgment-free signal: fix provenance
15
+
16
+ `fix_provenance_new` counts how many of a round's NEW findings land inside
17
+ the line ranges the PREVIOUS round's fix actually touched. That is the
18
+ "the fix introduced it" signal, and it is computed by interval math over a
19
+ unified diff — no LLM judgment, no heuristics about finding text. A round
20
+ whose new error/warning findings ALL carry fix provenance is churn by
21
+ construction: every problem it found was created by the round before it.
22
+
23
+ Intervals are taken from the diff's **new side** (the `+` file's line
24
+ numbers), because that is the coordinate system findings are reported in:
25
+ an agent re-reading the post-fix file reports `file:line` against the
26
+ content that now exists on disk.
27
+
28
+ ## Location & gating (issue #1624 design item 2)
29
+
30
+ Writes to `.claude/metrics/` **unconditionally**, matching
31
+ `boundary-events.jsonl` rather than `/build`'s consent-gated
32
+ `~/.claude/telemetry.json` path. Rationale, as recorded on the issue: this
33
+ is the same class of local, counts-only operational stream the commit gate
34
+ itself already depends on, and gating it behind consent would make the
35
+ epic's success criteria depend on consent being enabled on dev machines.
36
+ Rows carry counts, agent names, and enum values only — never code, file
37
+ content, or message text.
38
+
39
+ Stdlib-only. See docs/python-hook-contract.md.
40
+ """
41
+
42
+ from __future__ import annotations
43
+
44
+ import argparse
45
+ import json
46
+ import re
47
+ import sys
48
+ from datetime import datetime, timezone
49
+ from pathlib import Path
50
+
51
+ # skills/code-review/scripts -> skills/code-review -> skills -> plugin root
52
+ _PLUGIN_ROOT = Path(__file__).resolve().parents[3]
53
+ _HOOKS_LIB_DIR = _PLUGIN_ROOT / "hooks" / "lib"
54
+ if str(_HOOKS_LIB_DIR) not in sys.path:
55
+ sys.path.insert(0, str(_HOOKS_LIB_DIR))
56
+
57
+ try:
58
+ import artifact_paths # type: ignore[import-not-found]
59
+ except ImportError: # pragma: no cover - degraded fallback, hooks/lib unreachable
60
+ # Guarded-import form matching `change_shape.py`'s sibling pattern: this
61
+ # directory is not in `ruff.toml`'s E402 per-file-ignore list, and the
62
+ # import genuinely cannot precede the `sys.path` setup above. The fallback
63
+ # resolves the same default location `artifact_paths.resolve_file` would,
64
+ # minus the legacy-path migration — enough for an append-only metrics
65
+ # writer that is already fail-open.
66
+ artifact_paths = None
67
+
68
+ _STREAM_NAME = "review-value.jsonl"
69
+ _SOURCE = "code-review"
70
+
71
+ #: `dispatch_purpose` values. `discovery` = a panel looking for new problems
72
+ #: (round 1, and any full re-panel); `verification` = a re-dispatch confirming
73
+ #: a specific fix (#1628); `closing` = the scoped gate-closing pass (#1626).
74
+ DISPATCH_PURPOSES = ("discovery", "verification", "closing")
75
+
76
+ #: `outcome` values — the same closed enum `/build`'s rows already use, so the
77
+ #: two `source` values stay aggregatable in one query.
78
+ OUTCOMES = ("fixed", "no-op", "escalated")
79
+
80
+ #: `@@ -old,oldcount +new,newcount @@` — the counts are optional (git omits
81
+ #: `,1`), and anything may follow the closing `@@` (the hunk-header context).
82
+ _HUNK_RE = re.compile(r"^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@")
83
+
84
+
85
+ def _now_iso() -> str:
86
+ return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
87
+
88
+
89
+ def changed_line_intervals(diff_text: str) -> dict:
90
+ """Parse a unified diff into `{path: [(start, end), ...]}` — inclusive
91
+ NEW-side line ranges that the diff added or modified.
92
+
93
+ Only `+` lines (and their positions) count as changed. A hunk that is
94
+ pure deletion contributes no interval: there is no post-fix line for a
95
+ finding to be reported against, so a deletion can never be the *site* of
96
+ a new finding. Context lines advance the new-side counter without
97
+ producing an interval.
98
+
99
+ Paths come from the `+++ b/<path>` header with the `b/` prefix stripped;
100
+ `/dev/null` (a pure delete) is skipped. Consecutive added lines collapse
101
+ into one interval so the returned list stays small on large diffs.
102
+
103
+ Malformed input degrades to fewer intervals, never to an exception — a
104
+ caller that can't parse the diff simply gets no provenance credit, which
105
+ is the conservative direction (it under-reports churn rather than
106
+ inventing it).
107
+ """
108
+ intervals: dict = {}
109
+ path: str | None = None
110
+ new_line = 0
111
+ run_start: int | None = None
112
+ run_end: int | None = None
113
+
114
+ def flush() -> None:
115
+ nonlocal run_start, run_end
116
+ if path is not None and run_start is not None and run_end is not None:
117
+ intervals.setdefault(path, []).append((run_start, run_end))
118
+ run_start = None
119
+ run_end = None
120
+
121
+ for raw in diff_text.splitlines():
122
+ if raw.startswith("+++ "):
123
+ flush()
124
+ target = raw[4:].strip()
125
+ # Strip git's `b/` prefix; tolerate `--src-prefix`-less diffs.
126
+ if target == "/dev/null":
127
+ path = None
128
+ else:
129
+ path = target.removeprefix("b/")
130
+ new_line = 0
131
+ continue
132
+ if raw.startswith(("--- ", "diff --git ")):
133
+ flush()
134
+ continue
135
+ match = _HUNK_RE.match(raw)
136
+ if match:
137
+ flush()
138
+ new_line = int(match.group(1))
139
+ continue
140
+ if path is None:
141
+ continue
142
+ if raw.startswith("+"):
143
+ if run_start is None:
144
+ run_start = new_line
145
+ run_end = new_line
146
+ new_line += 1
147
+ elif raw.startswith("-"):
148
+ # Deletion: consumes an old-side line only. Does not advance the
149
+ # new-side counter and never opens an interval.
150
+ continue
151
+ elif raw.startswith("\\"):
152
+ # "" — belongs to whichever side
153
+ # preceded it and moves no counter.
154
+ continue
155
+ else:
156
+ # Context line (leading space) or a stray blank line git emits
157
+ # for an empty context line.
158
+ flush()
159
+ new_line += 1
160
+
161
+ flush()
162
+ return intervals
163
+
164
+
165
+ def _normalize_path(value: str) -> str:
166
+ """Compare paths by their POSIX form without a leading `./`, so a finding
167
+ reported as `./src/a.js` matches a diff header's `src/a.js`."""
168
+ text = str(value).replace("\\", "/")
169
+ while text.startswith("./"):
170
+ text = text[2:]
171
+ return text
172
+
173
+
174
+ def finding_has_fix_provenance(finding: dict, intervals: dict) -> bool:
175
+ """True when this finding's `file:line` falls inside a line range the
176
+ previous round's fix touched — i.e. the fix is where this finding lives.
177
+
178
+ A finding with no usable `line` (missing, non-integer, or <= 0) is NOT
179
+ credited: "somewhere in a file the fix touched" is too weak a claim to
180
+ call churn on. Same conservative direction as `changed_line_intervals`.
181
+ """
182
+ path = finding.get("file")
183
+ if not isinstance(path, str) or not path:
184
+ return False
185
+ line = finding.get("line")
186
+ if isinstance(line, bool) or not isinstance(line, int) or line <= 0:
187
+ return False
188
+ key = _normalize_path(path)
189
+ for candidate, ranges in intervals.items():
190
+ if _normalize_path(candidate) != key:
191
+ continue
192
+ if any(start <= line <= end for start, end in ranges):
193
+ return True
194
+ return False
195
+
196
+
197
+ def count_fix_provenance(findings, intervals: dict) -> int:
198
+ """How many of `findings` land inside the previous round's fix delta."""
199
+ return sum(1 for f in findings if isinstance(f, dict) and finding_has_fix_provenance(f, intervals))
200
+
201
+
202
+ def severity_breakdown(findings) -> dict:
203
+ """`{errors, warnings, suggestions}` counts over a finding list — the
204
+ same three-bucket shape `/build`'s rows already carry, so both `source`
205
+ values aggregate in one query. Unrecognized severities are dropped
206
+ rather than bucketed, keeping the three keys' sum meaningful."""
207
+ counts = {"errors": 0, "warnings": 0, "suggestions": 0}
208
+ bucket = {"error": "errors", "warning": "warnings", "suggestion": "suggestions"}
209
+ for finding in findings:
210
+ if not isinstance(finding, dict):
211
+ continue
212
+ key = bucket.get(str(finding.get("severity", "")).lower())
213
+ if key:
214
+ counts[key] += 1
215
+ return counts
216
+
217
+
218
+ def build_round_entry(
219
+ *,
220
+ round_number: int,
221
+ agents_run,
222
+ findings_new,
223
+ findings_carried: int,
224
+ dispatch_purpose: str,
225
+ outcome: str,
226
+ fix_diff: str = "",
227
+ timestamp: str | None = None,
228
+ ) -> dict:
229
+ """Assemble one `review-value.jsonl` row for a `/code-review` round.
230
+
231
+ `findings_new` is this round's NEW findings (carried-over signatures are
232
+ counted separately via `findings_carried` — see #1625's round ledger,
233
+ which owns signature identity). `fix_diff` is the unified diff of the
234
+ PREVIOUS round's fix; empty for round 1, which by definition has no
235
+ preceding fix and therefore always reports `fix_provenance_new: 0`.
236
+ """
237
+ if dispatch_purpose not in DISPATCH_PURPOSES:
238
+ raise ValueError(f"dispatch_purpose must be one of {DISPATCH_PURPOSES}")
239
+ if outcome not in OUTCOMES:
240
+ raise ValueError(f"outcome must be one of {OUTCOMES}")
241
+
242
+ findings = [f for f in findings_new if isinstance(f, dict)]
243
+ intervals = changed_line_intervals(fix_diff) if fix_diff else {}
244
+ return {
245
+ "timestamp": timestamp or _now_iso(),
246
+ "source": _SOURCE,
247
+ "round": int(round_number),
248
+ "agents_run": sorted({str(a) for a in agents_run}),
249
+ "findings_new": len(findings),
250
+ "findings_carried": int(findings_carried),
251
+ "severity_breakdown": severity_breakdown(findings),
252
+ "fix_provenance_new": count_fix_provenance(findings, intervals),
253
+ "dispatch_purpose": dispatch_purpose,
254
+ "outcome": outcome,
255
+ }
256
+
257
+
258
+ def append_round(entry: dict, cwd=None) -> Path | None:
259
+ """Append one row to `.claude/metrics/review-value.jsonl`.
260
+
261
+ Fail-open on the write, matching every other metrics emitter in this
262
+ plugin: a full disk or read-only metrics directory must never fail a
263
+ review. Returns the path written, or `None` when the write failed.
264
+ """
265
+ try:
266
+ base = Path(cwd) if cwd else Path.cwd()
267
+ log = (
268
+ artifact_paths.resolve_file("metrics", _STREAM_NAME, base)
269
+ if artifact_paths is not None
270
+ else base / ".claude" / "metrics" / _STREAM_NAME
271
+ )
272
+ log.parent.mkdir(parents=True, exist_ok=True)
273
+ with open(log, "a", encoding="utf-8") as handle:
274
+ handle.write(json.dumps(entry, separators=(",", ":"), sort_keys=True) + "\n")
275
+ return log
276
+ except Exception: # noqa: BLE001 - fail-open: telemetry never blocks a review
277
+ return None
278
+
279
+
280
+ def _load_findings(path: str | None):
281
+ if not path:
282
+ return []
283
+ text = sys.stdin.read() if path == "-" else Path(path).read_text(encoding="utf-8")
284
+ if not text.strip():
285
+ return []
286
+ data = json.loads(text)
287
+ if isinstance(data, dict):
288
+ data = data.get("findings", [])
289
+ return data if isinstance(data, list) else []
290
+
291
+
292
+ def main(argv=None) -> int:
293
+ parser = argparse.ArgumentParser(description="Append one /code-review round to review-value.jsonl")
294
+ parser.add_argument("--round", type=int, required=True, dest="round_number")
295
+ parser.add_argument(
296
+ "--agents", default="", help="Comma-separated agent names dispatched this round"
297
+ )
298
+ parser.add_argument(
299
+ "--findings",
300
+ default=None,
301
+ help="Path to this round's NEW findings JSON (a list, or {findings: [...]}); '-' for stdin",
302
+ )
303
+ parser.add_argument("--carried", type=int, default=0, dest="findings_carried")
304
+ parser.add_argument("--purpose", required=True, choices=list(DISPATCH_PURPOSES))
305
+ parser.add_argument("--outcome", required=True, choices=list(OUTCOMES))
306
+ parser.add_argument(
307
+ "--fix-diff",
308
+ default=None,
309
+ dest="fix_diff",
310
+ help="Path to the PREVIOUS round's fix diff (unified); '-' for stdin. Omit for round 1.",
311
+ )
312
+ parser.add_argument("--cwd", default=None)
313
+ parser.add_argument(
314
+ "--dry-run",
315
+ action="store_true",
316
+ help="Print the row that would be appended without writing it",
317
+ )
318
+ args = parser.parse_args(argv)
319
+
320
+ findings = _load_findings(args.findings)
321
+ fix_diff = ""
322
+ if args.fix_diff:
323
+ fix_diff = (
324
+ sys.stdin.read()
325
+ if args.fix_diff == "-"
326
+ else Path(args.fix_diff).read_text(encoding="utf-8")
327
+ )
328
+
329
+ entry = build_round_entry(
330
+ round_number=args.round_number,
331
+ agents_run=[a.strip() for a in args.agents.split(",") if a.strip()],
332
+ findings_new=findings,
333
+ findings_carried=args.findings_carried,
334
+ dispatch_purpose=args.purpose,
335
+ outcome=args.outcome,
336
+ fix_diff=fix_diff,
337
+ )
338
+ if not args.dry_run:
339
+ append_round(entry, args.cwd)
340
+ print(json.dumps(entry, sort_keys=True))
341
+ return 0
342
+
343
+
344
+ if __name__ == "__main__":
345
+ raise SystemExit(main(sys.argv[1:]))