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,742 @@
1
+ #!/usr/bin/env python3
2
+ """coverage_discovery_java.py — discover and classify every module in a Java
3
+ multi-module build for multi-project coverage discovery (issue #1765).
4
+
5
+ Generalizes the shape landed for .NET solutions (`coverage_discovery_dotnet.py`)
6
+ and JS/TS workspaces (`coverage_discovery_js.py`) in #1759/#1822 to the two
7
+ JVM multi-module build graphs:
8
+
9
+ - **Maven** — the root `pom.xml`'s `<modules><module>` list, resolved
10
+ **recursively** through aggregator modules (a module that itself declares
11
+ `<modules>` contributes its own children), with cycle protection so a
12
+ self- or mutually-referential graph terminates.
13
+ - **Gradle** — `settings.gradle` / `settings.gradle.kts` `include(...)`
14
+ declarations, translating Gradle's colon-separated project paths (`:a:b`)
15
+ to directory paths (`a/b`). Both the parenthesized (Kotlin DSL) and bare
16
+ (Groovy) call forms are recognized, including a multi-line argument list —
17
+ `include ':app',\n ':lib'` is a single declaration and yields BOTH
18
+ modules. `includeBuild` (composite builds) and `includeFlat` (sibling-
19
+ directory projects) are separate build graphs and are deliberately out of
20
+ scope; neither is mistaken for `include`.
21
+
22
+ **Out of scope, named explicitly.** A Gradle subproject whose directory is
23
+ remapped in `settings.gradle` (`project(":api").projectDir = file("custom")`)
24
+ is not resolved to its remapped location — this module resolves the default
25
+ `:a:b` → `a/b` layout only. Because a declared module whose directory is
26
+ absent is a hard `discovery_error` (never a silent `NOT_TEST`), such a
27
+ remapping surfaces as a loud, actionable error naming the missing path rather
28
+ than silently dropping the subproject from coverage accounting.
29
+
30
+ **Stack precedence (no cross-merge).** When both a root `pom.xml` declaring
31
+ `<modules>` and a `settings.gradle*` declaring `include(...)` are present,
32
+ Maven wins and Gradle is not consulted — the same "first present config wins"
33
+ rule `coverage_discovery_js.py` applies across `package.json#workspaces` →
34
+ `pnpm-workspace.yaml` → `lerna.json`.
35
+
36
+ **No JVM, no build-tool CLI.** Unlike .NET discovery (which shells out to
37
+ `dotnet sln list`), this module is a pure static parse, matching the JS/TS
38
+ module's filesystem-only approach. Invoking `mvn`/`gradlew` would require a
39
+ JVM and network access for plugin resolution and cost tens of seconds on
40
+ every measurement — unacceptable for a per-run re-derivation.
41
+
42
+ **Identity contract.** A module's "path" is its directory, expressed relative
43
+ to `repo_root` in POSIX form (matching both existing discovery modules) — the
44
+ exact, unmodified string every caller compares against `included`/`excluded`
45
+ entries, per `coverage_config`'s identity contract. The POSIX-relative
46
+ rendering is applied once at resolution time, never per comparison.
47
+
48
+ **Classification.** `TEST` when the module has BOTH a test-source directory
49
+ (`src/test/java` or `src/test/kotlin`) AND a JUnit/TestNG dependency declared
50
+ in its own build file. `AMBIGUOUS` — never silently `NOT_TEST` — when a
51
+ test-source directory is present but the test-framework dependency is not
52
+ declared in the module's own build file: it may be inherited from a parent
53
+ POM's `<dependencyManagement>`/`<dependencies>` or a Gradle `subprojects {}`
54
+ block or convention plugin. This module deliberately never evaluates that
55
+ inheritance (mirroring the .NET module's refusal to evaluate MSBuild
56
+ `Condition` attributes); it reports the ambiguity and lets
57
+ `coverage_config.drift_check` force an operator decision. `NOT_TEST` only
58
+ when there is no test-source directory at all.
59
+
60
+ **Security hardening.** Every resolved module directory, every build file
61
+ read, and the test-source-directory probe are verified to stay within the
62
+ resolved repository root before they are read or classified — a
63
+ `<module>../../etc</module>`, an `include(':..:..')`, a symlinked build file,
64
+ or a symlinked `src/test/java` can never cause this module to read or stat
65
+ outside the repository. An out-of-root entry is reported as an error, never
66
+ silently dropped.
67
+
68
+ Every XML read routes through `coverage_config.read_and_screen_xml`, the
69
+ shared `<!DOCTYPE`/`<!ENTITY` entity-expansion screen the .NET stack
70
+ introduced (`xml.etree.ElementTree` is explicitly not secure against
71
+ maliciously constructed data, and a `pom.xml` never legitimately carries
72
+ either declaration). It reads the bytes once and the caller parses THOSE
73
+ bytes via `ET.fromstring`, so no path is ever checked and then re-opened.
74
+ Gradle build files are read the same way — one read per contained path, never
75
+ a resolve-then-reopen pair.
76
+
77
+ A parsed Gradle project spec is validated against a conservative character
78
+ allowlist before any path is built from it: a raw NUL (reachable because
79
+ settings files are decoded with `errors="replace"`, which does not replace
80
+ U+0000) would otherwise make `Path.resolve()` raise `ValueError` — not
81
+ `OSError` — and escape this module's "every failure is a structured
82
+ `discovery_error`" contract as an unhandled traceback.
83
+
84
+ Stdlib-only (ADR 0014/0015/0031).
85
+ """
86
+
87
+ from __future__ import annotations
88
+
89
+ import re
90
+ import sys
91
+ import xml.etree.ElementTree as ET
92
+ from pathlib import Path
93
+
94
+ _HERE = Path(__file__).resolve().parent
95
+ sys.path.insert(0, str(_HERE))
96
+
97
+ import coverage_config
98
+ from coverage_config import TestClassification
99
+
100
+ # Test-source directories that mark a module as carrying tests at all.
101
+ _TEST_SOURCE_DIRS = ("src/test/java", "src/test/kotlin")
102
+
103
+ # Test-framework tokens searched for in a module's own build file. Matched
104
+ # case-insensitively against the raw build-file text for Gradle, and against
105
+ # declared dependency coordinates for Maven.
106
+ _TEST_FRAMEWORK_TOKENS = ("junit", "testng")
107
+
108
+ _MAVEN_POM_FILE = "pom.xml"
109
+ _GRADLE_SETTINGS_FILES = ("settings.gradle", "settings.gradle.kts")
110
+ _GRADLE_BUILD_FILES = ("build.gradle", "build.gradle.kts")
111
+
112
+ # A Gradle line counts as a TEST-framework dependency declaration only when a
113
+ # test *configuration* is being invoked with an argument. `test`-prefixed
114
+ # covers testImplementation / testCompileOnly / testRuntimeOnly / testApi /
115
+ # testAnnotationProcessor; `androidTest`-prefixed covers the Android variants;
116
+ # `integrationTest…` and other custom test source sets match the same infix.
117
+ #
118
+ # The token may follow start-of-line, `{`, or `;` so the one-line
119
+ # `dependencies { testImplementation "…" }` form is recognized, and the
120
+ # character after it must begin an ARGUMENT — `(`, a quote, or an
121
+ # identifier/`$` — never `{`. That last exclusion is load-bearing: `test {
122
+ # useJUnitPlatform() }` configures the Test *task*, and `testng { suites … }`
123
+ # the TestNG plugin extension; neither declares a dependency, so treating
124
+ # either as one would resolve a genuinely inherited-only module to a confident
125
+ # `TEST` and spend the `AMBIGUOUS` signal `drift_check` needs.
126
+ # The `(?![A-Za-z])` after the identifier is load-bearing: without it the regex
127
+ # backtracks into a PREFIX of a longer name, so `testng { suites '…' }` matches
128
+ # as `test` followed by the argument-looking `n` of `ng`. The lookahead forces
129
+ # the identifier to be complete before the argument check runs.
130
+ _GRADLE_TEST_CONFIG_RE = re.compile(
131
+ r"(?:^|[{;])\s*[A-Za-z]*[Tt]est[A-Za-z]*(?![A-Za-z])\s*(?:\(|['\"]|[A-Za-z_$])",
132
+ re.ASCII,
133
+ )
134
+ # A declaration split across lines (`testImplementation(\n "…"\n)`) is joined
135
+ # before scanning, so the configuration token and its argument are seen
136
+ # together. A line ending in `(` or `,` continues into the next.
137
+ _GRADLE_CONTINUATION_END = ("(", ",")
138
+ # `platform(...)`/`enforcedPlatform(...)` pins a version without declaring a
139
+ # dependency — Gradle's analogue of Maven's <dependencyManagement>.
140
+ _GRADLE_BOM_RE = re.compile(r"\b(?:enforced)?platform\s*\(", re.ASCII)
141
+
142
+ # `include`, Groovy or Kotlin DSL — but never `includeBuild`, `includeFlat`, or
143
+ # any other `include`-prefixed identifier. The lookahead rejects an identifier
144
+ # continuation rather than one specific suffix, so a new Gradle `includeXxx`
145
+ # API can never silently start matching as `include`.
146
+ _GRADLE_INCLUDE_RE = re.compile(r"\binclude(?![A-Za-z0-9_])")
147
+ _GRADLE_QUOTED_RE = re.compile(r"""['"]([^'"]*)['"]""")
148
+ # Characters that may separate the quoted project paths of one `include` call.
149
+ # Anything else (`;`, a new statement, an identifier) ends the argument list.
150
+ _GRADLE_ARG_SEPARATORS = frozenset(" \t\r\n,()")
151
+ # Conservative allowlist for a Gradle project spec, applied BEFORE any path is
152
+ # built from it. A raw NUL is the motivating case: settings files are decoded
153
+ # with errors="replace", which does not replace U+0000, and `Path.resolve()`
154
+ # raises ValueError (not OSError) on an embedded null — escaping this module's
155
+ # structured-error contract as an unhandled traceback.
156
+ _GRADLE_SPEC_ALLOWED_RE = re.compile(r"^[A-Za-z0-9._:\-/ ]+$")
157
+
158
+
159
+ def discover_java_modules(repo_root):
160
+ """Discover and classify every module in `repo_root`'s Java multi-module
161
+ build.
162
+
163
+ Returns a list of `{"path": <repo-relative POSIX module directory>,
164
+ "classification": TestClassification}` entries on success (sorted by
165
+ path), `coverage_config.DISCOVERY_NOT_APPLICABLE` when no multi-module
166
+ signal is present, or `coverage_config.discovery_error(...)` for a
167
+ parsing or path-containment failure.
168
+ """
169
+ root = Path(repo_root).resolve()
170
+
171
+ rel_paths = _maven_module_paths(root)
172
+ if rel_paths is None:
173
+ rel_paths = _gradle_module_paths(root)
174
+ if rel_paths is None:
175
+ return coverage_config.DISCOVERY_NOT_APPLICABLE
176
+ if isinstance(rel_paths, dict):
177
+ return rel_paths # a discovery_error propagated up
178
+
179
+ modules = []
180
+ for rel_path in rel_paths:
181
+ classification = _classify_module(root / rel_path, root)
182
+ if isinstance(classification, dict):
183
+ return classification # a discovery_error propagated up
184
+ modules.append({"path": rel_path, "classification": classification})
185
+ return modules
186
+
187
+
188
+ # ---------------------------------------------------------------------------
189
+ # Maven — recursive <modules> resolution
190
+ # ---------------------------------------------------------------------------
191
+
192
+
193
+ def _maven_module_paths(root: Path):
194
+ """Resolve the root `pom.xml`'s `<modules>` list, recursively through
195
+ aggregator modules.
196
+
197
+ Returns a sorted list of repo-relative POSIX module directories,
198
+ `None` when this stack does not apply (no root `pom.xml`, or one that
199
+ declares no `<modules>` element at all — a single-module project), or
200
+ `coverage_config.discovery_error(...)` for a parse, containment, or
201
+ empty-declaration failure."""
202
+ root_pom = root / _MAVEN_POM_FILE
203
+ if not root_pom.is_file():
204
+ return None
205
+
206
+ declared = _parse_pom_modules(root_pom, root)
207
+ if isinstance(declared, dict):
208
+ return declared # a discovery_error propagated up
209
+ if declared is None:
210
+ return None # no <modules> element — single-module project
211
+
212
+ if not declared:
213
+ return coverage_config.discovery_error(
214
+ f"'{root_pom}' declares a <modules> element with no <module> "
215
+ "entries. A declared-but-empty module list cannot be "
216
+ "distinguished from a discovery bug, and silently treating it as "
217
+ "an empty project list is the exact silent-exclusion failure "
218
+ "mode multi-project discovery exists to prevent. Remove the "
219
+ "empty <modules> element, or list the real modules."
220
+ )
221
+
222
+ resolved: set[str] = set()
223
+ # Each queue item is a (module-spec, declaring-pom-directory) pair, so a
224
+ # nested aggregator's <module> entries resolve relative to that
225
+ # aggregator's own directory, the way Maven itself resolves them.
226
+ queue = [(spec, root) for spec in declared]
227
+ while queue:
228
+ spec, base = queue.pop()
229
+ module_dir = _contained_dir(base / spec, root)
230
+ if isinstance(module_dir, dict):
231
+ return module_dir # a discovery_error propagated up
232
+ if not module_dir.is_dir():
233
+ return coverage_config.discovery_error(
234
+ f"'{base / 'pom.xml'}' declares <module>{spec}</module> but "
235
+ f"'{module_dir}' is not a directory on disk. A declared "
236
+ "module that does not exist is a broken build graph, not a "
237
+ "non-test module — classifying it NOT_TEST would drop it from "
238
+ "coverage accounting silently."
239
+ )
240
+
241
+ rel = module_dir.relative_to(root).as_posix()
242
+ if rel in resolved:
243
+ continue # cycle, or the same module declared twice
244
+ resolved.add(rel)
245
+
246
+ child_pom = module_dir / _MAVEN_POM_FILE
247
+ if not child_pom.is_file():
248
+ # Same domain fact as the missing-directory branch above, so it
249
+ # gets the same treatment: `mvn` itself fails on a <module> with
250
+ # no POM, making this a broken build graph rather than a non-test
251
+ # module. Classifying it would land it on AMBIGUOUS/NOT_TEST and
252
+ # (for NOT_TEST) drop it from accounting silently.
253
+ #
254
+ # Deliberately Maven-only: a Gradle subproject directory with no
255
+ # build file is legitimate (a container project), so the Gradle
256
+ # branch keeps `_classify_module`'s lenient path.
257
+ return coverage_config.discovery_error(
258
+ f"'{base / _MAVEN_POM_FILE}' declares <module>{spec}</module> "
259
+ f"but '{child_pom}' does not exist. A declared Maven module "
260
+ "with no POM is a broken build graph — `mvn` itself fails on "
261
+ "it — not a non-test module."
262
+ )
263
+ child_modules = _parse_pom_modules(child_pom, root)
264
+ if isinstance(child_modules, dict):
265
+ return child_modules # a discovery_error propagated up
266
+ if child_modules == []:
267
+ # Same rule as the root POM below: a declared-but-empty <modules>
268
+ # is indistinguishable from a discovery bug, so it must never be
269
+ # accepted silently — one level down included.
270
+ return coverage_config.discovery_error(
271
+ f"'{child_pom}' declares a <modules> element with no <module> "
272
+ "entries. A declared-but-empty module list cannot be "
273
+ "distinguished from a discovery bug; remove the empty "
274
+ "<modules> element, or list the real modules."
275
+ )
276
+ for child_spec in child_modules or ():
277
+ queue.append((child_spec, module_dir))
278
+
279
+ return sorted(resolved)
280
+
281
+
282
+ def _parse_pom_modules(pom_path: Path, root: Path):
283
+ """Return the list of `<module>` text values declared in `pom_path`'s
284
+ `<modules>` element, `None` when the POM declares no `<modules>` element
285
+ at all, or `coverage_config.discovery_error(...)` when the file cannot be
286
+ read, is not well-formed XML, or resolves outside `root`."""
287
+ root_el = _parse_contained_xml(pom_path, root)
288
+ if isinstance(root_el, dict):
289
+ return root_el # a discovery_error propagated up
290
+
291
+ for child in root_el:
292
+ if coverage_config.local_name(child.tag) != "modules":
293
+ continue
294
+ specs = []
295
+ for module_el in child:
296
+ if coverage_config.local_name(module_el.tag) != "module":
297
+ continue
298
+ text = (module_el.text or "").strip()
299
+ if text:
300
+ specs.append(text)
301
+ return specs
302
+ return None
303
+
304
+
305
+ # ---------------------------------------------------------------------------
306
+ # Gradle — settings.gradle(.kts) include(...) resolution
307
+ # ---------------------------------------------------------------------------
308
+
309
+
310
+ def _gradle_module_paths(root: Path):
311
+ """Resolve `include(...)` declarations from `settings.gradle` or
312
+ `settings.gradle.kts`.
313
+
314
+ Returns a sorted list of repo-relative POSIX module directories,
315
+ `None` when neither settings file is present (this stack does not
316
+ apply), or `coverage_config.discovery_error(...)` when a settings file is
317
+ present but declares no `include(...)` this parser recognizes, or a
318
+ resolved project escapes `root`."""
319
+ settings_path = None
320
+ for name in _GRADLE_SETTINGS_FILES:
321
+ candidate = root / name
322
+ if candidate.is_file():
323
+ settings_path = candidate
324
+ break
325
+ if settings_path is None:
326
+ return None
327
+
328
+ text = _read_contained_text(settings_path, root)
329
+ if isinstance(text, dict):
330
+ return text # a discovery_error propagated up
331
+
332
+ specs = _parse_gradle_includes(text)
333
+ if not specs:
334
+ return coverage_config.discovery_error(
335
+ f"'{settings_path}' is present but declares no include(...) this "
336
+ "parser recognizes (supported: Groovy and Kotlin DSL "
337
+ "include ':a', include(\":a\", \":b\") forms; includeBuild "
338
+ "composite builds are out of scope). Treating it as "
339
+ "single-project would silently exclude every subproject from "
340
+ "coverage — the exact failure mode multi-project discovery "
341
+ "exists to prevent."
342
+ )
343
+
344
+ resolved: set[str] = set()
345
+ for spec in specs:
346
+ cleaned = spec.strip().strip(":")
347
+ rel_spec = cleaned.replace(":", "/")
348
+ if not rel_spec:
349
+ continue
350
+ if not _GRADLE_SPEC_ALLOWED_RE.match(rel_spec):
351
+ return coverage_config.discovery_error(
352
+ f"'{settings_path}' includes a project spec containing "
353
+ "characters this module refuses to build a path from "
354
+ f"({cleaned!r}); allowed characters are letters, digits, and "
355
+ "'. _ - / :'. Refusing to resolve it."
356
+ )
357
+ module_dir = _contained_dir(root / rel_spec, root)
358
+ if isinstance(module_dir, dict):
359
+ return module_dir # a discovery_error propagated up
360
+ if not module_dir.is_dir():
361
+ return coverage_config.discovery_error(
362
+ f"'{settings_path}' includes ':{spec.strip().strip(':')}' but "
363
+ f"'{module_dir}' is not a directory on disk. A declared "
364
+ "subproject that does not exist is a broken build graph, not a "
365
+ "non-test module — classifying it NOT_TEST would drop it from "
366
+ "coverage accounting silently. (A subproject whose directory is "
367
+ "remapped via project(...).projectDir is not resolved by this "
368
+ "module; see the module docstring.)"
369
+ )
370
+ resolved.add(module_dir.relative_to(root).as_posix())
371
+ if not resolved:
372
+ return coverage_config.discovery_error(
373
+ f"'{settings_path}' declares include(...) entries but none "
374
+ "resolved to a subproject path."
375
+ )
376
+ return sorted(resolved)
377
+
378
+
379
+ def _parse_gradle_includes(text: str) -> list:
380
+ """Every quoted project path declared by an `include` call in `text`.
381
+
382
+ Scans the **whole comment-stripped document**, not line by line: a Groovy
383
+ multi-line argument list (`include ':app',\\n ':lib'`) is one
384
+ declaration and must yield both modules. Parsing per line would see
385
+ `':lib'` on a line with no `include` token and silently drop it — a
386
+ partial discovery is the same silent-subproject-exclusion failure mode
387
+ this module exists to prevent, and unlike a zero-spec parse it would slip
388
+ past the "no recognized include" guard because `specs` is non-empty.
389
+
390
+ `includeBuild`/`includeFlat` are excluded by the regex's identifier
391
+ lookahead, and each call's argument list is bounded by
392
+ `_collect_quoted_args`, so a second statement on the same line
393
+ (`include ':core'; includeBuild '../other'`) cannot bleed into the
394
+ first call's specs."""
395
+ stripped = _strip_gradle_comments(text)
396
+ specs = []
397
+ for match in _GRADLE_INCLUDE_RE.finditer(stripped):
398
+ specs.extend(_collect_quoted_args(stripped, match.end()))
399
+ return specs
400
+
401
+
402
+ def _collect_quoted_args(text: str, start: int) -> list:
403
+ """The quoted string arguments of one `include` call beginning at `start`.
404
+
405
+ Consumes quoted strings separated only by `_GRADLE_ARG_SEPARATORS`
406
+ (whitespace, commas, parentheses), so a multi-line list keeps collecting
407
+ across newlines. Any other character — `;`, a new `include`, an
408
+ identifier, an assignment — ends this call's argument list."""
409
+ args = []
410
+ i = start
411
+ length = len(text)
412
+ while i < length:
413
+ ch = text[i]
414
+ if ch in _GRADLE_ARG_SEPARATORS:
415
+ i += 1
416
+ continue
417
+ if ch in "'\"":
418
+ match = _GRADLE_QUOTED_RE.match(text, i)
419
+ if match is None:
420
+ break # an unterminated quote ends the argument list
421
+ args.append(match.group(1))
422
+ i = match.end()
423
+ continue
424
+ break
425
+ return args
426
+
427
+
428
+ def _strip_gradle_comments(text: str) -> str:
429
+ """`text` with `//` line comments and `/* ... */` block comments replaced
430
+ by whitespace, ignoring comment markers that appear inside a quoted
431
+ string. Block comments are handled because commenting out a subproject
432
+ with `/* include ':legacy' */` is an ordinary Gradle idiom, and treating
433
+ it as a live declaration would invent a phantom module.
434
+
435
+ Comment spans are replaced with spaces rather than removed so that
436
+ positions stay aligned and a block comment can never join two separate
437
+ statements into one."""
438
+ out = []
439
+ i = 0
440
+ length = len(text)
441
+ quote = None
442
+ while i < length:
443
+ ch = text[i]
444
+ if quote:
445
+ out.append(ch)
446
+ if ch == "\\" and i + 1 < length:
447
+ out.append(text[i + 1]) # an escape can't close the string
448
+ i += 2
449
+ continue
450
+ if ch == quote:
451
+ quote = None
452
+ i += 1
453
+ continue
454
+ if ch in "'\"":
455
+ quote = ch
456
+ out.append(ch)
457
+ i += 1
458
+ continue
459
+ if ch == "/" and text[i + 1 : i + 2] == "/":
460
+ while i < length and text[i] != "\n":
461
+ out.append(" ")
462
+ i += 1
463
+ continue
464
+ if ch == "/" and text[i + 1 : i + 2] == "*":
465
+ end = text.find("*/", i + 2)
466
+ stop = length if end == -1 else end + 2
467
+ for j in range(i, stop):
468
+ out.append("\n" if text[j] == "\n" else " ")
469
+ i = stop
470
+ continue
471
+ out.append(ch)
472
+ i += 1
473
+ return "".join(out)
474
+
475
+
476
+ # ---------------------------------------------------------------------------
477
+ # Containment helpers
478
+ # ---------------------------------------------------------------------------
479
+
480
+
481
+ def _contained_dir(candidate: Path, root: Path):
482
+ """`candidate` resolved, once, after confirming it stays inside `root`;
483
+ otherwise `coverage_config.discovery_error(...)`.
484
+
485
+ Containment only — this helper deliberately does not require the path to
486
+ exist, because a non-existent path still has to be containment-checked
487
+ before it is named in any message. Existence is the CALLER's check: both
488
+ `_maven_module_paths` and `_gradle_module_paths` reject a declared module
489
+ whose directory is absent as its own `discovery_error`, matching
490
+ `coverage_discovery_dotnet.py`'s missing-project error rather than letting
491
+ it classify `NOT_TEST` and vanish from coverage accounting."""
492
+ try:
493
+ resolved = candidate.resolve()
494
+ except (OSError, ValueError) as exc:
495
+ # ValueError, not just OSError — see `_contained_file` for why.
496
+ return coverage_config.discovery_error(
497
+ f"Could not resolve module path '{candidate}': {exc}"
498
+ )
499
+ if not coverage_config.is_within(resolved, root):
500
+ return coverage_config.discovery_error(
501
+ f"Module path '{candidate}' resolves to '{resolved}', which is "
502
+ f"outside the repository root ('{root}'); refusing to include it."
503
+ )
504
+ return resolved
505
+
506
+
507
+ def _contained_file(candidate: Path, root: Path):
508
+ """`candidate` resolved (following symlinks) after confirming the resolved
509
+ target stays inside `root`; otherwise `coverage_config.discovery_error(...)`.
510
+ Separate from `_contained_dir` because a symlinked build file inside an
511
+ already-contained directory can still point outside the repository."""
512
+ try:
513
+ resolved = candidate.resolve()
514
+ except (OSError, ValueError) as exc:
515
+ # ValueError, not just OSError: `resolve()` raises it for a path with
516
+ # an embedded NUL, which is reachable from a settings file decoded
517
+ # with errors="replace" (U+0000 is not replaced).
518
+ return coverage_config.discovery_error(
519
+ f"Could not resolve build file '{candidate}': {exc}"
520
+ )
521
+ if not coverage_config.is_within(resolved, root):
522
+ return coverage_config.discovery_error(
523
+ f"Build file '{candidate}' resolves to '{resolved}', which is "
524
+ f"outside the repository root ('{root}'); refusing to read it."
525
+ )
526
+ return resolved
527
+
528
+
529
+ def _parse_contained_xml(path: Path, root: Path):
530
+ """The parsed root element of the XML at `path`, or
531
+ `coverage_config.discovery_error(...)`.
532
+
533
+ Containment-checks `path`, then reads it ONCE through
534
+ `coverage_config.read_and_screen_xml` — the shared `<!DOCTYPE`/`<!ENTITY`
535
+ entity-expansion screen — and parses THOSE bytes. Never re-opens the
536
+ checked path, so there is no resolve-then-reopen window in which a
537
+ symlink swap could redirect the read."""
538
+ contained = _contained_file(path, root)
539
+ if isinstance(contained, dict):
540
+ return contained # a discovery_error propagated up
541
+ data, error = coverage_config.read_and_screen_xml(contained)
542
+ if error is not None:
543
+ return error
544
+ try:
545
+ return ET.fromstring(data)
546
+ except ET.ParseError as exc:
547
+ return coverage_config.discovery_error(
548
+ f"Could not parse '{path}' as XML: {exc}"
549
+ )
550
+
551
+
552
+ def _read_contained_text(path: Path, root: Path):
553
+ """The text of the file at `path`, or
554
+ `coverage_config.discovery_error(...)`.
555
+
556
+ Containment-checks `path` and reads it exactly once. Decoded with
557
+ `errors="replace"` because a Gradle settings/build file's encoding is not
558
+ declared anywhere — an undecodable byte must not abort discovery. Callers
559
+ that build a filesystem path from the decoded text must validate it first
560
+ (see `_GRADLE_SPEC_ALLOWED_RE`): `errors="replace"` does not replace
561
+ U+0000."""
562
+ contained = _contained_file(path, root)
563
+ if isinstance(contained, dict):
564
+ return contained # a discovery_error propagated up
565
+ try:
566
+ return contained.read_text(encoding="utf-8", errors="replace")
567
+ except OSError as exc:
568
+ return coverage_config.discovery_error(f"Could not read '{path}': {exc}")
569
+
570
+
571
+ # ---------------------------------------------------------------------------
572
+ # Module classification
573
+ # ---------------------------------------------------------------------------
574
+
575
+
576
+ def _classify_module(module_dir: Path, root: Path):
577
+ """`TEST` when `module_dir` has both a test-source directory and a
578
+ JUnit/TestNG dependency in its own build file; `AMBIGUOUS` when it has a
579
+ test-source directory but no such dependency declared locally (it may be
580
+ inherited — this module never evaluates inheritance); `NOT_TEST` when it
581
+ has no test-source directory at all.
582
+
583
+ Returns `coverage_config.discovery_error(...)` instead — never a
584
+ classification — when a build file exists but cannot be read or parsed, or
585
+ when it (or a test-source directory) resolves outside `root`."""
586
+ has_test_sources = False
587
+ for rel in _TEST_SOURCE_DIRS:
588
+ # Route the probe through the containment check rather than a bare
589
+ # `is_dir()`: `is_dir()` follows symlinks, so `mod/src/test/java -> /etc`
590
+ # would otherwise stat outside the repository root and let an
591
+ # out-of-root directory's existence decide this module's
592
+ # classification.
593
+ candidate = _contained_dir(module_dir / rel, root)
594
+ if isinstance(candidate, dict):
595
+ return candidate # a discovery_error propagated up
596
+ if candidate.is_dir():
597
+ has_test_sources = True
598
+ break
599
+ if not has_test_sources:
600
+ return TestClassification.NOT_TEST
601
+
602
+ declares_framework = _declares_test_framework(module_dir, root)
603
+ if isinstance(declares_framework, dict):
604
+ return declares_framework # a discovery_error propagated up
605
+ return (
606
+ TestClassification.TEST
607
+ if declares_framework
608
+ else TestClassification.AMBIGUOUS
609
+ )
610
+
611
+
612
+ def _declares_test_framework(module_dir: Path, root: Path):
613
+ """True when `module_dir`'s own build file declares a JUnit or TestNG
614
+ dependency; False when no build file declares one (including when the
615
+ module has no build file at all — an inherited-only declaration is
616
+ indistinguishable from none here, which is exactly why the caller maps
617
+ False to `AMBIGUOUS` rather than `NOT_TEST`). Returns
618
+ `coverage_config.discovery_error(...)` when a build file exists but cannot
619
+ be read or parsed.
620
+
621
+ Both branches are scoped the SAME way, deliberately: to a real dependency
622
+ declaration in the module's own build file. An earlier version scoped the
623
+ POM branch carefully and then let the Gradle branch substring-scan the
624
+ whole file — which resolved to a confident `TEST` for exactly the shapes
625
+ the POM branch documents as wrong (a `platform('org.junit:junit-bom')`
626
+ version pin, a `plugins { id 'org.junit...' }` id, a project name
627
+ containing `junit`), silently spending the `AMBIGUOUS` signal
628
+ `drift_check` needs."""
629
+ pom_path = module_dir / _MAVEN_POM_FILE
630
+ if pom_path.is_file():
631
+ found = _pom_declares_test_framework(pom_path, root)
632
+ if isinstance(found, dict) or found:
633
+ return found
634
+
635
+ for name in _GRADLE_BUILD_FILES:
636
+ build_path = module_dir / name
637
+ if not build_path.is_file():
638
+ continue
639
+ text = _read_contained_text(build_path, root)
640
+ if isinstance(text, dict):
641
+ return text # a discovery_error propagated up
642
+ if _gradle_text_declares_test_framework(text):
643
+ return True
644
+
645
+ return False
646
+
647
+
648
+ def _gradle_text_declares_test_framework(text: str) -> bool:
649
+ """True when comment-stripped Gradle build-script `text` declares a
650
+ JUnit/TestNG dependency on a TEST configuration.
651
+
652
+ Scoped to match the POM branch's precision rather than substring-scanning
653
+ the file:
654
+
655
+ - only lines whose dependency configuration is a test one
656
+ (`testImplementation`, `testCompileOnly`, `testRuntimeOnly`,
657
+ `testApi`, `androidTestImplementation`, …) count. A `plugins { id
658
+ 'org.junit.platform...' }` line, an `archivesBaseName` containing
659
+ `junit`, or a non-test `implementation` are not test dependencies.
660
+ - a `platform(...)`/`enforcedPlatform(...)` BOM line is excluded: like
661
+ Maven's `<dependencyManagement>`, it pins a version without declaring
662
+ a dependency, so it must leave the module `AMBIGUOUS` rather than
663
+ resolving it to `TEST`."""
664
+ for line in _join_gradle_continuations(_strip_gradle_comments(text)):
665
+ lowered = line.lower()
666
+ if not any(token in lowered for token in _TEST_FRAMEWORK_TOKENS):
667
+ continue
668
+ if _GRADLE_BOM_RE.search(lowered):
669
+ continue # a version pin, not a dependency declaration
670
+ if _GRADLE_TEST_CONFIG_RE.search(line):
671
+ return True
672
+ return False
673
+
674
+
675
+ def _join_gradle_continuations(text: str) -> list:
676
+ """`text`'s lines, with a line that ends in `(` or `,` joined to the one
677
+ after it.
678
+
679
+ Without this, a Kotlin-DSL declaration split across lines —
680
+ `testImplementation(\\n "org.junit.jupiter:junit-jupiter"\\n)` — hides the
681
+ configuration token from its own argument: the first line carries no
682
+ framework token and the second does not begin with the configuration, so
683
+ the module would classify `AMBIGUOUS` despite declaring the dependency
684
+ locally."""
685
+ joined = []
686
+ pending = ""
687
+ for raw_line in text.splitlines():
688
+ line = raw_line.strip()
689
+ if not line:
690
+ continue
691
+ pending = f"{pending} {line}".strip() if pending else line
692
+ if pending.endswith(_GRADLE_CONTINUATION_END):
693
+ continue
694
+ joined.append(pending)
695
+ pending = ""
696
+ if pending:
697
+ joined.append(pending)
698
+ return joined
699
+
700
+
701
+ def _pom_declares_test_framework(pom_path: Path, root: Path):
702
+ """True when `pom_path`'s own top-level `<dependencies>` declare a JUnit or
703
+ TestNG artifact; False otherwise; `coverage_config.discovery_error(...)`
704
+ when the POM cannot be read or is not well-formed XML.
705
+
706
+ Scoped deliberately to `<project>`'s DIRECT `<dependencies>` child, and
707
+ within it to each `<dependency>`'s own `<groupId>`/`<artifactId>`. A
708
+ whole-document scan would classify as `TEST`: a module merely *named*
709
+ `junit-extensions` (its own `<artifactId>`), a `<dependencyManagement>`
710
+ or `junit-bom` version declaration, a `junit-platform-maven-plugin` under
711
+ `<build><plugins>`, and a `<profiles>`-scoped dependency. The first three
712
+ are not dependencies of this module at all; the last is *conditional*, and
713
+ a conditional declaration is exactly what this module reports as
714
+ `AMBIGUOUS` (mirroring the .NET module's refusal to evaluate MSBuild
715
+ `Condition` attributes) rather than resolving to a confident `TEST`.
716
+ Returning False for those shapes is what preserves the `AMBIGUOUS` signal
717
+ `drift_check` uses to force an operator decision."""
718
+ root_el = _parse_contained_xml(pom_path, root)
719
+ if isinstance(root_el, dict):
720
+ return root_el # a discovery_error propagated up
721
+
722
+ for child in root_el:
723
+ if coverage_config.local_name(child.tag) != "dependencies":
724
+ continue
725
+ for dependency in child:
726
+ if coverage_config.local_name(dependency.tag) != "dependency":
727
+ continue
728
+ if _dependency_names_test_framework(dependency):
729
+ return True
730
+ return False
731
+
732
+
733
+ def _dependency_names_test_framework(dependency) -> bool:
734
+ """True when a single `<dependency>` element's own `<groupId>`/
735
+ `<artifactId>` names a JUnit or TestNG artifact."""
736
+ for field in dependency:
737
+ if coverage_config.local_name(field.tag) not in ("groupId", "artifactId"):
738
+ continue
739
+ value = (field.text or "").lower()
740
+ if any(token in value for token in _TEST_FRAMEWORK_TOKENS):
741
+ return True
742
+ return False