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,847 @@
1
+ #!/usr/bin/env python3
2
+ """stryker_shard_pipeline.py — sharded Stryker pipeline with timeout-abort.
3
+
4
+ Migrated from the ACI ``nextgen-test-upgrade-process`` ``stryker-pipeline.py``
5
+ and de-hardcoded: nothing repo-specific lives here. Shards are discovered from
6
+ ``stryker-config.shard-*.json`` files (emitted by ``stryker_shard_setup.py``);
7
+ each shard runs Stryker through the shipped ``csharp_stryker_net_wrapper`` and
8
+ the per-shard survivor-fix loop is ``mutation_kill_loop`` forced into
9
+ ``--headless`` mode (the pipeline is unattended — there is no live agent turn).
10
+
11
+ Compounding worktrees: shards are processed **sequentially**, each in its own
12
+ git worktree created from the current ``HEAD``. Because the survivor-fix loop
13
+ commits its fixes onto ``HEAD`` before the next shard's worktree is created,
14
+ the second shard's worktree already contains the first shard's committed fixes.
15
+
16
+ Timeout-abort: Stryker output is streamed through the wrapper's line-callback
17
+ (added in #1136 Slice 5.1). A ``"N mutants got status Timeout"`` line kills the
18
+ Stryker process and marks the shard failed — timeouts are non-deterministic
19
+ noise that would otherwise inflate the score, so we refuse to score them.
20
+
21
+ Generic, stdlib-only, cross-platform (macOS, Linux, Windows). The only
22
+ non-stdlib imports are the three sibling plugin modules in this same
23
+ ``scripts/`` directory.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import argparse
29
+ import json
30
+ import os
31
+ import re
32
+ import subprocess
33
+ import sys
34
+ import threading
35
+ import time
36
+ from collections.abc import Callable, Sequence
37
+ from datetime import datetime, timezone
38
+ from pathlib import Path
39
+ from typing import NamedTuple
40
+
41
+ # typing, not collections.abc: the module-level type aliases below are real
42
+ # runtime expressions, so `from __future__ import annotations` cannot defer
43
+ # them — they must be subscriptable at import time. collections.abc generics
44
+ # have been since 3.9, which the 3.10 floor (ADR 0031) clears.
45
+ import csharp_stryker_net_wrapper as wrapper
46
+ import mutation_report
47
+ from mutation_kill_retry import EXIT_GENERATION_EXHAUSTED
48
+
49
+ # ── Constants ────────────────────────────────────────────────────────────────
50
+
51
+ PYTHON = sys.executable
52
+ LOOP_SCRIPT = str(Path(__file__).resolve().parent / "mutation_kill_loop.py")
53
+
54
+ SHARD_GLOB = "stryker-config.shard-*.json"
55
+ SHARD_PREFIX = "stryker-config.shard-"
56
+ SHARD_SUFFIX = ".json"
57
+
58
+ # Stryker prints e.g. "5 mutants got status Timeout" once at least one mutant
59
+ # times out. A leading non-zero count means real timeouts (never "0 mutants").
60
+ # The status word comes from mutation_report's status vocabulary (AC4) — no raw
61
+ # literal is retyped here.
62
+ TIMEOUT_PATTERN = re.compile(
63
+ rf"[1-9]\d*\s+mutants got status {mutation_report.STATUS_TIMEOUT}"
64
+ )
65
+
66
+ # Conventional C# test-file names paired with a source file's stem.
67
+ _TEST_FILE_SUFFIXES = ("Tests.cs", "Test.cs", "Specs.cs", "Spec.cs")
68
+
69
+
70
+ class ShardSetupMissing(Exception):
71
+ """No ``stryker-config.shard-*.json`` files were discovered — the operator
72
+ must run shard setup first. Carries an actionable message."""
73
+
74
+
75
+ class FixOutcome(NamedTuple):
76
+ """``launch_survivor_fix``'s return value (#1951).
77
+
78
+ Replaces the previous ``bool`` return plus a mutable ``exhausted``
79
+ out-parameter — extending that pattern with two more per-run outcomes
80
+ (unresolved test files, no report) would have meant threading a fourth
81
+ and fifth mutable accumulator through three function signatures, which
82
+ is the exact command-query smell #1951 flagged. A single typed result
83
+ mirrors :class:`ShardRunResult`'s existing precedent instead.
84
+
85
+ ``ok`` is False the moment a launched fix exits any non-zero, non-5 code
86
+ (see ``launch_survivor_fix``'s docstring for the full exit-code
87
+ decoding). ``exhausted``/``unresolved`` carry ``"shard/source"`` entries.
88
+ ``no_report`` is True when the shard had no Stryker report to act on at
89
+ all — no survivor files were even considered.
90
+ """
91
+
92
+ ok: bool
93
+ exhausted: list[str]
94
+ unresolved: list[str]
95
+ no_report: bool
96
+
97
+
98
+ class ShardOutcome(NamedTuple):
99
+ """``process_shard``'s return value (#1951).
100
+
101
+ ``status`` keeps the three prior string values (``"ok"`` / ``"failed"`` /
102
+ ``"skipped"``). The other three fields are ``launch_survivor_fix``'s
103
+ :class:`FixOutcome` propagated up one level — empty/False for a shard
104
+ that never reached the survivor-fix stage (Stryker itself failed, the
105
+ shard was skipped, or ``--skip-agent`` was set).
106
+ """
107
+
108
+ status: str
109
+ exhausted: list[str]
110
+ unresolved: list[str]
111
+ no_report: bool
112
+
113
+
114
+ class ShardRunResult(NamedTuple):
115
+ """``run_all``'s return value.
116
+
117
+ A NamedTuple (not a bare tuple) so a future call site can't silently
118
+ transpose fields — access by name, not position. #1951 widened this from
119
+ 2 fields (``failed``, ``exhausted``) to 5, so the previous "still
120
+ 2-tuple-unpackable" guarantee no longer holds: ``failed, exhausted =
121
+ run_all(...)`` now raises ``ValueError`` (too many values to unpack).
122
+ That guarantee was a bonus of a 2-field type, not a design goal in its
123
+ own right — every internal caller passes ``run_all``'s result straight
124
+ through by field access, so the trade (3 more silently-swallowed
125
+ run-level outcomes made visible) is worth the break.
126
+ """
127
+
128
+ failed: list[str]
129
+ exhausted: list[str]
130
+ unresolved: list[str]
131
+ no_report: list[str]
132
+ skipped: list[str]
133
+
134
+
135
+ # ── Small helpers ──────────────────────────────────────────────────────────────
136
+
137
+
138
+ def _safe(v: str) -> str:
139
+ """Whitespace-collapse a caller-supplied value before it lands in a log
140
+ line — same precedent as ``mutation_kill_loop.py``'s and
141
+ ``mutation_kill_loop_python.py``'s ``_commit_message`` (#1607):
142
+ ``source``/``shard`` are survivor-report file paths, not
143
+ operator-supplied, but could theoretically contain a newline that would
144
+ otherwise forge extra log lines."""
145
+ return " ".join(str(v).split())
146
+
147
+
148
+ def ts() -> str:
149
+ """Wall-clock ``HH:MM:SS`` stamp for per-shard progress lines."""
150
+ # Local wall-clock time is the point (a human-readable progress line),
151
+ # not a comparable timestamp — go through UTC-aware then convert back
152
+ # to the system local zone so the value stays tz-aware for DTZ005
153
+ # without changing the displayed (local) hour/minute/second.
154
+ return datetime.now(timezone.utc).astimezone().strftime("%H:%M:%S")
155
+
156
+
157
+ def shard_config_path(repo_root: Path, shard: str) -> Path:
158
+ return Path(repo_root) / f"{SHARD_PREFIX}{shard}{SHARD_SUFFIX}"
159
+
160
+
161
+ def report_path(out_dir: Path) -> Path:
162
+ return Path(out_dir) / "reports" / "mutation-report.json"
163
+
164
+
165
+ def discover_shards(repo_root: Path) -> list[str]:
166
+ """Return shard slugs from ``stryker-config.shard-*.json``, sorted.
167
+
168
+ Raises :class:`ShardSetupMissing` — naming how to generate the configs —
169
+ when none exist, rather than silently processing nothing.
170
+ """
171
+ configs = sorted(Path(repo_root).glob(SHARD_GLOB))
172
+ if not configs:
173
+ raise ShardSetupMissing(
174
+ f"No {SHARD_GLOB} files found in {repo_root}. Run shard setup first: "
175
+ "python3 stryker_shard_setup.py (generates one shard config per "
176
+ "source project)."
177
+ )
178
+ return [c.name[len(SHARD_PREFIX) : -len(SHARD_SUFFIX)] for c in configs]
179
+
180
+
181
+ # ── Timeout-abort callback ─────────────────────────────────────────────────────
182
+
183
+
184
+ def make_timeout_callback(
185
+ timed_out: threading.Event, *, log: Callable[[str], None] = print
186
+ ) -> Callable[[str], bool]:
187
+ """Return a line-callback for ``wrapper.run_stryker`` that sets
188
+ ``timed_out`` and requests an abort (returns True) on the first Stryker
189
+ timeout line. Every other line is echoed for live progress."""
190
+
191
+ def callback(line: str) -> bool:
192
+ sys.stdout.write(line)
193
+ if TIMEOUT_PATTERN.search(line):
194
+ timed_out.set()
195
+ return True
196
+ return False
197
+
198
+ return callback
199
+
200
+
201
+ # ── git worktree management ─────────────────────────────────────────────────────
202
+
203
+
204
+ def _git(cmd: Sequence[str], repo_root: Path, check: bool) -> subprocess.CompletedProcess:
205
+ """Run a git command in ``repo_root``.
206
+
207
+ ``check`` is deliberately POSITIONAL, not keyword-only. This is the default
208
+ ``GitRunner``, and that alias — ``Callable[[Sequence[str], Path, bool],
209
+ object]`` — is the contract every call site and every test fake already
210
+ implements positionally. Declaring it ``*, check`` here made the production
211
+ default the only implementation that did not satisfy its own alias, so
212
+ every real invocation (any path that does not inject a fake, which is all
213
+ of them: ``main()`` calls ``run_all(...)`` with no ``git_run``) raised
214
+ ``TypeError: _git() takes 2 positional arguments but 3 were given`` (#1953).
215
+
216
+ The bug was invisible to the suite precisely because every test injects a
217
+ fake, so the default was never exercised — which is why the regression
218
+ test below calls the real default rather than a fake.
219
+ """
220
+ return subprocess.run(
221
+ list(cmd), cwd=str(repo_root), capture_output=True, check=check
222
+ )
223
+
224
+
225
+ GitRunner = Callable[[Sequence[str], Path, bool], object]
226
+
227
+
228
+ def worktree_add(
229
+ repo_root: Path, path: Path, *, ref: str = "HEAD", git_run: GitRunner | None = None
230
+ ) -> None:
231
+ """Create a git worktree at ``path`` from ``ref`` (default ``HEAD``).
232
+
233
+ A pre-existing worktree at that path is force-removed first so reruns are
234
+ idempotent. Creating from ``HEAD`` is what makes shards compounding: the
235
+ fixes previous shards committed onto ``HEAD`` are already present.
236
+ """
237
+ git_run = git_run or _git
238
+ if Path(path).exists():
239
+ git_run(["git", "worktree", "remove", "--force", str(path)], repo_root, False)
240
+ git_run(["git", "worktree", "add", "--quiet", str(path), ref], repo_root, True)
241
+
242
+
243
+ def worktree_remove(
244
+ repo_root: Path, path: Path, *, git_run: GitRunner | None = None
245
+ ) -> None:
246
+ git_run = git_run or _git
247
+ git_run(["git", "worktree", "remove", "--force", str(path)], repo_root, False)
248
+
249
+
250
+ # ── Stryker runner (timeout-abort via the wrapper callback) ────────────────────
251
+
252
+
253
+ StrykerRunner = Callable[..., int]
254
+
255
+
256
+ def run_shard_stryker(
257
+ shard: str,
258
+ *,
259
+ repo_root: Path,
260
+ worktree: Path,
261
+ out_dir: Path,
262
+ stryker_bin: str,
263
+ log: Callable[[str], None] = print,
264
+ run_stryker: StrykerRunner | None = None,
265
+ ) -> bool:
266
+ """Run Stryker for one shard in its worktree. Returns True on success.
267
+
268
+ Streams output through ``wrapper.run_stryker``'s line-callback so a timeout
269
+ line kills the process and marks the shard failed — no re-implemented
270
+ streamer (AC4). A non-zero Stryker exit also fails the shard.
271
+ """
272
+ run_stryker = run_stryker or wrapper.run_stryker
273
+ config = shard_config_path(repo_root, shard)
274
+ if not config.exists():
275
+ log(f"ERROR: {config} not found")
276
+ return False
277
+
278
+ Path(out_dir).mkdir(parents=True, exist_ok=True)
279
+ logfile = Path(out_dir).parent / f"{shard}.log"
280
+
281
+ timed_out = threading.Event()
282
+ rc = run_stryker(
283
+ stryker_bin=stryker_bin,
284
+ stryker_args=["--config-file", str(config), "--output", str(out_dir)],
285
+ logfile=logfile,
286
+ line_callback=make_timeout_callback(timed_out, log=log),
287
+ cwd=worktree,
288
+ )
289
+
290
+ if timed_out.is_set():
291
+ log(
292
+ f"[{ts()}] Shard ABORTED (timeout): {shard} — increase "
293
+ "additional-timeout or reduce concurrency, then retry with "
294
+ "stryker_timeout_retry.py"
295
+ )
296
+ return False
297
+ if rc != 0:
298
+ log(f"[{ts()}] Shard FAILED: {shard} (exit {rc})")
299
+ return False
300
+ return True
301
+
302
+
303
+ # ── Survivor-fix launch (forced --headless) ─────────────────────────────────────
304
+
305
+
306
+ def survivor_source_files(report: Path) -> list[str]:
307
+ """Return the source-file keys in the report that have Survived mutants.
308
+
309
+ Report parsing and the ``Survived`` status vocabulary live in
310
+ ``mutation_report`` (AC4) — this never re-walks the report itself.
311
+ """
312
+ return mutation_report.files_with_survivors(report)
313
+
314
+
315
+ def shard_test_projects(config_path: Path) -> list[str]:
316
+ raw = json.loads(Path(config_path).read_text(encoding="utf-8"))
317
+ inner = raw.get("stryker-config", raw)
318
+ return list(inner.get("test-projects", []))
319
+
320
+
321
+ TestFileResolver = Callable[[str, Sequence[str], Path], Path | None]
322
+
323
+
324
+ def default_resolve_test_file(
325
+ source: str, test_projects: Sequence[str], repo_root: Path
326
+ ) -> Path | None:
327
+ """Best-effort convention search for a source file's test file.
328
+
329
+ Looks under each configured test-project directory for
330
+ ``<Stem>Tests.cs`` / ``<Stem>Test.cs`` / ``<Stem>Specs.cs``. Returns the
331
+ first hit, or None when no conventional pairing is found (the caller skips
332
+ that file rather than guessing — never a silent mis-target)."""
333
+ stem = Path(source).stem
334
+ for tp in test_projects:
335
+ tp_dir = (Path(repo_root) / tp).parent
336
+ if not tp_dir.exists():
337
+ continue
338
+ for suffix in _TEST_FILE_SUFFIXES:
339
+ for hit in sorted(tp_dir.rglob(f"{stem}{suffix}")):
340
+ return hit
341
+ return None
342
+
343
+
344
+ def build_loop_command(
345
+ *,
346
+ config: Path,
347
+ source_file: str,
348
+ source_path: str,
349
+ test_file: Path,
350
+ report: Path,
351
+ model: str | None,
352
+ max_rounds: int,
353
+ stryker_bin: str = "dotnet",
354
+ ) -> list[str]:
355
+ """Build the ``mutation_kill_loop`` invocation. ``--headless`` is forced —
356
+ the pipeline is unattended and can never depend on a live agent turn.
357
+
358
+ ``stryker_bin`` is forwarded explicitly so an override on the pipeline's
359
+ own ``--stryker-bin`` (e.g. targeting a global install) reaches this
360
+ per-file survivor-fix subprocess too, rather than that subprocess
361
+ silently falling back to its own independent default.
362
+ """
363
+ cmd = [
364
+ PYTHON,
365
+ LOOP_SCRIPT,
366
+ "--headless",
367
+ "--config",
368
+ str(config),
369
+ "--file",
370
+ source_file,
371
+ "--source-path",
372
+ str(source_path),
373
+ "--test-file",
374
+ str(test_file),
375
+ "--report",
376
+ str(report),
377
+ "--max-rounds",
378
+ str(max_rounds),
379
+ "--stryker-bin",
380
+ stryker_bin,
381
+ ]
382
+ if model:
383
+ cmd += ["--model", model]
384
+ return cmd
385
+
386
+
387
+ def launch_survivor_fix(
388
+ shard: str,
389
+ *,
390
+ repo_root: Path,
391
+ out_dir: Path,
392
+ config_path: Path,
393
+ model: str | None,
394
+ max_rounds: int,
395
+ stryker_bin: str = "dotnet",
396
+ run: Callable[..., subprocess.CompletedProcess] = subprocess.run,
397
+ resolve_test_file: TestFileResolver | None = None,
398
+ log: Callable[[str], None] = print,
399
+ ) -> FixOutcome:
400
+ """Launch the forced-headless survivor-fix loop for a shard's survivors.
401
+
402
+ Invokes ``mutation_kill_loop`` (always with ``--headless``) once per source
403
+ file that still has survivors, seeding round 1 from the shard's report.
404
+ Runs from ``repo_root`` so fixes commit onto ``HEAD`` — that is what makes
405
+ the *next* shard's worktree compounding.
406
+
407
+ Returns a :class:`FixOutcome`. ``ok`` is True when every launched fix
408
+ exited zero or the dedicated GenerationExhausted exit code 5 (or none
409
+ were launched); False the moment one exits any other non-zero code. The
410
+ implementation does not distinguish the fatal-revert exit code 4
411
+ (``mutation_kill_headless``/``mutation_kill_loop_python`` #1598) from any
412
+ other non-zero, non-5 code — every such exit is treated identically as a
413
+ failed revert, which means the working tree may be in an
414
+ unknown/possibly-mutated state, so processing stops for the remaining
415
+ files in this shard rather than silently continuing onto a tree that may
416
+ already be broken. Exit code 4 is ``RevertFailed`` specifically — a
417
+ failed revert. Exit code 5 covers two distinct outcomes that both map to
418
+ the same code: true GenerationExhausted (a fully spent
419
+ retry-then-downgrade budget) and any other clean RuntimeError (e.g. a
420
+ generation timeout, or a mutmut/Stryker infrastructure failure — not
421
+ exhaustion). Both are carved out from the fatal case: this file is
422
+ logged as unfixed and the loop continues to the next file in the shard
423
+ (the tree was not mutated), matching ``mutation-kill.md``'s documented
424
+ exhaustion contract that ```--all` continues``` (#1908 review) — but the
425
+ pipeline's overall exit code becomes ``EXIT_GENERATION_EXHAUSTED`` (5) at
426
+ the end if any file across any shard hit either outcome, unless a hard
427
+ failure elsewhere makes it 1 (``main()``'s 3-branch priority: failed >
428
+ exhausted/unresolved/no_report > clean).
429
+
430
+ Two more outcomes, previously silently swallowed as a bare ``True`` (#1951):
431
+ a survivor whose test file never resolves (``FixOutcome.unresolved``, one
432
+ entry per such survivor — logged ``Agent SKIP: no test file resolved`` but
433
+ the loop continues, since other survivors in the shard may still resolve)
434
+ and a shard with no Stryker report at all (``FixOutcome.no_report``) —
435
+ both now propagate to the run-level result instead of reading identically
436
+ to a fully clean run with zero fix attempts made.
437
+ """
438
+ resolve_test_file = resolve_test_file or default_resolve_test_file
439
+ report = report_path(out_dir)
440
+ if not report.exists():
441
+ log(f"[{ts()}] Agent SKIP: no report for {_safe(shard)}")
442
+ return FixOutcome(ok=True, exhausted=[], unresolved=[], no_report=True)
443
+ files = survivor_source_files(report)
444
+ if not files:
445
+ log(f"[{ts()}] Agent SKIP: no survivors in {_safe(shard)}")
446
+ return FixOutcome(ok=True, exhausted=[], unresolved=[], no_report=False)
447
+
448
+ exhausted: list[str] = []
449
+ unresolved: list[str] = []
450
+ test_projects = shard_test_projects(config_path)
451
+ for source in files:
452
+ test_file = resolve_test_file(source, test_projects, repo_root)
453
+ if test_file is None:
454
+ log(f"[{ts()}] Agent SKIP: no test file resolved for {_safe(source)}")
455
+ unresolved.append(f"{_safe(shard)}/{_safe(source)}")
456
+ continue
457
+ cmd = build_loop_command(
458
+ config=config_path,
459
+ source_file=Path(source).name,
460
+ source_path=source,
461
+ test_file=test_file,
462
+ report=report,
463
+ model=model,
464
+ max_rounds=max_rounds,
465
+ stryker_bin=stryker_bin,
466
+ )
467
+ log(f"[{ts()}] Agent START (headless): {_safe(shard)} — {_safe(source)}")
468
+ result = run(cmd, cwd=str(repo_root))
469
+ rc = result.returncode
470
+ if rc == EXIT_GENERATION_EXHAUSTED:
471
+ log(
472
+ f"[{ts()}] Agent UNFIXED (headless, clean): {_safe(shard)} — "
473
+ f"{_safe(source)} (exit {rc}) — retry budget spent OR a "
474
+ "clean generation/infrastructure failure (#1956: exit 5 "
475
+ "covers both since #1939, so this line names the OUTCOME, "
476
+ "not a specific cause); logging this file as unfixed and "
477
+ "continuing to the next file in this shard (the tree was "
478
+ "not mutated) — the pipeline's overall exit code becomes "
479
+ "EXIT_GENERATION_EXHAUSTED (5) at the end unless a hard "
480
+ "failure elsewhere makes it 1"
481
+ )
482
+ exhausted.append(f"{_safe(shard)}/{_safe(source)}")
483
+ continue
484
+ if rc != 0:
485
+ log(
486
+ f"[{ts()}] Agent FAILED (headless): {_safe(shard)} — "
487
+ f"{_safe(source)} (exit {rc}) — stopping further files in "
488
+ "this shard; the working tree may be left in an "
489
+ "unknown/possibly-mutated state (this treats every "
490
+ "non-4-non-5 exit the same as a failed revert — see #1930)"
491
+ )
492
+ return FixOutcome(
493
+ ok=False, exhausted=exhausted, unresolved=unresolved, no_report=False
494
+ )
495
+ return FixOutcome(ok=True, exhausted=exhausted, unresolved=unresolved, no_report=False)
496
+
497
+
498
+ # ── Resume (skip-existing wins over max-age) ────────────────────────────────────
499
+
500
+
501
+ def report_age_seconds(out_dir: Path) -> float | None:
502
+ rp = report_path(out_dir)
503
+ if not rp.exists():
504
+ return None
505
+ return time.time() - rp.stat().st_mtime
506
+
507
+
508
+ def should_skip(
509
+ out_dir: Path,
510
+ *,
511
+ skip_existing: bool,
512
+ max_age_hours: float,
513
+ shard: str,
514
+ log: Callable[[str], None] = print,
515
+ ) -> bool:
516
+ """Resume gate. ``--skip-existing`` is evaluated **first**, so it wins over
517
+ ``--max-age-hours``: any existing report is skipped regardless of its age.
518
+ ``--max-age-hours`` only applies when ``--skip-existing`` is not set.
519
+ """
520
+ age = report_age_seconds(out_dir)
521
+ if age is None:
522
+ return False
523
+ if skip_existing:
524
+ log(f"[{ts()}] SKIPPED ({shard}): --skip-existing wins over --max-age-hours")
525
+ return True
526
+ if max_age_hours > 0 and age < max_age_hours * 3600:
527
+ log(
528
+ f"[{ts()}] SKIPPED ({shard}): report {int(age / 60)}m old "
529
+ f"< --max-age-hours {max_age_hours}"
530
+ )
531
+ return True
532
+ return False
533
+
534
+
535
+ # ── Summary (honest score) ──────────────────────────────────────────────────────
536
+
537
+
538
+ def print_summary(
539
+ shards: Sequence[str],
540
+ shard_out_base: Path,
541
+ *,
542
+ log: Callable[[str], None] = print,
543
+ exhausted: Sequence[str] = (),
544
+ unresolved: Sequence[str] = (),
545
+ no_report: Sequence[str] = (),
546
+ skipped: Sequence[str] = (),
547
+ ) -> None:
548
+ """Print the per-shard honest score with Timeout and NoCoverage broken out
549
+ separately — never the timeout-inflated reported score (AC3).
550
+
551
+ Four run-level outcome lines are appended when non-empty — each a case
552
+ that previously read identically to a fully clean run (#1951):
553
+
554
+ - ``EXHAUSTED files (N)`` — ``shard/source`` entries that hit
555
+ ``EXIT_GENERATION_EXHAUSTED`` (5): either true GenerationExhausted (a
556
+ fully spent retry-then-downgrade budget) or any other clean
557
+ ``RuntimeError`` (e.g. a generation timeout, or a mutmut/Stryker
558
+ infrastructure failure — not exhaustion); see ``launch_survivor_fix``.
559
+ - ``UNRESOLVED test file (N)`` — ``shard/source`` entries where
560
+ ``resolve_test_file`` never found a conventional pairing.
561
+ - ``NO REPORT shards (N)`` — shards Stryker produced no report for.
562
+ - ``SKIPPED shards (N)`` — shards resumed past via ``--skip-existing``/
563
+ ``--max-age-hours``; informational only, never affects the exit code.
564
+ """
565
+ log("=== Pipeline summary ===")
566
+ for shard in shards:
567
+ rp = report_path(Path(shard_out_base) / shard)
568
+ if not rp.exists():
569
+ log(f" {shard}: no report")
570
+ continue
571
+ s = mutation_report.score_report(rp)
572
+ log(
573
+ f" {shard}: honest={s.honest_score:.1f}% "
574
+ f"killed={s.killed} survived={s.survived} "
575
+ f"timeout={s.timeout} nocoverage={s.no_coverage}"
576
+ )
577
+ if skipped:
578
+ log(f"\nSKIPPED shards ({len(skipped)}): " + ", ".join(skipped))
579
+ if no_report:
580
+ log(f"\nNO REPORT shards ({len(no_report)}): " + ", ".join(no_report))
581
+ if unresolved:
582
+ log(f"\nUNRESOLVED test file ({len(unresolved)}): " + ", ".join(unresolved))
583
+ if exhausted:
584
+ log(f"\nEXHAUSTED files ({len(exhausted)}): " + ", ".join(exhausted))
585
+
586
+
587
+ # ── Orchestration ───────────────────────────────────────────────────────────────
588
+
589
+
590
+ def process_shard(
591
+ shard: str,
592
+ *,
593
+ repo_root: Path,
594
+ worktree_base: Path,
595
+ shard_out_base: Path,
596
+ stryker_bin: str,
597
+ model: str | None,
598
+ max_rounds: int,
599
+ skip_agent: bool,
600
+ skip_existing: bool,
601
+ max_age_hours: float,
602
+ log: Callable[[str], None] = print,
603
+ run_stryker: StrykerRunner | None = None,
604
+ run: Callable[..., object] = subprocess.run,
605
+ resolve_test_file: TestFileResolver | None = None,
606
+ git_run: GitRunner | None = None,
607
+ events: list[tuple] | None = None,
608
+ ) -> ShardOutcome:
609
+ """Process one shard end to end. Returns a :class:`ShardOutcome` whose
610
+ ``status`` is ``"ok"`` / ``"failed"`` / ``"skipped"``, with
611
+ ``launch_survivor_fix``'s :class:`FixOutcome` fields propagated up
612
+ unchanged for shards that reach the survivor-fix stage. ``events`` (when
613
+ supplied) records the worktree-creation and fix-launch ordering so tests
614
+ can assert compounding sequencing."""
615
+ out_dir = Path(shard_out_base) / shard
616
+ if should_skip(
617
+ out_dir,
618
+ skip_existing=skip_existing,
619
+ max_age_hours=max_age_hours,
620
+ shard=shard,
621
+ log=log,
622
+ ):
623
+ return ShardOutcome("skipped", [], [], False)
624
+
625
+ wt = Path(worktree_base) / f"shard-{shard}"
626
+ worktree_add(repo_root, wt, git_run=git_run)
627
+ if events is not None:
628
+ events.append(("worktree_add", shard))
629
+ log(f"[{ts()}] Shard START: {shard}")
630
+ try:
631
+ ok = run_shard_stryker(
632
+ shard,
633
+ repo_root=repo_root,
634
+ worktree=wt,
635
+ out_dir=out_dir,
636
+ stryker_bin=stryker_bin,
637
+ log=log,
638
+ run_stryker=run_stryker,
639
+ )
640
+ finally:
641
+ worktree_remove(repo_root, wt, git_run=git_run)
642
+
643
+ if not ok:
644
+ return ShardOutcome("failed", [], [], False)
645
+ log(f"[{ts()}] Shard DONE: {shard}")
646
+
647
+ if not skip_agent:
648
+ fix = launch_survivor_fix(
649
+ shard,
650
+ repo_root=repo_root,
651
+ out_dir=out_dir,
652
+ config_path=shard_config_path(repo_root, shard),
653
+ model=model,
654
+ max_rounds=max_rounds,
655
+ stryker_bin=stryker_bin,
656
+ run=run,
657
+ resolve_test_file=resolve_test_file,
658
+ log=log,
659
+ )
660
+ if events is not None:
661
+ events.append(("fix", shard))
662
+ status = "ok" if fix.ok else "failed"
663
+ return ShardOutcome(status, fix.exhausted, fix.unresolved, fix.no_report)
664
+ return ShardOutcome("ok", [], [], False)
665
+
666
+
667
+ def run_all(
668
+ shards: Sequence[str],
669
+ *,
670
+ repo_root: Path,
671
+ worktree_base: Path,
672
+ shard_out_base: Path,
673
+ stryker_bin: str,
674
+ model: str | None,
675
+ max_rounds: int,
676
+ skip_agent: bool,
677
+ skip_existing: bool,
678
+ max_age_hours: float,
679
+ log: Callable[[str], None] = print,
680
+ run_stryker: StrykerRunner | None = None,
681
+ run: Callable[..., object] = subprocess.run,
682
+ resolve_test_file: TestFileResolver | None = None,
683
+ git_run: GitRunner | None = None,
684
+ events: list[tuple] | None = None,
685
+ ) -> ShardRunResult:
686
+ """Process every shard **sequentially** (compounding depends on ordering).
687
+ Returns a :class:`ShardRunResult` collecting, across all shards: failed
688
+ shards, exhausted/unresolved source files, no-report shards, and
689
+ skipped shards (#1951)."""
690
+ failed: list[str] = []
691
+ exhausted: list[str] = []
692
+ unresolved: list[str] = []
693
+ no_report: list[str] = []
694
+ skipped: list[str] = []
695
+ for shard in shards:
696
+ outcome = process_shard(
697
+ shard,
698
+ repo_root=repo_root,
699
+ worktree_base=worktree_base,
700
+ shard_out_base=shard_out_base,
701
+ stryker_bin=stryker_bin,
702
+ model=model,
703
+ max_rounds=max_rounds,
704
+ skip_agent=skip_agent,
705
+ skip_existing=skip_existing,
706
+ max_age_hours=max_age_hours,
707
+ log=log,
708
+ run_stryker=run_stryker,
709
+ run=run,
710
+ resolve_test_file=resolve_test_file,
711
+ git_run=git_run,
712
+ events=events,
713
+ )
714
+ if outcome.status == "failed":
715
+ failed.append(shard)
716
+ elif outcome.status == "skipped":
717
+ skipped.append(shard)
718
+ exhausted.extend(outcome.exhausted)
719
+ unresolved.extend(outcome.unresolved)
720
+ if outcome.no_report:
721
+ no_report.append(shard)
722
+ return ShardRunResult(failed, exhausted, unresolved, no_report, skipped)
723
+
724
+
725
+ def build_parser() -> argparse.ArgumentParser:
726
+ parser = argparse.ArgumentParser(
727
+ prog="stryker_shard_pipeline.py",
728
+ description="Sharded Stryker pipeline with compounding worktrees and timeout-abort",
729
+ formatter_class=argparse.RawDescriptionHelpFormatter,
730
+ )
731
+ parser.add_argument(
732
+ "shards", nargs="*", default=[], help="Shards to run (default: all discovered)"
733
+ )
734
+ parser.add_argument("--repo-root", help="Repo root (default: cwd)")
735
+ parser.add_argument(
736
+ "--stryker-bin",
737
+ default=os.environ.get("STRYKER_BIN", "dotnet"),
738
+ help="Stryker executable name, or 'dotnet' to invoke a local-tool-"
739
+ "manifest install via 'dotnet stryker' (default: %(default)s)",
740
+ )
741
+ parser.add_argument(
742
+ "--model",
743
+ help="Generation model for the forced-headless survivor-fix loop.",
744
+ )
745
+ parser.add_argument(
746
+ "--max-rounds", type=int, default=3, help="Survivor-fix rounds per file (default: 3)"
747
+ )
748
+ parser.add_argument(
749
+ "--skip-agent", action="store_true", help="Run shards only; skip survivor-fix"
750
+ )
751
+ parser.add_argument(
752
+ "--skip-existing",
753
+ action="store_true",
754
+ help="Skip shards with an existing report, any age (wins over --max-age-hours)",
755
+ )
756
+ parser.add_argument(
757
+ "--max-age-hours",
758
+ type=float,
759
+ default=0,
760
+ help="Skip shards whose report is younger than N hours (ignored under --skip-existing)",
761
+ )
762
+ return parser
763
+
764
+
765
+ def main(argv: Sequence[str] | None = None) -> int:
766
+ """CLI entry point. Exit code follows a 3-branch priority, failure first:
767
+
768
+ - ``1`` — one or more shards failed (``run_all``'s ``failed`` list is
769
+ non-empty). Takes priority over exhaustion. A shard is marked failed
770
+ when ``launch_survivor_fix`` returns a :class:`FixOutcome` with
771
+ ``ok=False`` — which happens on any non-zero, non-5 per-file exit code
772
+ (most commonly ``EXIT_REVERT_FAILED``, ``4``); this branch is where
773
+ that per-file signal ends up, since ``main()`` never returns ``4``
774
+ itself.
775
+ - ``EXIT_GENERATION_EXHAUSTED`` (``5``) — no shard failed, but at least
776
+ one of three "a survivor was not addressed this run" outcomes fired
777
+ (#1951): ``exhausted`` is non-empty (a true ``GenerationExhausted`` — a
778
+ fully spent retry-then-downgrade budget — or any other clean
779
+ ``RuntimeError`` such as a generation timeout), ``unresolved`` is
780
+ non-empty (a survivor whose test file never resolved), or
781
+ ``no_report`` is non-empty (a shard Stryker produced no report for).
782
+ All three previously read identically to a fully clean run; only
783
+ ``exhausted`` got run-level visibility before this fix.
784
+ - ``0`` — fully clean: no failures, no exhaustions, no unresolved test
785
+ files, no missing reports. (``skipped`` shards — resumed past via
786
+ ``--skip-existing``/``--max-age-hours`` — are reported in the summary
787
+ but never affect the exit code; see ``print_summary``.)
788
+ """
789
+ args = build_parser().parse_args(list(sys.argv[1:] if argv is None else argv))
790
+ repo_root = Path(args.repo_root).resolve() if args.repo_root else Path.cwd()
791
+
792
+ try:
793
+ all_shards = discover_shards(repo_root)
794
+ except ShardSetupMissing as exc:
795
+ sys.stderr.write(f"error: {exc}\n")
796
+ return 1
797
+ shards = list(args.shards) if args.shards else all_shards
798
+
799
+ worktree_base = repo_root / ".stryker-worktrees"
800
+ shard_out_base = repo_root / "StrykerOutput" / "shards"
801
+ worktree_base.mkdir(parents=True, exist_ok=True)
802
+ shard_out_base.mkdir(parents=True, exist_ok=True)
803
+
804
+ # DOTNET_ROOT resolution is delegated to the wrapper (AC4) and exported so
805
+ # every shard's Stryker subprocess inherits it.
806
+ dotnet_root, err = wrapper.resolve_dotnet_root(
807
+ preset=os.environ.get("DOTNET_ROOT"),
808
+ candidates=wrapper.default_probe_candidates(),
809
+ )
810
+ if err is not None:
811
+ sys.stderr.write(err)
812
+ return wrapper.EXIT_NO_DOTNET_SDK
813
+ assert dotnet_root is not None
814
+ os.environ["DOTNET_ROOT"] = dotnet_root
815
+
816
+ print(f"Pipeline: {' '.join(shards)}")
817
+ result = run_all(
818
+ shards,
819
+ repo_root=repo_root,
820
+ worktree_base=worktree_base,
821
+ shard_out_base=shard_out_base,
822
+ stryker_bin=args.stryker_bin,
823
+ model=args.model,
824
+ max_rounds=args.max_rounds,
825
+ skip_agent=args.skip_agent,
826
+ skip_existing=args.skip_existing,
827
+ max_age_hours=args.max_age_hours,
828
+ )
829
+
830
+ print_summary(
831
+ shards,
832
+ shard_out_base,
833
+ exhausted=result.exhausted,
834
+ unresolved=result.unresolved,
835
+ no_report=result.no_report,
836
+ skipped=result.skipped,
837
+ )
838
+ if result.failed:
839
+ print(f"\nFAILED shards: {' '.join(result.failed)}")
840
+ return 1
841
+ if result.exhausted or result.unresolved or result.no_report:
842
+ return EXIT_GENERATION_EXHAUSTED
843
+ return 0
844
+
845
+
846
+ if __name__ == "__main__":
847
+ sys.exit(main())