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.
- package/LICENSE +21 -0
- package/PORTING.md +134 -0
- package/README.md +207 -0
- package/UPSTREAM.json +64 -0
- package/agents/Explore.md +15 -0
- package/agents/a11y-review.md +118 -0
- package/agents/adr-author.md +70 -0
- package/agents/ai-provenance-review.md +120 -0
- package/agents/angular-reactivity-review.md +95 -0
- package/agents/arch-review.md +135 -0
- package/agents/architect.md +78 -0
- package/agents/autoship-batch-proposer.md +69 -0
- package/agents/claude-setup-review.md +136 -0
- package/agents/codebase-recon.md +184 -0
- package/agents/component-architecture-review.md +119 -0
- package/agents/concurrency-review.md +109 -0
- package/agents/correctness-review.md +290 -0
- package/agents/data-flow-tracer.md +120 -0
- package/agents/doc-review.md +165 -0
- package/agents/domain-review.md +136 -0
- package/agents/general-purpose.md +10 -0
- package/agents/gherkin-quality-critic.md +113 -0
- package/agents/js-fp-review.md +114 -0
- package/agents/mutation-kill.md +684 -0
- package/agents/naming-review.md +142 -0
- package/agents/orchestrator.md +339 -0
- package/agents/performance-review.md +105 -0
- package/agents/plan-review-acceptance.md +115 -0
- package/agents/plan-review-design.md +90 -0
- package/agents/plan-review-parallelization.md +84 -0
- package/agents/plan-review-strategic.md +96 -0
- package/agents/plan-review-ux.md +110 -0
- package/agents/platform-engineer.md +64 -0
- package/agents/product-manager.md +68 -0
- package/agents/progress-guardian.md +79 -0
- package/agents/qa-engineer.md +289 -0
- package/agents/quality-reviewer.md +132 -0
- package/agents/react-reactivity-review.md +102 -0
- package/agents/refactor-opportunity-review.md +128 -0
- package/agents/security-engineer.md +60 -0
- package/agents/security-review.md +218 -0
- package/agents/session-analysis.md +95 -0
- package/agents/software-engineer.md +105 -0
- package/agents/spec-compliance-review.md +100 -0
- package/agents/spec-reviewer.md +114 -0
- package/agents/structure-review.md +146 -0
- package/agents/tech-writer.md +84 -0
- package/agents/test-review.md +246 -0
- package/agents/test-smell-review.md +188 -0
- package/agents/token-efficiency-review.md +139 -0
- package/agents/ui-ux-designer.md +54 -0
- package/agents/vue-reactivity-review.md +95 -0
- package/bin/__pycache__/claudecpython-314.pyc +0 -0
- package/bin/claude +258 -0
- package/docs/upstream/.pages +1 -0
- package/docs/upstream/CHANGELOG.md +2586 -0
- package/docs/upstream/README.md +155 -0
- package/docs/upstream/agent-architecture.md +214 -0
- package/docs/upstream/agent_info.md +187 -0
- package/docs/upstream/artifact-migration.md +124 -0
- package/docs/upstream/code-intelligence-nudge.md +149 -0
- package/docs/upstream/code-review-process.md +294 -0
- package/docs/upstream/concurrent-use.md +73 -0
- package/docs/upstream/context-management.md +111 -0
- package/docs/upstream/developer-notes.md +280 -0
- package/docs/upstream/diagrams/architecture-overview.svg +101 -0
- package/docs/upstream/diagrams/review-dispatch.svg +139 -0
- package/docs/upstream/diagrams/team-agents.svg +128 -0
- package/docs/upstream/diagrams/test-improve-flow.svg +166 -0
- package/docs/upstream/diagrams/workflow-linear.svg +66 -0
- package/docs/upstream/diagrams/workflow-three-phase.svg +200 -0
- package/docs/upstream/eval-maintenance.md +95 -0
- package/docs/upstream/eval-running-guide.md +147 -0
- package/docs/upstream/eval-system.md +291 -0
- package/docs/upstream/session-review-oss-complements.md +75 -0
- package/docs/upstream/session-review.md +212 -0
- package/docs/upstream/skills.md +188 -0
- package/docs/upstream/team-structure.md +21 -0
- package/docs/upstream/telemetry-ci-access.md +129 -0
- package/docs/upstream/telemetry-repo-security.md +120 -0
- package/docs/upstream/test-evaluation.md +277 -0
- package/docs/upstream/test-improve.md +154 -0
- package/docs/upstream/triage-workflow.md +282 -0
- package/docs/upstream/workflows.md +289 -0
- package/extensions/dev-team/index.ts +539 -0
- package/extensions/dev-team/lib/agents.ts +272 -0
- package/extensions/dev-team/lib/ai-credits.ts +92 -0
- package/extensions/dev-team/lib/autocompact.ts +81 -0
- package/extensions/dev-team/lib/child-run.ts +102 -0
- package/extensions/dev-team/lib/config.ts +236 -0
- package/extensions/dev-team/lib/gh-command.ts +103 -0
- package/extensions/dev-team/lib/github-style.ts +307 -0
- package/extensions/dev-team/lib/hooks.ts +350 -0
- package/extensions/dev-team/lib/metrics.ts +115 -0
- package/extensions/dev-team/lib/safe-read.ts +49 -0
- package/extensions/dev-team/lib/session-files.ts +57 -0
- package/extensions/dev-team/lib/session-spend.ts +123 -0
- package/extensions/dev-team/lib/shell-scan.ts +205 -0
- package/extensions/dev-team/lib/skills.ts +213 -0
- package/extensions/dev-team/lib/subagent-render.ts +245 -0
- package/extensions/dev-team/lib/subagent-types.ts +164 -0
- package/extensions/dev-team/lib/subagent.ts +596 -0
- package/extensions/dev-team/lib/terminal-text.ts +54 -0
- package/extensions/dev-team/lib/tools-misc.ts +152 -0
- package/extensions/dev-team/lib/transcript.ts +110 -0
- package/extensions/dev-team/lib/trust.ts +52 -0
- package/extensions/dev-team/lib/usage-breakdown.ts +176 -0
- package/extensions/dev-team/lib/usage-chart.ts +153 -0
- package/extensions/dev-team/lib/usage-command.ts +107 -0
- package/extensions/dev-team/lib/usage-history.ts +203 -0
- package/extensions/dev-team/lib/usage-render.ts +225 -0
- package/extensions/dev-team/lib/usage-split-bar.ts +127 -0
- package/extensions/dev-team/lib/usage-state.ts +116 -0
- package/extensions/dev-team/lib/usage-text.ts +159 -0
- package/extensions/dev-team/lib/usage-view.ts +109 -0
- package/hooks/__pycache__/refactor_test_freeze_guard.cpython-314.pyc +0 -0
- package/hooks/agent_dispatch_ledger.py +190 -0
- package/hooks/autocompact_setup_nudge.py +99 -0
- package/hooks/bash_retry_guard.py +228 -0
- package/hooks/boundary_events_write_guard.py +352 -0
- package/hooks/code_intelligence_nudge.py +293 -0
- package/hooks/code_intelligence_turn_mark.py +317 -0
- package/hooks/codegraph_bootstrap.py +139 -0
- package/hooks/contract_version_guard.py +362 -0
- package/hooks/cost_meter.py +106 -0
- package/hooks/destructive-commands.json +62 -0
- package/hooks/destructive_guard.py +477 -0
- package/hooks/eval_compliance_check.py +440 -0
- package/hooks/guards.json +17 -0
- package/hooks/hooks.json +323 -0
- package/hooks/internal_double_gate.py +296 -0
- package/hooks/js_fp_review.py +212 -0
- package/hooks/knowledge_index.py +119 -0
- package/hooks/lib/__pycache__/artifact_paths.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/atomic_state.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/autocompact_config.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/boundary_events.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/doc_classification.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/gh_pr_create_detect.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/git_safe_diff.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/instrument_log.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/metrics_query.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/plugin_version.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/pre_commit_doc_classifier.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/review_agent_registry.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/review_gate_corroboration.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/review_gate_hash.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/review_verdicts.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/stdin_json.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/stryker_invocation.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/telemetry_consent.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/test_file_classify.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/token_efficiency_limits.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/verify_guard_state.cpython-314.pyc +0 -0
- package/hooks/lib/__pycache__/xunit_v3_operator_gate.cpython-314.pyc +0 -0
- package/hooks/lib/agent_skill_hints.py +74 -0
- package/hooks/lib/artifact_paths.py +263 -0
- package/hooks/lib/atomic_state.py +557 -0
- package/hooks/lib/autocompact_config.py +103 -0
- package/hooks/lib/autoship_log.py +106 -0
- package/hooks/lib/banned_scripts_policy.py +51 -0
- package/hooks/lib/boundary_events.py +436 -0
- package/hooks/lib/build_knowledge_index.py +504 -0
- package/hooks/lib/build_skills_index.py +361 -0
- package/hooks/lib/build_state.py +116 -0
- package/hooks/lib/classify_ship_outcome.py +126 -0
- package/hooks/lib/config_changelog_schema.py +115 -0
- package/hooks/lib/cost_meter.py +955 -0
- package/hooks/lib/doc_classification.py +116 -0
- package/hooks/lib/gh_pr_create_detect.py +136 -0
- package/hooks/lib/git_safe_diff.py +123 -0
- package/hooks/lib/instrument_log.py +66 -0
- package/hooks/lib/iteration_journal_gate.py +197 -0
- package/hooks/lib/knowledge_index_paths.py +88 -0
- package/hooks/lib/mcp_json_repowise.py +177 -0
- package/hooks/lib/metrics_query.py +202 -0
- package/hooks/lib/minimal_yaml.py +434 -0
- package/hooks/lib/plugin_version.py +142 -0
- package/hooks/lib/pre_commit_detect.py +537 -0
- package/hooks/lib/pre_commit_doc_classifier.py +126 -0
- package/hooks/lib/pricing.py +118 -0
- package/hooks/lib/report_pdf.py +371 -0
- package/hooks/lib/review_agent_registry.py +142 -0
- package/hooks/lib/review_dispatch_ledger.py +101 -0
- package/hooks/lib/review_gate_corroboration.py +521 -0
- package/hooks/lib/review_gate_hash.py +252 -0
- package/hooks/lib/review_gate_normalized_hash.py +1115 -0
- package/hooks/lib/review_verdicts.py +301 -0
- package/hooks/lib/run_report.py +160 -0
- package/hooks/lib/skill_categories.yaml +125 -0
- package/hooks/lib/stdin_json.py +57 -0
- package/hooks/lib/stryker_invocation.py +102 -0
- package/hooks/lib/telemetry_consent.py +41 -0
- package/hooks/lib/telemetry_report.py +108 -0
- package/hooks/lib/test_file_classify.py +160 -0
- package/hooks/lib/token_efficiency_limits.py +51 -0
- package/hooks/lib/turn_identity.py +77 -0
- package/hooks/lib/verify_guard_state.py +110 -0
- package/hooks/lib/workflow_state.py +206 -0
- package/hooks/lib/xunit_v3_operator_gate.py +596 -0
- package/hooks/mcp_json_repowise_nudge.py +74 -0
- package/hooks/mutation_adapters/__init__.py +7 -0
- package/hooks/mutation_adapters/__pycache__/__init__.cpython-314.pyc +0 -0
- package/hooks/mutation_adapters/__pycache__/lib.cpython-314.pyc +0 -0
- package/hooks/mutation_adapters/__pycache__/mutmut.cpython-314.pyc +0 -0
- package/hooks/mutation_adapters/__pycache__/pitest.cpython-314.pyc +0 -0
- package/hooks/mutation_adapters/__pycache__/stryker.cpython-314.pyc +0 -0
- package/hooks/mutation_adapters/__pycache__/stryker_net.cpython-314.pyc +0 -0
- package/hooks/mutation_adapters/lib.py +478 -0
- package/hooks/mutation_adapters/mutmut.py +188 -0
- package/hooks/mutation_adapters/pitest.py +266 -0
- package/hooks/mutation_adapters/stryker.py +157 -0
- package/hooks/mutation_adapters/stryker_net.py +264 -0
- package/hooks/mutation_gate.py +193 -0
- package/hooks/mutation_testing_smoke_gate.py +371 -0
- package/hooks/pending_review_notify.py +121 -0
- package/hooks/phase_marker.py +138 -0
- package/hooks/post_compact_state_reinject.py +180 -0
- package/hooks/post_format.py +115 -0
- package/hooks/pre_commit_knowledge_index.py +128 -0
- package/hooks/pre_commit_review.py +66 -0
- package/hooks/pre_pr_review.py +694 -0
- package/hooks/pre_tool_guard.py +405 -0
- package/hooks/py.sh +73 -0
- package/hooks/refactor-bash-write-patterns.json +29 -0
- package/hooks/refactor_test_bash_guard.py +253 -0
- package/hooks/refactor_test_freeze_guard.py +139 -0
- package/hooks/refactor_test_revert_guard.py +186 -0
- package/hooks/repo_review_nudge.py +287 -0
- package/hooks/review_verdict_recorder.py +464 -0
- package/hooks/scan_bash_command_for_banned_scripts.py +428 -0
- package/hooks/scan_worktree_for_banned_scripts.py +238 -0
- package/hooks/session_learning_trigger.py +248 -0
- package/hooks/skills_index.py +126 -0
- package/hooks/stryker_xunit_shim_guard.py +571 -0
- package/hooks/subagent_completion_guard.py +309 -0
- package/hooks/subagent_skill_context.py +139 -0
- package/hooks/task_completion_metrics.py +216 -0
- package/hooks/tdd_guard.py +229 -0
- package/hooks/telemetry.py +341 -0
- package/hooks/token_efficiency_review.py +194 -0
- package/hooks/verify_guard.py +183 -0
- package/hooks/verify_guard_edit_marker.py +73 -0
- package/hooks/version_check.py +173 -0
- package/knowledge/accepted-risks-schema.md +98 -0
- package/knowledge/adr-decision-criteria.md +64 -0
- package/knowledge/adversarial-review-protocol.md +139 -0
- package/knowledge/agent-registry.md +228 -0
- package/knowledge/agent-review-methodology.md +80 -0
- package/knowledge/ai-friendly-repo-guidelines.md +67 -0
- package/knowledge/architecture-assessment.md +96 -0
- package/knowledge/artifact-lifecycle.md +57 -0
- package/knowledge/cd-maturity-model.md +82 -0
- package/knowledge/cd-test-architecture.md +190 -0
- package/knowledge/ci-cd-file-scope.md +24 -0
- package/knowledge/codegraph-vs-graphify.md +192 -0
- package/knowledge/component-test-patterns.md +139 -0
- package/knowledge/database-change-management.md +80 -0
- package/knowledge/database-test-patterns.md +79 -0
- package/knowledge/decision-defaults.md +88 -0
- package/knowledge/dependency-breaking-techniques.md +116 -0
- package/knowledge/deployment-pipeline.md +86 -0
- package/knowledge/design-smells.md +122 -0
- package/knowledge/directory-enumeration.md +38 -0
- package/knowledge/domain-modeling.md +123 -0
- package/knowledge/evidence-bundle.md +90 -0
- package/knowledge/exploratory-testing-field-guide.md +122 -0
- package/knowledge/failure-routing.md +28 -0
- package/knowledge/fixture-construction.md +56 -0
- package/knowledge/frontend-component-architecture.md +139 -0
- package/knowledge/gherkin-quality-review-dispatch.md +135 -0
- package/knowledge/index.json +6766 -0
- package/knowledge/internal-collaborator-doubling.md +101 -0
- package/knowledge/legacy-test-strategy.md +71 -0
- package/knowledge/long-run-waiting.md +66 -0
- package/knowledge/microservice-testing.md +71 -0
- package/knowledge/model-pricing.json +23 -0
- package/knowledge/mutation-score-formulas.md +60 -0
- package/knowledge/object-calisthenics.md +147 -0
- package/knowledge/oracle-provenance.md +94 -0
- package/knowledge/orchestrator-script-implementation.md +185 -0
- package/knowledge/owasp-detection.md +148 -0
- package/knowledge/plan-review-rubric.md +56 -0
- package/knowledge/proxy-connectivity.md +62 -0
- package/knowledge/reactive-effect-patterns.md +73 -0
- package/knowledge/recon-inventory-excludes.txt +32 -0
- package/knowledge/references/bdd-value-guide.md +61 -0
- package/knowledge/references/csharp-http-client-testing.md +264 -0
- package/knowledge/release-strategies.md +74 -0
- package/knowledge/report-output-location.md +117 -0
- package/knowledge/report-pdf-integration.md +63 -0
- package/knowledge/report-print.css +129 -0
- package/knowledge/report-template.md +114 -0
- package/knowledge/report-to-pdf.md +69 -0
- package/knowledge/request-processing-flow.md +63 -0
- package/knowledge/result-verification.md +52 -0
- package/knowledge/review-agent-output-contract.md +121 -0
- package/knowledge/review-lens-classification.md +113 -0
- package/knowledge/review-rubric.md +62 -0
- package/knowledge/review-template.md +104 -0
- package/knowledge/rule-fixtures/A02.insecure-random-js/negative.js +1 -0
- package/knowledge/rule-fixtures/A02.insecure-random-js/positive.js +1 -0
- package/knowledge/rule-fixtures/A02.weak-hashing-md5/negative.py +1 -0
- package/knowledge/rule-fixtures/A02.weak-hashing-md5/positive.py +1 -0
- package/knowledge/rule-fixtures/A03.command-injection/negative.js +1 -0
- package/knowledge/rule-fixtures/A03.command-injection/positive.js +1 -0
- package/knowledge/rule-fixtures/A03.sql-injection/negative.js +1 -0
- package/knowledge/rule-fixtures/A03.sql-injection/positive.js +1 -0
- package/knowledge/rule-fixtures/A03.xss-innerhtml/negative.js +1 -0
- package/knowledge/rule-fixtures/A03.xss-innerhtml/positive.js +1 -0
- package/knowledge/rule-fixtures/A05.cors-wildcard/negative.js +1 -0
- package/knowledge/rule-fixtures/A05.cors-wildcard/positive.js +1 -0
- package/knowledge/rule-fixtures/A05.default-credentials/negative.js +1 -0
- package/knowledge/rule-fixtures/A05.default-credentials/positive.js +1 -0
- package/knowledge/rule-fixtures/A07.jwt-alg-none/negative.js +1 -0
- package/knowledge/rule-fixtures/A07.jwt-alg-none/positive.js +1 -0
- package/knowledge/rule-fixtures/A08.binary-formatter/negative.cs +1 -0
- package/knowledge/rule-fixtures/A08.binary-formatter/positive.cs +1 -0
- package/knowledge/rule-fixtures/A08.js-eval/negative.js +1 -0
- package/knowledge/rule-fixtures/A08.js-eval/positive.js +1 -0
- package/knowledge/rule-fixtures/A08.object-input-stream/negative.java +1 -0
- package/knowledge/rule-fixtures/A08.object-input-stream/positive.java +1 -0
- package/knowledge/schemas/disposition-register-v1.json +65 -0
- package/knowledge/schemas/recon-envelope-v1.json +198 -0
- package/knowledge/schemas/unified-finding-v1.json +72 -0
- package/knowledge/security-primitives-contract.md +301 -0
- package/knowledge/security-review-rule-map.yaml +107 -0
- package/knowledge/skills-registry.md +72 -0
- package/knowledge/task-size-classifier.md +103 -0
- package/knowledge/telemetry-schema.md +881 -0
- package/knowledge/test-automation-maturity.md +56 -0
- package/knowledge/test-automation-principles.md +71 -0
- package/knowledge/test-cadence-tradeoffs.md +68 -0
- package/knowledge/test-doubles.md +105 -0
- package/knowledge/test-file-indicators.md +22 -0
- package/knowledge/test-layer-gates.md +35 -0
- package/knowledge/test-matrix-examples/django-batch.md +24 -0
- package/knowledge/test-matrix-examples/dotnet-grpc-fronting-api.md +90 -0
- package/knowledge/test-matrix-examples/dotnet-http-consumer.md +131 -0
- package/knowledge/test-matrix-examples/react-node-spa.md +24 -0
- package/knowledge/test-matrix-examples/spring-boot-service.md +25 -0
- package/knowledge/test-matrix-examples/ssr-htmx.md +24 -0
- package/knowledge/test-organization.md +70 -0
- package/knowledge/test-pyramid.md +84 -0
- package/knowledge/test-refactoring.md +67 -0
- package/knowledge/test-review-division-of-labor.md +85 -0
- package/knowledge/test-smells.md +80 -0
- package/knowledge/test-stack-profiles/bdd-frameworks.md +235 -0
- package/knowledge/test-stack-profiles/django.md +13 -0
- package/knowledge/test-stack-profiles/dotnet.md +18 -0
- package/knowledge/test-stack-profiles/go.md +16 -0
- package/knowledge/test-stack-profiles/node.md +16 -0
- package/knowledge/test-stack-profiles/react.md +12 -0
- package/knowledge/test-stack-profiles/spring-boot.md +16 -0
- package/knowledge/test-stack-profiles/ssr-htmx.md +14 -0
- package/knowledge/test-stack-profiles/vue.md +12 -0
- package/knowledge/test-strategy.md +70 -0
- package/knowledge/testability-patterns.md +240 -0
- package/knowledge/testing-quadrants.md +44 -0
- package/knowledge/testing-techniques/approval.md +15 -0
- package/knowledge/testing-techniques/chaos.md +17 -0
- package/knowledge/testing-techniques/fuzz.md +15 -0
- package/knowledge/testing-techniques/property-based.md +15 -0
- package/knowledge/testing-techniques/schema-validation.md +15 -0
- package/knowledge/testing-techniques/screenshot.md +15 -0
- package/knowledge/three-phase-workflow.md +198 -0
- package/knowledge/value-patterns.md +55 -0
- package/knowledge/verification-mode.md +116 -0
- package/knowledge/virtual-service-libraries.md +75 -0
- package/knowledge/wave-consolidation-guidance.md +21 -0
- package/overrides/agents/Explore.md +15 -0
- package/overrides/agents/general-purpose.md +10 -0
- package/overrides/notes/autoship.md +6 -0
- package/overrides/notes/issues-from-assessment.md +3 -0
- package/overrides/notes/issues-from-plan.md +3 -0
- package/overrides/notes/mutation-night-watch.md +3 -0
- package/overrides/notes/mutation-testing.md +3 -0
- package/overrides/notes/pr.md +7 -0
- package/overrides/notes/project-init.md +6 -0
- package/overrides/notes/setup.md +13 -0
- package/overrides/notes/specs.md +3 -0
- package/overrides/skills/headless-run/SKILL.md +45 -0
- package/overrides/skills/upgrade/SKILL.md +30 -0
- package/overrides/skills/version/SKILL.md +25 -0
- package/package.json +36 -0
- package/scripts/authoring_digest.py +93 -0
- package/scripts/autoship_discover.py +121 -0
- package/scripts/autoship_group.py +409 -0
- package/scripts/autoship_proposals.py +494 -0
- package/scripts/autoship_queue.py +291 -0
- package/scripts/autoship_reclaim.py +495 -0
- package/scripts/build_jobs.py +108 -0
- package/scripts/build_rollback_point.py +240 -0
- package/scripts/build_slice_scope.py +157 -0
- package/scripts/build_wave.py +109 -0
- package/scripts/build_wave_reconcile.py +252 -0
- package/scripts/build_worktree_baseref.py +113 -0
- package/scripts/check_agent_scope.py +117 -0
- package/scripts/check_agent_tool_mapping.py +213 -0
- package/scripts/check_review_agent_mcp_tools.py +317 -0
- package/scripts/check_security_assessment_mcp_tools.py +165 -0
- package/scripts/checkpoint_abort.py +502 -0
- package/scripts/claude_setup_review.py +438 -0
- package/scripts/codebase_recon.py +556 -0
- package/scripts/coverage_config.py +623 -0
- package/scripts/coverage_delta_steering.py +330 -0
- package/scripts/coverage_discovery_dotnet.py +315 -0
- package/scripts/coverage_discovery_java.py +742 -0
- package/scripts/coverage_discovery_js.py +546 -0
- package/scripts/coverage_gap_ranking.py +556 -0
- package/scripts/coverage_readiness.py +455 -0
- package/scripts/coverage_report_parse.py +521 -0
- package/scripts/detect_bdd_convention.py +252 -0
- package/scripts/eval_ablation.py +376 -0
- package/scripts/gherkin_analysis_coverage_gate.py +306 -0
- package/scripts/gherkin_cross_feature_duplicate_titles_gate.py +173 -0
- package/scripts/gherkin_effectiveness_rollup.py +238 -0
- package/scripts/gherkin_failure_path_gate.py +206 -0
- package/scripts/gherkin_feature_merge.py +720 -0
- package/scripts/gherkin_stub_gate.py +163 -0
- package/scripts/gherkin_stub_merge.py +479 -0
- package/scripts/git_origin_host.py +88 -0
- package/scripts/install-java-static-analysis.py +110 -0
- package/scripts/issue_deps.py +74 -0
- package/scripts/lib/_bdd_markers.py +28 -0
- package/scripts/lib/_gherkin_text.py +93 -0
- package/scripts/lib/_vendored_tree.py +70 -0
- package/scripts/lib/autoship_state.py +397 -0
- package/scripts/lib/claude_md_guard.py +226 -0
- package/scripts/lib/deterministic_recon.py +446 -0
- package/scripts/lib/mcp_tool_grants.py +211 -0
- package/scripts/lib/plan_parse.py +386 -0
- package/scripts/lib/review_result.py +84 -0
- package/scripts/lib/review_roster.py +86 -0
- package/scripts/lib/session_log/__init__.py +34 -0
- package/scripts/lib/session_log/__pycache__/__init__.cpython-314.pyc +0 -0
- package/scripts/lib/session_log/__pycache__/records.cpython-314.pyc +0 -0
- package/scripts/lib/session_log/classify.py +231 -0
- package/scripts/lib/session_log/corrections.py +194 -0
- package/scripts/lib/session_log/discovery.py +108 -0
- package/scripts/lib/session_log/records.py +218 -0
- package/scripts/lib/session_log/redact.py +76 -0
- package/scripts/lib/session_log/signals.py +373 -0
- package/scripts/lib/session_report_downstream.py +614 -0
- package/scripts/lib/session_report_maintainer.py +1273 -0
- package/scripts/lib/session_report_shared.py +262 -0
- package/scripts/lib/settings_hook_guard.py +157 -0
- package/scripts/lib/slug.py +33 -0
- package/scripts/lib/stub_extractors/__init__.py +82 -0
- package/scripts/lib/stub_extractors/_common.py +328 -0
- package/scripts/lib/stub_extractors/csharp.py +19 -0
- package/scripts/lib/stub_extractors/go.py +173 -0
- package/scripts/lib/stub_extractors/java.py +18 -0
- package/scripts/lib/stub_extractors/jsts.py +126 -0
- package/scripts/mutation_stack_sections.py +149 -0
- package/scripts/mutation_yield_steering.py +345 -0
- package/scripts/orchestrator.py +895 -0
- package/scripts/plan_gherkin_export.py +227 -0
- package/scripts/plan_waves.py +208 -0
- package/scripts/pr_close_keyword_lint.py +108 -0
- package/scripts/progress_guardian.py +888 -0
- package/scripts/recon_inventory.py +273 -0
- package/scripts/review_findings_log.py +93 -0
- package/scripts/run_invariants.py +124 -0
- package/scripts/select_lenses.py +640 -0
- package/scripts/session_report.py +486 -0
- package/scripts/set_autocompact_env.py +221 -0
- package/scripts/ship_resume_guard.py +135 -0
- package/scripts/ship_review_gate.py +63 -0
- package/scripts/specs_convention_marker.py +103 -0
- package/scripts/test_improve_resume.py +277 -0
- package/scripts/test_review_mechanics.py +958 -0
- package/scripts/token_efficiency_review.py +322 -0
- package/scripts/verdict_scope.py +285 -0
- package/scripts/verify_gherkin_quality_critic_isolation.py +296 -0
- package/scripts/verify_tier.py +157 -0
- package/skills/adr-tools/SKILL.md +118 -0
- package/skills/agent-readiness/SKILL.md +105 -0
- package/skills/agent-readiness/ai_friendly_analyzers.py +326 -0
- package/skills/agent-readiness/scanner.py +441 -0
- package/skills/agent-readiness/scorecard.yaml +88 -0
- package/skills/api-design/SKILL.md +115 -0
- package/skills/apply-fixes/SKILL.md +171 -0
- package/skills/apply-test-doubles/SKILL.md +321 -0
- package/skills/artifact-lifecycle/SKILL.md +127 -0
- package/skills/autoship/SKILL.md +1124 -0
- package/skills/benchmark/SKILL.md +105 -0
- package/skills/branch-workflow/SKILL.md +89 -0
- package/skills/browse/SKILL.md +184 -0
- package/skills/browser-testing/SKILL.md +62 -0
- package/skills/browser-testing/references/playwright-patterns.md +216 -0
- package/skills/build/SKILL.md +422 -0
- package/skills/build/references/static-self-heal.md +245 -0
- package/skills/careful/SKILL.md +72 -0
- package/skills/cd-test-architecture/SKILL.md +371 -0
- package/skills/ci-debugging/SKILL.md +105 -0
- package/skills/co-evolution-audit/SKILL.md +269 -0
- package/skills/code-review/SKILL.md +1015 -0
- package/skills/code-review/examples/aggregated-sample.json +56 -0
- package/skills/code-review/examples/sample-report.md +41 -0
- package/skills/code-review/output-format.md +478 -0
- package/skills/code-review/scripts/activation.py +86 -0
- package/skills/code-review/scripts/change_impact.py +357 -0
- package/skills/code-review/scripts/change_shape.py +372 -0
- package/skills/code-review/scripts/change_size.py +212 -0
- package/skills/code-review/scripts/changed_file_list.py +141 -0
- package/skills/code-review/scripts/closing_pass.py +187 -0
- package/skills/code-review/scripts/consolidate.py +277 -0
- package/skills/code-review/scripts/contract_failure_report.py +185 -0
- package/skills/code-review/scripts/dispatch_reconcile.py +66 -0
- package/skills/code-review/scripts/dispatch_waves.py +164 -0
- package/skills/code-review/scripts/finding_signature.py +446 -0
- package/skills/code-review/scripts/ledger.py +283 -0
- package/skills/code-review/scripts/partition.py +169 -0
- package/skills/code-review/scripts/render_tiered_findings.py +274 -0
- package/skills/code-review/scripts/repo_invariants.py +1066 -0
- package/skills/code-review/scripts/review_context_pack.py +306 -0
- package/skills/code-review/scripts/review_round_log.py +345 -0
- package/skills/code-review/scripts/review_value_coverage.py +297 -0
- package/skills/code-review/scripts/validate_review_output.py +467 -0
- package/skills/code-review/sliced-mode.md +205 -0
- package/skills/competitive-analysis/SKILL.md +191 -0
- package/skills/context-loading-protocol/SKILL.md +157 -0
- package/skills/continue/SKILL.md +90 -0
- package/skills/cost-report/SKILL.md +178 -0
- package/skills/coverage-baseline/SKILL.md +335 -0
- package/skills/coverage-baseline/references/multi-project-discovery.md +202 -0
- package/skills/coverage-delta/SKILL.md +181 -0
- package/skills/coverage-delta/references/mutation-gate.md +70 -0
- package/skills/design-doc/SKILL.md +95 -0
- package/skills/design-interrogation/SKILL.md +89 -0
- package/skills/design-it-twice/SKILL.md +91 -0
- package/skills/docker-image-audit/SKILL.md +108 -0
- package/skills/docker-image-audit/references/install-guide.md +64 -0
- package/skills/docker-image-audit/references/report-template.md +73 -0
- package/skills/docker-image-create/SKILL.md +185 -0
- package/skills/domain-analysis/SKILL.md +183 -0
- package/skills/domain-driven-design/SKILL.md +194 -0
- package/skills/exploratory-testing/SKILL.md +108 -0
- package/skills/explore/SKILL.md +51 -0
- package/skills/farley-score/SKILL.md +165 -0
- package/skills/feature-file-validation/SKILL.md +78 -0
- package/skills/feature-file-validation/references/validation-rules.md +115 -0
- package/skills/feedback-learning/SKILL.md +414 -0
- package/skills/fix/SKILL.md +450 -0
- package/skills/freeze/SKILL.md +68 -0
- package/skills/frontend-architecture/SKILL.md +113 -0
- package/skills/gherkin-derive/SKILL.md +630 -0
- package/skills/gherkin-public/SKILL.md +266 -0
- package/skills/governance-compliance/SKILL.md +150 -0
- package/skills/guard/SKILL.md +75 -0
- package/skills/handoff/SKILL.md +139 -0
- package/skills/handoff/references/summary-templates.md +242 -0
- package/skills/harness-audit/SKILL.md +751 -0
- package/skills/harness-audit/scripts/lesson_validate.py +386 -0
- package/skills/harness-audit/scripts/redundancy_criterion.py +188 -0
- package/skills/headless-run/SKILL.md +45 -0
- package/skills/headless-run/scripts/isolated_dispatch.py +381 -0
- package/skills/help/SKILL.md +72 -0
- package/skills/hexagonal-architecture/SKILL.md +85 -0
- package/skills/human-oversight-protocol/SKILL.md +224 -0
- package/skills/issues-from-assessment/SKILL.md +223 -0
- package/skills/issues-from-plan/SKILL.md +133 -0
- package/skills/legacy-code/SKILL.md +132 -0
- package/skills/mermaid-diagramming/SKILL.md +120 -0
- package/skills/mutation-night-watch/SKILL.md +154 -0
- package/skills/mutation-night-watch/references/scheduling.md +135 -0
- package/skills/mutation-testing/SKILL.md +396 -0
- package/skills/mutation-testing/references/languages/csharp-stryker-net.md +676 -0
- package/skills/mutation-testing/references/languages/go-go-mutesting.md +95 -0
- package/skills/mutation-testing/references/languages/java-pitest.md +77 -0
- package/skills/mutation-testing/references/languages/javascript-stryker.md +188 -0
- package/skills/mutation-testing/references/languages/python-mutmut.md +97 -0
- package/skills/mutation-testing/references/time-estimation.md +34 -0
- package/skills/mutation-testing/references/tool-detection.md +15 -0
- package/skills/mutation-testing/references/workflow-callers.md +23 -0
- package/skills/mutation-testing/scripts/__pycache__/xunit_v3_feature_detector.cpython-314.pyc +0 -0
- package/skills/mutation-testing/scripts/csharp_stryker_net_slice_runner.py +635 -0
- package/skills/mutation-testing/scripts/csharp_stryker_net_status_loop.py +525 -0
- package/skills/mutation-testing/scripts/csharp_stryker_net_wrapper.py +681 -0
- package/skills/mutation-testing/scripts/mutation_baseline_reuse.py +292 -0
- package/skills/mutation-testing/scripts/mutation_exclude_policy.py +268 -0
- package/skills/mutation-testing/scripts/mutation_feasibility_gate.py +463 -0
- package/skills/mutation-testing/scripts/mutation_kill_headless.py +331 -0
- package/skills/mutation-testing/scripts/mutation_kill_insert.py +199 -0
- package/skills/mutation-testing/scripts/mutation_kill_insert_python.py +150 -0
- package/skills/mutation-testing/scripts/mutation_kill_loop.py +869 -0
- package/skills/mutation-testing/scripts/mutation_kill_loop_python.py +949 -0
- package/skills/mutation-testing/scripts/mutation_kill_retry.py +592 -0
- package/skills/mutation-testing/scripts/mutation_kill_shared.py +620 -0
- package/skills/mutation-testing/scripts/mutation_nightwatch.py +462 -0
- package/skills/mutation-testing/scripts/mutation_nightwatch_stacks.py +425 -0
- package/skills/mutation-testing/scripts/mutation_report.py +743 -0
- package/skills/mutation-testing/scripts/mutation_report_cli.py +175 -0
- package/skills/mutation-testing/scripts/mutation_safety_gate.py +69 -0
- package/skills/mutation-testing/scripts/stryker_shard_pipeline.py +847 -0
- package/skills/mutation-testing/scripts/stryker_shard_setup.py +440 -0
- package/skills/mutation-testing/scripts/stryker_timeout_retry.py +142 -0
- package/skills/mutation-testing/scripts/xunit_v3_feature_detector.py +341 -0
- package/skills/performance-benchmark/SKILL.md +174 -0
- package/skills/performance-benchmark/examples/report-format.md +43 -0
- package/skills/performance-benchmark/references/benchmark-script.md +169 -0
- package/skills/performance-metrics/SKILL.md +265 -0
- package/skills/plan/SKILL.md +199 -0
- package/skills/plan/references/gherkin-persistence.md +43 -0
- package/skills/plan/references/plan-template.md +182 -0
- package/skills/pr/SKILL.md +289 -0
- package/skills/pr/scripts/gate_retry_state.py +368 -0
- package/skills/project-init/README.md +141 -0
- package/skills/project-init/SKILL.md +1197 -0
- package/skills/project-init/evals/evals.json +200 -0
- package/skills/project-init/references/capability-tools.md +55 -0
- package/skills/project-init/references/configs.md +221 -0
- package/skills/property-based-testing/SKILL.md +121 -0
- package/skills/property-based-testing/fixtures/invariant_fixture.py +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/README.md +42 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/LICENSE +21 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/README.md +263 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/fast-check.d.ts +5165 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/fast-check.js +12147 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/package.json +3 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/types57/fast-check.d.ts +5165 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/fast-check.d.ts +5165 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/fast-check.js +12011 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/rolldown-runtime-D7D4PA-g.js +13 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/types57/fast-check.d.ts +5165 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/package.json +94 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/LICENSE +21 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/README.md +168 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/RandomGenerator-DcXj09Ch.d.ts +14 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformBigInt.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformBigInt.js +38 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat32.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat32.js +18 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat64.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat64.js +22 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformInt.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformInt.js +134 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/RandomGenerator-DcXj09Ch.d.ts +14 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformBigInt.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformBigInt.js +37 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat32.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat32.js +17 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat64.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat64.js +21 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformInt.d.ts +15 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformInt.js +133 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/congruential32.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/congruential32.js +44 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/mersenne.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/mersenne.js +90 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xoroshiro128plus.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xoroshiro128plus.js +80 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xorshift128plus.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xorshift128plus.js +78 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/package.json +3 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/JumpableRandomGenerator.d.ts +16 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/JumpableRandomGenerator.js +0 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/RandomGenerator.d.ts +2 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/RandomGenerator.js +0 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/generateN.d.ts +6 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/generateN.js +8 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/purify.d.ts +12 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/purify.js +9 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/skipN.d.ts +6 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/skipN.js +6 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/congruential32.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/congruential32.js +46 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/mersenne.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/mersenne.js +92 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xoroshiro128plus.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xoroshiro128plus.js +82 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xorshift128plus.d.ts +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xorshift128plus.js +80 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/JumpableRandomGenerator.d.ts +16 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/JumpableRandomGenerator.js +0 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/RandomGenerator.d.ts +2 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/RandomGenerator.js +0 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/generateN.d.ts +6 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/generateN.js +9 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/purify.d.ts +12 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/purify.js +10 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/skipN.d.ts +6 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/skipN.js +7 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/package.json +133 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/package-lock.json +1179 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/package.json +14 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/roundtrip.js +29 -0
- package/skills/property-based-testing/fixtures/js-roundtrip/roundtrip.properties.test.js +16 -0
- package/skills/property-based-testing/fixtures/no_property_fixture.py +10 -0
- package/skills/property-based-testing/fixtures/roundtrip_fixture.py +16 -0
- package/skills/property-based-testing/references/languages/javascript.md +54 -0
- package/skills/property-based-testing/scripts/detect_and_dispatch.py +80 -0
- package/skills/property-based-testing/scripts/hypothesis_scaffold.py +276 -0
- package/skills/proxy-resilience/SKILL.md +84 -0
- package/skills/quality-gate-pipeline/SKILL.md +184 -0
- package/skills/quality-targets-converge/SKILL.md +254 -0
- package/skills/repo-review/SKILL.md +159 -0
- package/skills/report-pdf/SKILL.md +66 -0
- package/skills/review/SKILL.md +47 -0
- package/skills/review-agent/SKILL.md +152 -0
- package/skills/review-summary/SKILL.md +73 -0
- package/skills/run-report/SKILL.md +70 -0
- package/skills/semantic-duplication-scan/SKILL.md +337 -0
- package/skills/semantic-scan/SKILL.md +53 -0
- package/skills/semgrep-analyze/SKILL.md +139 -0
- package/skills/setup/SKILL.md +1122 -0
- package/skills/ship/SKILL.md +240 -0
- package/skills/source-verification/SKILL.md +210 -0
- package/skills/source-verification/scripts/claim_extractor.py +155 -0
- package/skills/specs/.size-baseline.json +4 -0
- package/skills/specs/SKILL.md +243 -0
- package/skills/specs/references/completeness-checklist.md +83 -0
- package/skills/specs/references/extraction.md +58 -0
- package/skills/specs/references/glossary.md +59 -0
- package/skills/specs/references/persistence.md +115 -0
- package/skills/specs/references/predictability-check.md +77 -0
- package/skills/static-analysis-integration/SKILL.md +235 -0
- package/skills/static-analysis-integration/adapters/_envelope.py +26 -0
- package/skills/static-analysis-integration/adapters/jscpd-adapter.py +66 -0
- package/skills/static-analysis-integration/adapters/lizard-adapter.py +81 -0
- package/skills/static-analysis-integration/adapters/mypy-adapter.py +50 -0
- package/skills/static-analysis-integration/adapters/mypy-src-layout.py +93 -0
- package/skills/static-analysis-integration/adapters/security-review-adapter.py +212 -0
- package/skills/static-analysis-integration/maintenance.md +23 -0
- package/skills/static-analysis-integration/references/language-setup.md +228 -0
- package/skills/static-analysis-integration/references/sarif-parser.md +124 -0
- package/skills/static-analysis-integration/references/security-review-adapter.md +118 -0
- package/skills/static-analysis-integration/references/tool-configs.md +617 -0
- package/skills/static-analysis-integration/rulesets/pmd-quickstart.xml +24 -0
- package/skills/stryker-xunit-v2-shim/SKILL.md +274 -0
- package/skills/stryker-xunit-v2-shim/references/shim-howto.md +256 -0
- package/skills/stryker-xunit-v2-shim/scripts/generate_shim.py +143 -0
- package/skills/systematic-debugging/SKILL.md +130 -0
- package/skills/telemetry/SKILL.md +75 -0
- package/skills/test-audit-disable/SKILL.md +129 -0
- package/skills/test-design/SKILL.md +177 -0
- package/skills/test-design/scripts/__pycache__/internal_double_detector.cpython-314.pyc +0 -0
- package/skills/test-design/scripts/internal_double_detector.py +631 -0
- package/skills/test-design-advisor/SKILL.md +166 -0
- package/skills/test-driven-development/SKILL.md +169 -0
- package/skills/test-health/SKILL.md +262 -0
- package/skills/test-improve/SKILL.md +239 -0
- package/skills/test-improve/references/phase-0-approach-contract.md +228 -0
- package/skills/test-improve/references/phase-1-analyze.md +131 -0
- package/skills/test-improve/references/phase-2-baseline.md +121 -0
- package/skills/test-improve/references/phase-3-derive-gherkin.md +53 -0
- package/skills/test-improve/references/phase-4-plan-fixes.md +34 -0
- package/skills/test-improve/references/phase-5-improve.md +215 -0
- package/skills/test-improve/references/phase-6-refactor-decision.md +45 -0
- package/skills/test-improve/references/phase-7-refactor.md +44 -0
- package/skills/test-improve/references/phase-8-validate.md +66 -0
- package/skills/test-improve/references/phase-9-close-out-prompt.md +11 -0
- package/skills/test-improve/references/phase-9-report.md +62 -0
- package/skills/test-improve/references/review-loop.md +92 -0
- package/skills/test-improve/templates/executive-summary.md +123 -0
- package/skills/threat-modeling/SKILL.md +108 -0
- package/skills/triage/SKILL.md +211 -0
- package/skills/ubiquitous-language/SKILL.md +192 -0
- package/skills/ubiquitous-language/scripts/collect_domain_signals.py +300 -0
- package/skills/unfreeze/SKILL.md +37 -0
- package/skills/upgrade/SKILL.md +31 -0
- package/skills/upgrade/scripts/check_version_drift.py +113 -0
- package/skills/upgrade/scripts/enable_autoupdate.py +149 -0
- package/skills/version/SKILL.md +25 -0
- package/sync/__pycache__/sync_upstream.cpython-314.pyc +0 -0
- package/sync/sync_upstream.py +293 -0
- package/templates/ACCEPTED-RISKS.md.tmpl +46 -0
- package/templates/agents/agent-template.md +151 -0
- package/templates/agents/angular-testing.md +66 -0
- package/templates/agents/csharp-quality.md +63 -0
- package/templates/agents/esm-enforcer.md +52 -0
- package/templates/agents/front-end-testing.md +65 -0
- package/templates/agents/go-quality.md +65 -0
- package/templates/agents/python-quality.md +62 -0
- package/templates/agents/react-testing.md +61 -0
- package/templates/agents/ts-enforcer.md +60 -0
- package/templates/agents/twelve-factor-audit.md +49 -0
- package/tools/entropy-check.py +250 -0
- package/tools/model-hash-verify.py +213 -0
|
@@ -0,0 +1,676 @@
|
|
|
1
|
+
# Mutation Testing — C# / .NET (Stryker.NET)
|
|
2
|
+
|
|
3
|
+
Tool: [Stryker.NET](https://stryker-mutator.io/docs/stryker-net/introduction/). Detection: `dotnet-stryker` in tool manifest.
|
|
4
|
+
|
|
5
|
+
## Install / detect
|
|
6
|
+
|
|
7
|
+
The tool manifest is the **local** install path: `.config/dotnet-tools.json` lives in the repo, so `dotnet stryker` resolves via the manifest without depending on `$PATH`. A global install (`dotnet tool install -g dotnet-stryker`) is a fallback only — it depends on `~/.dotnet/tools` being on `PATH` and is the failure mode that motivated the "prefer local install" note in the skill.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
dotnet new tool-manifest # if no .config/dotnet-tools.json yet
|
|
11
|
+
dotnet tool install dotnet-stryker
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Confirm the tool resolves before configuring a run:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
dotnet stryker --version
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Environment preamble (macOS Homebrew)
|
|
21
|
+
|
|
22
|
+
`dotnet stryker` (whether invoked as the tool or as `~/.dotnet/tools/dotnet-stryker`) fails with **"You must install .NET to run this application"** when .NET is installed via Homebrew, because the runtime lives at `/opt/homebrew/opt/dotnet/libexec` rather than at the default path. Export `DOTNET_ROOT` before any Stryker invocation:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
export DOTNET_ROOT="${DOTNET_ROOT:-/opt/homebrew/opt/dotnet/libexec}"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Confirm the local runtime path with:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
dotnet --info | grep "Base Path"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Every run command below assumes this export is in scope.
|
|
35
|
+
|
|
36
|
+
## xunit.v3 detection (do this before configuring runs)
|
|
37
|
+
|
|
38
|
+
xunit.v3 adopted the Microsoft Testing Platform (MTP) runner. The MTP runner **does not support per-test coverage boundaries**, so `"coverage-analysis": "perTest"` silently falls back to running the entire test suite against every mutant — plus, hanging async tests burn the entire `additional-timeout` window. The observable symptoms are massive timeout counts, multi-hour runtimes, and a **fake 100% mutation score** (all mutants recorded as `Timeout`, none `Killed` or `Survived`). See [stryker-net#3117](https://github.com/stryker-mutator/stryker-net/issues/3117) and [stryker-net#3629](https://github.com/stryker-mutator/stryker-net/issues/3629).
|
|
39
|
+
|
|
40
|
+
Detect xunit.v3 before configuring the run:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
grep -rl "xunit.v3" tests/ --include="*.csproj" 2>/dev/null
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
If detected, take **all four** steps below. Missing any one recreates the fake-score failure mode.
|
|
47
|
+
|
|
48
|
+
1. In every `stryker-config.json` (or per-shard config), set `"coverage-analysis": "off"` explicitly — not `perTest`.
|
|
49
|
+
2. Create `xunit.runner.json` in each test project directory with `"testTimeout": 5000` to cap individual hanging tests at 5 s:
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
|
|
54
|
+
"testTimeout": 5000
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
3. Deploy `xunit.runner.json` to the output directory by adding this to each test `.csproj`:
|
|
59
|
+
|
|
60
|
+
```xml
|
|
61
|
+
<ItemGroup>
|
|
62
|
+
<None Update="xunit.runner.json">
|
|
63
|
+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
64
|
+
</None>
|
|
65
|
+
</ItemGroup>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
4. In `stryker-config.json`, set `"additional-timeout": 30000` — headroom for ~5 hanging tests × 5 s `testTimeout` per mutant plus overhead. This is a **layered** cap on top of the per-mutant `timeout` documented in [`SKILL.md`](../../SKILL.md) Step 1b.
|
|
69
|
+
|
|
70
|
+
The four steps above defend against the *fake-100 %-via-Timeout* variant of the MTP-runner incompatibility. The **complementary** *fake-0 %-via-Survived* variant (mutation-switch not observing mutations at runtime; every mutant reported `Survived`; final score `0.00 %`) is caught by [`SKILL.md`](../../SKILL.md) **Step 1c smoke gate** — run a single-file probe before any full run and parse `mutation-report.json` for `Killed > 0`. Do not skip Step 1c on xunit.v3 configurations; it is the specific safety net for issues [#554](https://github.com/bdfinst/agentic-dev-team/issues/554) and [#557](https://github.com/bdfinst/agentic-dev-team/issues/557). Inside a Claude Code session the [`mutation_testing_smoke_gate`](../../../../hooks/mutation_testing_smoke_gate.py) PreToolUse hook enforces this step automatically — see SKILL.md § Step 1c for the operator-facing contract.
|
|
71
|
+
|
|
72
|
+
## xunit.v3 shim-breaking features — detect and human-gate (before building the shim)
|
|
73
|
+
|
|
74
|
+
The v2 shim is the only path that gives the mutant-kill **loop** per-test coverage on an xunit.v3 suite (under v2/VSTest `perTest` works, ~5–6× faster than `off` — see [#669](https://github.com/bdfinst/agentic-dev-team/issues/669)). Its weakness is compile fragility: any xunit-v3-only API breaks the shim's compile before Stryker runs a mutant (the `[Fact(Explicit = true)]` break that motivated [#1156](https://github.com/bdfinst/agentic-dev-team/issues/1156)). Rather than hand the operator an opaque C# compile error, scan for the breaking constructs first and let a human decide.
|
|
75
|
+
|
|
76
|
+
**Detector.** [`../../scripts/xunit_v3_feature_detector.py`](../../scripts/xunit_v3_feature_detector.py) scans the real xunit.v3 test `.cs` files for shim-breaking v3-only constructs (`[Fact/Theory(Explicit = true)]`, `Assert.Skip`/`SkipWhen`/`SkipUnless`, `TestContext.Current`/`ITestContext`, `ValueTask` async-lifetime signatures, `TheoryDataRow`) and classifies each on two axes:
|
|
77
|
+
|
|
78
|
+
- **compile-ability** — `clean-translatable` (a mechanical v2 equivalent exists) vs `no-v2-equivalent` (cannot compile under v2).
|
|
79
|
+
- **coverage impact** — `neutral` (excluding the test from the shim changes no coverage — e.g. `Explicit=true` tests are skipped by default, **provided the run does not enable explicit tests** via `-explicit` / `xunit.runner.json` `explicit=on`) vs `bearing` (the test runs and covers code, so excluding it inflates the loop's survivor set and makes it generate redundant tests).
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
python3 "${CLAUDE_PLUGIN_ROOT}/skills/mutation-testing/scripts/xunit_v3_feature_detector.py" <test-project>/**/*.cs --json
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Human gate — always ask, never auto-drop.** Present the full classified list every run, even when every hit is coverage-neutral. For each test the operator chooses whether to exclude it from the shim for the duration of the loop; nothing is deactivated silently. Coverage-bearing tests are flagged with the lines that go dark if excluded. The detector's `summary.recommendation` is **advisory** sizing only (few + neutral → shim path is reasonable; many or coverage-bearing → prefer skipping the loop for a single-pass `coverage-analysis: off` advisory) — the human always decides.
|
|
86
|
+
|
|
87
|
+
**"Deactivate" means exclude from the shim's `<Compile Include>` set, never edit the real test suite** — so there is no crash-unsafe "restore after the loop" step. The operator-selected exclusions are applied to the shim project by the shim-generation path (see [#1159](https://github.com/bdfinst/agentic-dev-team/issues/1159)); the loop-vs-degrade decision that consumes this gate's outcome lives in [#1158](https://github.com/bdfinst/agentic-dev-team/issues/1158).
|
|
88
|
+
|
|
89
|
+
### Stryker >= 5.0.0 — `-t mtp` + `coverage-analysis: perTest` restores real per-test coverage, no shim
|
|
90
|
+
|
|
91
|
+
Stryker.NET **5.0.0** (2026-09-11) shipped [stryker-net#3752](https://github.com/stryker-mutator/stryker-net/issues/3752) — MTP `perTest`/`perTestInIsolation` coverage analysis — plus [#3696](https://github.com/stryker-mutator/stryker-net/issues/3696) (flaky MTP coverage) and [#3769](https://github.com/stryker-mutator/stryker-net/issues/3769) (MTP coverage per mutated assembly). That closes the gap the shim exists to work around: against a **real xunit.v3 suite**, no shim, no v3-only-construct porting:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
dotnet stryker -t mtp --config-file stryker-config.json # coverage-analysis: perTest, concurrency: 1
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Pin `concurrency: 1` until [stryker-net#3832](https://github.com/stryker-mutator/stryker-net/issues/3832) closes** — an OPEN regression where 5.0.0 under-reports kills nondeterministically under MTP at concurrency > 1 (a proposed fix, #3724, was confirmed by the reporter NOT to resolve it; a minimal repro exists at `dclark-olm/stryker-3832-repro`). [#2192](https://github.com/bdfinst/agentic-dev-team/issues/2192) tracks removing this pin once #3832 ships a fix.
|
|
98
|
+
|
|
99
|
+
`stryker_xunit_shim_guard.py` detects the installed version (`hooks/mutation_adapters/stryker_net.py::stryker_net_version()`) and silent-passes an xunit.v3 project run on >= 5.0.0 — it does not scaffold a shim or block, whichever runner flag the command uses. An undetermined version (no `dotnet` on PATH, or unparseable `--version` output) fails closed to the < 5.0.0 behavior below.
|
|
100
|
+
|
|
101
|
+
### < 5.0.0 — no-shim floor: `-t mtp` + `coverage-analysis: off`
|
|
102
|
+
|
|
103
|
+
On Stryker **< 5.0.0**, when the feasibility gate degrades — a declined shim, a failed per-test capture probe, or an operator choosing to degrade after an over-budget `ask-operator` prompt (see [mutation-kill.md](../../../../agents/mutation-kill.md#pre-loop-feasibility-gate-xunitv3-shim-first) — an over-budget estimate alone asks the operator, it does not auto-degrade) — the sanctioned fallback is to run the **real xunit.v3 suite** through the Microsoft Testing Platform runner with coverage off:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
dotnet stryker -t mtp --config-file stryker-config.json # coverage-analysis: off
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
No shim is built, so there are no v3-only-syntax compile breaks. **On < 5.0.0, `-t mtp` is the floor, not a fast path** — it does not restore per-test coverage (stryker-net#3629 was closed-unfixed pre-5.0.0; #3752 above is what fixed it, starting at 5.0.0), so the run is still whole-suite-per-mutant and slow; use it for a single advisory pass, not the iterating loop. The `stryker_xunit_shim_guard.py` gate **exempts** an explicit `-t mtp` run on any version (it produces a real score once MTP coverage works, and on < 5.0.0 it's still the sanctioned single-pass floor either way, so the false-~0% block never applies to it).
|
|
110
|
+
|
|
111
|
+
**Trigger is xunit.v3, not the TFM.** Decide `off`-vs-`perTest` from xunit.v3 in the **real** test suite, never from a csproj that may be the v2 shim — a shim's `xunit` v2 marker must not mask the real v3 project. **Runtime:** current Stryker.NET requires the **.NET 10 runtime to run** (even for older target projects); if `dotnet --version` is below 10, install/select it before any Stryker invocation.
|
|
112
|
+
|
|
113
|
+
## .NET 10 targets: default `vstest` runner can silently fake a 0% score
|
|
114
|
+
|
|
115
|
+
> **Distinct from the xunit.v3 coverage-capture failure** (see the "No-shim floor" and xunit.v3 sections above). That one is a **per-test coverage-capture** problem keyed on **xunit.v3** (breaks even under VSTest), where `-t mtp` is only the slow *floor*. The one below is a **runner-execution** problem keyed on the **TFM**: the bundled vstest runner cannot execute the assemblies at all. `-t mtp` genuinely fixes *this* one (it swaps in a runner that can execute the tests) but still does **not** restore fast per-test coverage. Do not read this TFM-keyed runner bug as licence to decide `off`-vs-`perTest` from the TFM — that decision keys on xunit.v3.
|
|
116
|
+
|
|
117
|
+
On **.NET 10** test-project targets (and possibly .NET 9), Stryker.NET's bundled default `vstest` test runner can silently fail to **execute** newer-TFM test assemblies — it ships a `net8.0` `vstest.console.dll` that cannot correctly run them. The observable symptom is a **fake `Killed: 0` / `Survived: N` / 0.00 % score**, even though the same tests pass fine under a direct `dotnet test`. This is a **complementary** failure mode to the [xunit.v3 detection](#xunitv3-detection-do-this-before-configuring-runs) section above (that one produces a fake **100 %** via `Timeout`; this one produces a fake **0 %** via `Survived`) — both are caught by [`SKILL.md`](../../SKILL.md) **Step 1c smoke gate**, but this one is easy to mistake for a legitimately weak test suite rather than a broken runner.
|
|
118
|
+
|
|
119
|
+
**Recommend `-t mtp` (the Microsoft Testing Platform runner) for .NET 10+ targets to fix the runner-execution failure — but note it does not restore per-test coverage (that is the separate xunit.v3 constraint above):**
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
export DOTNET_ROOT="${DOTNET_ROOT:-/opt/homebrew/opt/dotnet/libexec}"
|
|
123
|
+
dotnet build <solution> -c Debug --nologo
|
|
124
|
+
dotnet stryker -t mtp --mutate "**/ChangedFile.cs" -O StrykerOutput/probe
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
If a smoke probe (Step 1c) or full run reports `Killed: 0` alongside `Survived > 0` on a .NET 10 target using the default runner, retry with `-t mtp` before assuming the test suite doesn't cover the mutated code — a broken runner (can't execute the assemblies), not a real test gap, is the more likely explanation on this TFM.
|
|
128
|
+
|
|
129
|
+
## Default `coverage-analysis: perTest` for xunit.v2 / non-MTP projects
|
|
130
|
+
|
|
131
|
+
For Stryker.NET projects that are **not** on xunit.v3 / the MTP runner (see the [xunit.v3 detection](#xunitv3-detection-do-this-before-configuring-runs) section above, which stays mandatory for those projects), default `"coverage-analysis": "perTest"` in `stryker-config.json` rather than `"off"`. Per-test coverage tracking lets each mutant run only the tests that actually exercise the mutated line, instead of the full suite — a significant speedup on large suites.
|
|
132
|
+
|
|
133
|
+
[#669](https://github.com/bdfinst/agentic-dev-team/issues/669) validated this against an xunit.v2-shim repo (the shim workaround from #554/#557, described in the [SolutionPath trap](#solutionpath-trap) section below) at two points. It specifically checked the two failure modes a static-analysis-based coverage tool is prone to:
|
|
134
|
+
|
|
135
|
+
- **Reflection** (`MethodInfo.Invoke`) — a test invoking a private method via reflection correctly killed its target mutant under `perTest`.
|
|
136
|
+
- **Container-resolution DI** (Autofac `container.Resolve<T>()`) — 14 tests building a real Autofac container and resolving decorated services were correctly attributed as covering the registration statements they exercise.
|
|
137
|
+
|
|
138
|
+
Both risks checked out clean — zero mutants flipped from `Killed` to `Survived`/`NoCoverage` between the `"off"` baseline and `perTest`:
|
|
139
|
+
|
|
140
|
+
| File | Baseline (`off`) | `perTest` |
|
|
141
|
+
| --- | --- | --- |
|
|
142
|
+
| DataFormatter.cs | 40 Killed / 2 Survived | 41 Killed / 1 Survived |
|
|
143
|
+
| SystemConstants.cs | 78 Killed / 0 | 78 Killed / 0 — identical |
|
|
144
|
+
| RequestContext.cs | 10 Killed / 0 | 10 Killed / 0 — identical |
|
|
145
|
+
| PublicApiAttribute.cs | 1 Killed / 0 | 1 Killed / 0 — identical |
|
|
146
|
+
| ComponentModule.cs | 48 Killed / 168 Survived | 48 Killed / 164 Survived / 4 NoCoverage — identical Killed count |
|
|
147
|
+
|
|
148
|
+
Speed: the testing-phase wall-clock dropped roughly **5-6x** (~17-21 min under `off` → ~3-4 min under `perTest`; total run including build+shim went from ~19-24 min to ~6 min).
|
|
149
|
+
|
|
150
|
+
This recommendation **does not apply to xunit.v3 / MTP-runner projects** — the [xunit.v3 detection](#xunitv3-detection-do-this-before-configuring-runs) section's `"coverage-analysis": "off"` mandate above is unrelated and unaffected; #669 did not re-test that failure mode.
|
|
151
|
+
|
|
152
|
+
## Pre-run: build first
|
|
153
|
+
|
|
154
|
+
Always build before timing the baseline suite or invoking Stryker. A stale binary produces phantom failures — Stryker either aborts on load or reports every mutant as `Survived`. Baseline timing:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
dotnet build <solution> -c Debug --nologo
|
|
158
|
+
time dotnet test <test-project> -c Debug --no-build
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Every Stryker run block below assumes a fresh `dotnet build ... -c Debug --nologo` immediately precedes it.
|
|
162
|
+
|
|
163
|
+
## Config authoring notes
|
|
164
|
+
|
|
165
|
+
Stryker.NET rejects **any unknown key** in `stryker-config.json` since v1.x — a JSON comment workaround like `"_note": "..."` or `"//": "..."` causes the entire run to fail with a clear error message. Do not embed intent comments in the config. Document config intent in the git commit message that introduces the config, or in a nearby `README.md`.
|
|
166
|
+
|
|
167
|
+
### `--mutate` line-span narrowing — character offsets, not line numbers (#2031)
|
|
168
|
+
|
|
169
|
+
Stryker.NET's `mutate` option supports a span suffix beyond plain globs. Confirmed against Stryker.NET's own current documentation (`stryker-mutator.io/docs/stryker-net/configuration/`, § `mutate`, fetched live during the #2031 investigation):
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
dotnet stryker -m "MyFolder/MyService.cs{10..100}"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**The span is defined by character indices, not line numbers.** The docs are explicit: "the span of text that should be in- or excluded. A span is defined by the indices of the first character and the last character." A `mutation-kill` scaffold landed in #2053 assumed the opposite for the survivor-scoped confirm-run optimization (`mutation_kill_loop.make_confirm_scoped_config`) — that the `{start..end}` suffix takes *line* numbers, one span per previous-round survivor line (`"**/File.cs{10..10}"` for a survivor on line 10). That assumption is wrong: fed a line number where Stryker parses a character offset, the span points at an unrelated, essentially arbitrary character range near the start of the file, not the intended line.
|
|
176
|
+
|
|
177
|
+
**Status: not wired into the loop.** Translating a survivor line number to the character-offset span Stryker.NET actually expects is mechanically computable (read the file, sum preceding line lengths), but the exact indexing convention — 0- vs 1-based, inclusive/exclusive end, how CRLF line endings count toward the offset — is not pinned by the documentation snippet alone, and confirming it needs a live `dotnet`/`dotnet-stryker` run against a probe file with a known survivor line. That toolchain was not available in the environment that did this investigation (`dotnet` not on `PATH`; general GitHub repository/source access beyond this plugin's own repo was also unavailable, so the Stryker.NET parser source itself could not be inspected directly — only the published docs). `make_confirm_scoped_config` therefore stays unwired from `_score_round` — pinned by `test_confirm_scoped_config_is_not_wired_into_the_default_loop_path` in `tests/scripts/test_mutation_kill_loop.py` — until a pass with a real Stryker.NET verifies the character-offset conversion end-to-end.
|
|
178
|
+
|
|
179
|
+
**To perform that verification:** pick a probe file with one known Survived mutant on a known line, hand-compute a `{start..end}` character span bracketing that line by a few conventions (0-based vs 1-based, inclusive vs exclusive end), run `dotnet stryker -m "<Probe>.cs{<start>..<end>}"` for each candidate, and confirm which one reports mutants on exactly that line — not the whole file, not an adjacent line, not zero mutants. Record the confirmed convention here and in `make_confirm_scoped_config`'s docstring, then wire the loop's terminal-round confirm through it.
|
|
180
|
+
|
|
181
|
+
**Degenerate-narrowing guard already lands regardless.** `make_confirm_scoped_config` accepts an optional `total_file_lines` — when narrowing would touch too much of the file's own line count (default: 50%+) to be worth the extra `mutate` array entries, it degrades to the ordinary whole-file scoped config instead. This doesn't depend on resolving the character-offset question above, so it ships now, tested, ready for whichever span form eventually gets wired in.
|
|
182
|
+
|
|
183
|
+
**JS Stryker is unaffected — no equivalent loop exists to verify.** `mutation_kill_loop.py` (the module this section documents) is Stryker.NET-specific — it imports `csharp_stryker_net_wrapper` directly and owns `.sln` hide/restore, which has no JS analogue. The Python/mutmut sibling (`mutation_kill_loop_python.py`) is Python-only per its own module docstring. No JS-Stryker survivor-scoped confirm-run loop exists in this plugin today, so #2031's span-syntax verification is Stryker.NET-only; there is no parallel JS `--mutate` span form this change needs to check.
|
|
184
|
+
|
|
185
|
+
### SolutionPath trap
|
|
186
|
+
|
|
187
|
+
When `stryker-config.json` sets **both** `SolutionPath` and an explicit `test-projects` list, Stryker.NET evidently enumerates additional test projects from the solution and prefers them over the ones listed in `test-projects`. On a repo whose main test project is on xunit.v3 + MTP but whose configured `test-projects` points at a working xunit.v2 shim, this manifests as the shim's `InternalsVisibleTo` grant and successful smoke tests not helping — because Stryker isn't actually running the shim; it's running the main xunit.v3 test project it discovered via `SolutionPath`, and the fake-0 %-via-Survived MTP failure mode from #554 strikes anyway. The `--diag` output reveals this via a `Property TargetPath=` line naming the wrong test-project `.dll`. See issue [#557](https://github.com/bdfinst/agentic-dev-team/issues/557).
|
|
188
|
+
|
|
189
|
+
Three remediation paths, in order of preference:
|
|
190
|
+
|
|
191
|
+
1. **Remove `SolutionPath` from `stryker-config.json`.** Rely on `test-projects` only. Simplest fix; the plugin **recommends this path** for multi-project repos where the only reason `SolutionPath` was set was to help Stryker resolve source-project dependencies — the explicit `test-projects` list gives it what it needs. This is the path documented in the shipped wrapper.
|
|
192
|
+
2. **Add the shim project to the solution and exclude the main test project from Stryker's discovery.** Requires per-repo solution-file surgery and a Stryker-side exclusion rule; brittle and not documented upstream.
|
|
193
|
+
3. **Downgrade the main test project to xunit.v2** for the mutation window. Nuclear option — invasive to the main test suite for the duration of a mutation-testing session; only use when path 1 is genuinely impossible.
|
|
194
|
+
|
|
195
|
+
### Reporters — use `dots` for log-tail parsing
|
|
196
|
+
|
|
197
|
+
Configure Stryker with a **non-ANSI** reporter alongside JSON/HTML so status-loop tooling and log inspection can read progress deterministically:
|
|
198
|
+
|
|
199
|
+
```json
|
|
200
|
+
{
|
|
201
|
+
"stryker-config": {
|
|
202
|
+
"reporters": ["dots", "json", "html"]
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
The default `progress` reporter uses ANSI in-place cursor updates that **do not survive log redirection** — a redirected run's log file has no per-mutant progress record. The `dots` reporter emits one `.` per completed mutant to stdout, which redirects cleanly. Any long-run inspection tooling (see [`SKILL.md` → Long-run inspection](../../SKILL.md#long-run-inspection)) that reads progress from a log tail depends on `dots` (or JSON) being configured.
|
|
208
|
+
|
|
209
|
+
### Probe file selection — C#-specific traps
|
|
210
|
+
|
|
211
|
+
The language-agnostic probe rule (≥ 50 mutants, highest existing mutation score, avoid generated code / DTOs / near-0 %-coverage files) lives in [`../../SKILL.md`](../../SKILL.md) Step 2 — read it first. Two Stryker.NET-specific probe anti-patterns compound the general rule; picking either as a probe validates nothing and produces a mass-CompileError smoke plume:
|
|
212
|
+
|
|
213
|
+
- **gRPC / Protobuf service implementations.** Stryker.NET's `ObjectInitializer` mutations target the auto-generated Protobuf message types. Because those types are code-generated, the mutations produce constructor / initializer forms that do not compile, yielding hundreds to thousands of `CompileError` mutants — no signal, only cost. Avoid these files as probes; scope them out of full runs unless you have a specific reason.
|
|
214
|
+
- **Caching / key-building classes under `mutation-level: Standard`.** The `Standard` mutation level enables `LinqMutation` and `StringMutation` operators that generate calls to methods that **do not exist** — for example `StringBuilder.Prepend` (the method is `Insert(0, …)`) and `IDictionary.Sum` (there is no `Sum` extension in the target namespace). These produce 1000+ `CompileError` mutants on files that build hash keys or aggregate LINQ. Drop such files to `mutation-level: Basic` (or exclude them) before probing.
|
|
215
|
+
|
|
216
|
+
### Tiered mutation-level: Basic baseline, Standard escalation
|
|
217
|
+
|
|
218
|
+
Pairs with the mutation-kill agent's [tiered mutation-level](../../../../agents/mutation-kill.md#tiered-mutation-level-strykernet-only) rule: the baseline `--all` scan runs at `Basic`; only files with survivors remaining after Basic converges get a Standard-level pass scoped to that one file.
|
|
219
|
+
|
|
220
|
+
**Basic baseline (whole scan):**
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
export DOTNET_ROOT="${DOTNET_ROOT:-/opt/homebrew/opt/dotnet/libexec}"
|
|
224
|
+
dotnet build <solution> -c Debug --nologo
|
|
225
|
+
dotnet stryker \
|
|
226
|
+
--config-file stryker-config.shard-<name>.json \
|
|
227
|
+
--mutation-level Basic \
|
|
228
|
+
--coverage-analysis perTest \
|
|
229
|
+
--reporter json \
|
|
230
|
+
-O StrykerOutput/baseline
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**Standard escalation (single file, after Basic converges with survivors remaining):**
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
export DOTNET_ROOT="${DOTNET_ROOT:-/opt/homebrew/opt/dotnet/libexec}"
|
|
237
|
+
dotnet build <solution> -c Debug --nologo
|
|
238
|
+
dotnet stryker \
|
|
239
|
+
--config-file stryker-config.shard-<name>.json \
|
|
240
|
+
--mutation-level Standard \
|
|
241
|
+
--mutate "**/CacheKeyBuilder.cs" \
|
|
242
|
+
--coverage-analysis perTest \
|
|
243
|
+
--reporter json \
|
|
244
|
+
-O StrykerOutput/escalation-CacheKeyBuilder
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
If the Standard escalation run hits the caching/key-building `CompileError` trap above, drop back to the Basic-level results and exclude the file from further Standard-level attempts rather than retrying.
|
|
248
|
+
|
|
249
|
+
## Run (scoped)
|
|
250
|
+
|
|
251
|
+
Large C# repos take 60–90 min for a whole-project run. Always scope runs; if the repo has pre-generated shard configs, use them.
|
|
252
|
+
|
|
253
|
+
> When capturing run output to a log file, do **not** use a bare `dotnet stryker ... 2>&1 | tee run.log` — the pipeline exit code is `tee`'s (always 0), so a Stryker failure is silently masked. Use `>run.log 2>&1` for one-shot runs or `set -o pipefail` for live tail. See [`SKILL.md` → Capturing run output safely](../../SKILL.md#capturing-run-output-safely).
|
|
254
|
+
|
|
255
|
+
**Single file in `--scope` (Phase 4 per-Story gate):**
|
|
256
|
+
|
|
257
|
+
`coverage-analysis` is config-file-only in Stryker.NET 4.15.0 — there is no CLI flag for it (confirmed via `--help`); set it in `stryker-config.shard-<name>.json` (see [Default `coverage-analysis: perTest`](#default-coverage-analysis-pertest-for-xunitv2--non-mtp-projects) above) rather than passing it on the command line below.
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
export DOTNET_ROOT="${DOTNET_ROOT:-/opt/homebrew/opt/dotnet/libexec}"
|
|
261
|
+
dotnet build <solution> -c Debug --nologo
|
|
262
|
+
|
|
263
|
+
# Scope to the changed file within its shard config
|
|
264
|
+
dotnet stryker \
|
|
265
|
+
--config-file stryker-config.shard-<name>.json \
|
|
266
|
+
--mutate "**/ChangedFile.cs" \
|
|
267
|
+
--reporter json \
|
|
268
|
+
-O StrykerOutput/gate-shard
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Full scan — shard configs present (Phase 5 convergence, initial baseline):**
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
export DOTNET_ROOT="${DOTNET_ROOT:-/opt/homebrew/opt/dotnet/libexec}"
|
|
275
|
+
dotnet build <solution> -c Debug --nologo
|
|
276
|
+
|
|
277
|
+
# Run each shard sequentially; aggregate results.
|
|
278
|
+
# stryker-pipeline.py --skip-agent handles this automatically.
|
|
279
|
+
python3 /path/to/nextgen-test-upgrade-process/scripts/stryker-pipeline.py \
|
|
280
|
+
--skip-agent
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
The pipeline writes one `StrykerOutput/shards/<name>/reports/mutation-report.json` per shard. Aggregate kills and survivors across all reports for the total score.
|
|
284
|
+
|
|
285
|
+
**Full scan — no shard configs (first time, small repo):**
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
export DOTNET_ROOT="${DOTNET_ROOT:-/opt/homebrew/opt/dotnet/libexec}"
|
|
289
|
+
dotnet build <solution> -c Debug --nologo
|
|
290
|
+
|
|
291
|
+
# Generate shard configs first to make future runs fast
|
|
292
|
+
python3 /path/to/nextgen-test-upgrade-process/scripts/stryker-setup.py
|
|
293
|
+
|
|
294
|
+
# Then run — dotnet stryker finds stryker-config.json
|
|
295
|
+
# (set "coverage-analysis" in stryker-config.json itself — it's config-file-only, no CLI flag)
|
|
296
|
+
dotnet stryker --reporter json -O StrykerOutput/baseline
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Named-run output directories.** Use the `-O` / `--output` CLI flag to name the output directory, e.g. `-O StrykerOutput/baseline` and `-O StrykerOutput/verification`. Do **not** use `--report-file-name` as a CLI flag — it is not one; it is a **config-file key** (`"report-file-name"` inside `stryker-config.json`) that renames the HTML/JSON output files *within* whichever directory `-O` selected.
|
|
300
|
+
|
|
301
|
+
**Probe a single file (default verbosity):**
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
export DOTNET_ROOT="${DOTNET_ROOT:-/opt/homebrew/opt/dotnet/libexec}"
|
|
305
|
+
dotnet build <solution> -c Debug --nologo
|
|
306
|
+
|
|
307
|
+
# Info-level output is default and readable — use trace only when debugging a startup problem.
|
|
308
|
+
dotnet stryker -m "**/ProbeFile.cs" -O StrykerOutput/probe
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Extract the summary from any run regardless of verbosity:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
grep -E "Killed:|Survived:|Timeout:|mutation score" <output-log> | tail -5
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
`-V trace` is a debug-only escape hatch for Stryker startup problems — it emits 1.5M+ lines for a two-minute probe run and buries the summary. Do not include it in probe or gate commands.
|
|
318
|
+
|
|
319
|
+
**Finding the relevant shard config for a given file (bash helper):**
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
changed_file="src/Foo.Bar/Controllers/PaymentController.cs"
|
|
323
|
+
for cfg in stryker-config.shard-*.json; do
|
|
324
|
+
prefix=$(python3 -c "
|
|
325
|
+
import json
|
|
326
|
+
p = json.load(open('$cfg'))['stryker-config'].get('mutate', [''])[0]
|
|
327
|
+
print(p.split('/**')[0])
|
|
328
|
+
")
|
|
329
|
+
[[ "$changed_file" == ${prefix}/* ]] && echo "$cfg" && break
|
|
330
|
+
done
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## Shipped wrapper
|
|
334
|
+
|
|
335
|
+
The plugin ships a Python wrapper + status loop under `plugins/dev-team/skills/mutation-testing/scripts/`:
|
|
336
|
+
|
|
337
|
+
- **`csharp_stryker_net_wrapper.py`** — hides `.sln` during the run + restores on any exit path, exports `DOTNET_ROOT` (auto-probed across all supported platforms; a pre-set value is respected), pre-builds `${SLN}` and optional `${SHIM_PROJECT}` **before** hiding, runs Stryker as a subprocess so SIGINT/SIGTERM kill the child too (no orphans), and redirects log via file descriptor (never a bare `| tee`).
|
|
338
|
+
- **`csharp_stryker_net_status_loop.py`** — status + red-flag inspection loop invoked by the wrapper. Ticks every `STATUS_INTERVAL` seconds emitting one status record plus zero-or-more `[RED-FLAG]` lines when known-broken patterns are observed (mutation-switch not observing; CompileError count over threshold; SolutionPath trap; Stryker died mid-run; parser drift).
|
|
339
|
+
|
|
340
|
+
Cross-platform authoritative: same code runs identically on macOS, Linux, Windows Git Bash, and native Windows via Python 3.10+'s stdlib. Requires only `python3` on PATH — no bash-shell tooling, no MSYS quirks. See [ADR 0014](../../../../../../docs/adr/0014-python-for-cross-os-scripts.md).
|
|
341
|
+
|
|
342
|
+
### Install
|
|
343
|
+
|
|
344
|
+
Copy `csharp_stryker_net_wrapper.py` AND `csharp_stryker_net_status_loop.py` into your repo's `scripts/` directory. The wrapper imports the status loop by module name; both files must sit next to each other so Python can find the loop on `sys.path`.
|
|
345
|
+
|
|
346
|
+
### Run
|
|
347
|
+
|
|
348
|
+
Run in place of a bare `dotnet stryker`:
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
python3 scripts/csharp_stryker_net_wrapper.py \
|
|
352
|
+
--sln Foo.sln \
|
|
353
|
+
--shim-project tests/Foo.Tests.Mutation/Foo.Tests.Mutation.csproj \
|
|
354
|
+
--logfile StrykerOutput/wrapper.log \
|
|
355
|
+
--config-file stryker-config.json \
|
|
356
|
+
--mutate "**/Validators/**/*.cs" \
|
|
357
|
+
-O StrykerOutput/slice-validators
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
The default `--stryker-bin` (`dotnet`) invokes the local tool-manifest install via `dotnet stryker`, matching "prefer local install" above. Pass `--stryker-bin dotnet-stryker` only to target a global install instead.
|
|
361
|
+
|
|
362
|
+
CLI flags (all optional; every one accepts an environment-variable equivalent so header-var configuration is preserved):
|
|
363
|
+
|
|
364
|
+
| Flag | Env var | Default |
|
|
365
|
+
| --- | --- | --- |
|
|
366
|
+
| `--sln PATH` | `SLN` | `Foo.sln` |
|
|
367
|
+
| `--shim-project PATH` | `SHIM_PROJECT` | (empty; no shim) |
|
|
368
|
+
| `--stryker-bin CMD` | `STRYKER_BIN` | `dotnet` (invoked as `dotnet stryker`) |
|
|
369
|
+
| `--logfile PATH` | `LOGFILE` | `StrykerOutput/wrapper.log` |
|
|
370
|
+
| `--stryker-concurrency N` | `STRYKER_MUTANT_CONCURRENCY` | `max(1, cpu_count - 2)` (computed) |
|
|
371
|
+
|
|
372
|
+
Everything after those flags forwards to Stryker unchanged.
|
|
373
|
+
|
|
374
|
+
`DOTNET_ROOT` is auto-probed across the standard install locations on all supported platforms; a pre-set value is respected. When no SDK is found the wrapper exits 3 with an actionable message.
|
|
375
|
+
|
|
376
|
+
### Concurrency default
|
|
377
|
+
|
|
378
|
+
The wrapper defaults Stryker's own mutant-testing-process concurrency (its
|
|
379
|
+
`-c`/`--concurrency` flag) to `max(1, cpu_count - 2)` instead of Stryker's
|
|
380
|
+
flat default of 5, computed from `os.cpu_count()`. Override precedence,
|
|
381
|
+
highest to lowest: a pass-through `-c`/`--concurrency` already present in
|
|
382
|
+
the args forwarded to Stryker (explicit caller intent, never overridden) >
|
|
383
|
+
the `--stryker-concurrency` CLI flag > the `STRYKER_MUTANT_CONCURRENCY`
|
|
384
|
+
env var > the computed `cores - 2` default. When a pass-through value
|
|
385
|
+
conflicts with an explicit `--stryker-concurrency`/env value, the wrapper
|
|
386
|
+
logs a one-line note to stderr naming which pass-through value overrode
|
|
387
|
+
which explicit value — the override is never silent.
|
|
388
|
+
|
|
389
|
+
`--stryker-concurrency`/`STRYKER_MUTANT_CONCURRENCY` is deliberately **not**
|
|
390
|
+
named `--concurrency`/`-c`: that spelling is reserved for (a) Stryker's own
|
|
391
|
+
pass-through flag — registering `-c` as a wrapper-owned option would make it
|
|
392
|
+
structurally impossible for a caller's pass-through `-c` to ever reach the
|
|
393
|
+
"already present" detection above — and (b) `mutation-kill`'s own
|
|
394
|
+
pre-existing `--concurrency` flag (worktree fan-out, a different dial at a
|
|
395
|
+
different layer) despite the shared "cores − 2" heuristic.
|
|
396
|
+
|
|
397
|
+
**CI/cgroup caveat:** `os.cpu_count()` reads the host/system core count, not
|
|
398
|
+
a container's cgroup quota. On resource-capped CI runners this can compute a
|
|
399
|
+
concurrency value higher than the container's actual allotment — pass an
|
|
400
|
+
explicit `--stryker-concurrency` value (or set `STRYKER_MUTANT_CONCURRENCY`)
|
|
401
|
+
rather than rely on the computed default in those environments.
|
|
402
|
+
|
|
403
|
+
## Slice runner
|
|
404
|
+
|
|
405
|
+
The plugin ships a third script, `csharp_stryker_net_slice_runner.py`, under
|
|
406
|
+
`plugins/dev-team/skills/mutation-testing/scripts/`, layering first-class
|
|
407
|
+
slicing and configurable slice-level parallelism (#561) on top of the
|
|
408
|
+
wrapper documented above. It imports `csharp_stryker_net_wrapper.py`
|
|
409
|
+
directly and reuses its `hide_sln`/`restore_sln`/`build_project`/
|
|
410
|
+
`run_stryker` primitives — the slice runner does not duplicate the
|
|
411
|
+
DOTNET_ROOT probe, the pre-build-before-hide ordering, or the signal-safe
|
|
412
|
+
Stryker subprocess handling; it only adds the fleet-level orchestration
|
|
413
|
+
around them.
|
|
414
|
+
|
|
415
|
+
### Invocation
|
|
416
|
+
|
|
417
|
+
```bash
|
|
418
|
+
python3 "${CLAUDE_PLUGIN_ROOT}/skills/mutation-testing/scripts/csharp_stryker_net_slice_runner.py" \
|
|
419
|
+
--slices-config mutation-slices.json \
|
|
420
|
+
--slice <name> # a single configured slice by name
|
|
421
|
+
--slice all # every configured slice, resuming past terminal ones
|
|
422
|
+
--sln Foo.sln \
|
|
423
|
+
--output-root StrykerOutput \
|
|
424
|
+
--total-workers auto
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### `slices:` config block
|
|
428
|
+
|
|
429
|
+
A top-level `slices` array in `mutation-slices.json` (JSON, not YAML — this
|
|
430
|
+
plugin's shipped scripts are stdlib-only Python, and `json` is stdlib while
|
|
431
|
+
YAML is not). Only `name` + `mutate` are required in this first cut; `kind`,
|
|
432
|
+
`mutation-level`, and `exclude-converged` are accepted and passed through
|
|
433
|
+
but reserved for #667's within-slice refinements — a typo in one of those
|
|
434
|
+
field names is not rejected — it falls into the generic passthrough below
|
|
435
|
+
and prints the unrecognized-key warning that guards against exactly this
|
|
436
|
+
(#2145) — it just isn't otherwise acted on yet.
|
|
437
|
+
|
|
438
|
+
Any other key is passed through verbatim into the slice's generated
|
|
439
|
+
`stryker-config.json` — most usefully `project`, naming the single source
|
|
440
|
+
`.csproj` under test (Stryker's own `-p`/`--project`/config `"project"`
|
|
441
|
+
key). Without it, Stryker auto-discovers and rebuilds every source project
|
|
442
|
+
transitively referenced by `test-projects` on **every** slice invocation,
|
|
443
|
+
regardless of that slice's `mutate` glob; set `project` to scope a slice to
|
|
444
|
+
just the one source project it actually mutates:
|
|
445
|
+
|
|
446
|
+
```json
|
|
447
|
+
{
|
|
448
|
+
"slices": [
|
|
449
|
+
{
|
|
450
|
+
"name": "validators",
|
|
451
|
+
"mutate": "**/Validators/**/*.cs",
|
|
452
|
+
"project": "src/Foo.Validators/Foo.Validators.csproj",
|
|
453
|
+
"kind": "logic",
|
|
454
|
+
"mutation-level": "Basic",
|
|
455
|
+
"exclude-converged": true
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
"name": "services",
|
|
459
|
+
"mutate": "**/Services/**/*.cs"
|
|
460
|
+
}
|
|
461
|
+
]
|
|
462
|
+
}
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
Each generated per-slice `stryker-config.json` inherits
|
|
466
|
+
`"coverage-analysis": "perTest"` by default (per #669's validated
|
|
467
|
+
recommendation above); pass a `--base-config` pointing at an existing
|
|
468
|
+
`stryker-config.json` whose `"coverage-analysis": "off"` should be
|
|
469
|
+
preserved (e.g. xunit.v3/MTP projects) — an explicit value in the base
|
|
470
|
+
config always wins over the per-slice default. A slice may also set its own
|
|
471
|
+
`"coverage-analysis"` key directly (the same generic passthrough `project`
|
|
472
|
+
uses) to override it for that one slice alone — intentional, for a mixed
|
|
473
|
+
solution where only some slices' projects are xunit.v3/MTP; an unrecognized
|
|
474
|
+
passthrough key (a typo, most commonly) prints a warning to stderr naming
|
|
475
|
+
the slice and the key, but is still applied unchanged.
|
|
476
|
+
|
|
477
|
+
### Output layout and the aggregate roll-up
|
|
478
|
+
|
|
479
|
+
Each slice writes its own report to
|
|
480
|
+
`<output-root>/slice-<name>/reports/mutation-report.json` (Stryker's native
|
|
481
|
+
JSON-reporter shape). After every slice in the run completes, the runner
|
|
482
|
+
reads each slice's report, sums per-status mutant counts, and writes one
|
|
483
|
+
aggregate roll-up to `<output-root>/aggregate-mutation-report.json` — the
|
|
484
|
+
stable, programmatic entry point for #667's glob-shrinking logic (or any
|
|
485
|
+
other tooling) instead of scraping per-slice reports individually.
|
|
486
|
+
|
|
487
|
+
### Resume by skipping terminal slices
|
|
488
|
+
|
|
489
|
+
A slice is **terminal** when its `mutation-report.json` exists, parses as
|
|
490
|
+
JSON, and has a non-empty `files` map — a partial file from a crashed mid-
|
|
491
|
+
run either fails to parse or has no `files` entries, so it is never
|
|
492
|
+
mistaken for a completed run. On `--slice all`, the runner skips every
|
|
493
|
+
terminal slice and logs `SKIPPED <name> — terminal report exists (use
|
|
494
|
+
--force to rerun)`; pass `--force` to rerun every selected slice
|
|
495
|
+
unconditionally, including terminal ones.
|
|
496
|
+
|
|
497
|
+
### Configurable slice-level parallelism
|
|
498
|
+
|
|
499
|
+
- `--total-workers N|auto` — the overall worker ceiling. `auto` (the
|
|
500
|
+
default) computes `max(2, cores / 2)`.
|
|
501
|
+
- `--parallel-slices N` / `--per-slice-concurrency N` — optional hints for
|
|
502
|
+
operators who want to fix one axis explicitly. When **both** are set, the
|
|
503
|
+
runner refuses (unless `--force`) when their product exceeds
|
|
504
|
+
`--total-workers`.
|
|
505
|
+
- When **neither** is set, the default split allocates slices first (up to
|
|
506
|
+
the configured slice count), then divides the remainder as per-slice
|
|
507
|
+
concurrency — this favours cross-slice parallelism over deeper
|
|
508
|
+
within-slice parallelism, matching #667's per-slice-convergence work.
|
|
509
|
+
- A `--total-workers` value over `cores − 1` is refused with an error
|
|
510
|
+
unless `--force` is passed, in which case it proceeds with a warning
|
|
511
|
+
instead — never silently oversubscribe the machine.
|
|
512
|
+
|
|
513
|
+
### `.sln` hide/restore is a fleet-level ceremony, done once
|
|
514
|
+
|
|
515
|
+
Only one Stryker instance can safely hide the shared `.sln` at a time — a
|
|
516
|
+
per-slice hide/restore would race across parallel slices. The slice runner
|
|
517
|
+
hides `.sln` **once**, before spawning any slice, and restores it **once**,
|
|
518
|
+
after every slice in the fleet has finished (success, failure, or
|
|
519
|
+
exception) — never per slice. Individual slice invocations run against the
|
|
520
|
+
already-hidden `.sln` and never touch the hide/restore state themselves.
|
|
521
|
+
|
|
522
|
+
### Rolled-up progress reporting
|
|
523
|
+
|
|
524
|
+
The runner prints one rolled-up progress line per slice-state transition,
|
|
525
|
+
e.g.:
|
|
526
|
+
|
|
527
|
+
```
|
|
528
|
+
slice 1/7 running, slice 2/7 running, slice 3/7 queued, slice 4/7 queued, ...
|
|
529
|
+
slice 1/7 done, slice 2/7 running, slice 3/7 running, slice 4/7 queued, ...
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
Each slice's state is one of `queued`, `running`, `done`, or `failed`
|
|
533
|
+
(non-zero Stryker exit code); the overall exit code is the worst
|
|
534
|
+
(highest, non-zero-preferred) of all slice exit codes.
|
|
535
|
+
|
|
536
|
+
## Incremental runs with `--since`
|
|
537
|
+
|
|
538
|
+
For fast iteration during Phase-4 test-fix work, add a `since` block to the dev shard config so Stryker only mutates source files that changed vs a reference (typically `main`):
|
|
539
|
+
|
|
540
|
+
```json
|
|
541
|
+
// stryker-config.shard-<name>.json — development / Phase 4 fix loop
|
|
542
|
+
{
|
|
543
|
+
"stryker-config": {
|
|
544
|
+
"since": {
|
|
545
|
+
"enabled": true,
|
|
546
|
+
"target": "main"
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
Run with the dev config for fast feedback:
|
|
553
|
+
|
|
554
|
+
```bash
|
|
555
|
+
export DOTNET_ROOT="${DOTNET_ROOT:-/opt/homebrew/opt/dotnet/libexec}"
|
|
556
|
+
dotnet build <solution> -c Debug --nologo
|
|
557
|
+
dotnet stryker --config-file stryker-config.shard-webapi.json
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
**Trap — verification runs must NOT use `since`.** `--since` limits mutations to **source** files that changed since the git ref. Test-file changes do **not** trigger source-file mutations, so a verification run through a `--since` config silently produces **0 results** — no mutants, no report, no useful signal. Always keep a **separate** verification config (`stryker-config.verification.json` or equivalent) that is identical to the dev shard config **except** for having no `since` block:
|
|
561
|
+
|
|
562
|
+
```bash
|
|
563
|
+
# Full verification — no --since; mutates every source file in scope
|
|
564
|
+
dotnet stryker --config-file stryker-config.verification.json -O StrykerOutput/verification
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
Adapter-side, `hooks/mutation_adapters/stryker_net.py` reads `STRYKER_SINCE_TARGET` when `CI` is not `true` and appends `--since:$STRYKER_SINCE_TARGET` to the command line. Set the env var on dev machines; leave it unset in CI so the gate always runs the full scan.
|
|
568
|
+
|
|
569
|
+
## Infrastructure exclusion `mutate` glob template
|
|
570
|
+
|
|
571
|
+
DI wiring, exception handlers, and generated code produce mutations that no test surface can kill — dragging the score down without providing any signal. Exclude them from the `mutate` glob in the shard config:
|
|
572
|
+
|
|
573
|
+
```json
|
|
574
|
+
// stryker-config.shard-webapi.json
|
|
575
|
+
{
|
|
576
|
+
"stryker-config": {
|
|
577
|
+
"mutate": [
|
|
578
|
+
"**/MyProject.WebAPI/**/*.cs",
|
|
579
|
+
"!**/Startup.cs",
|
|
580
|
+
"!**/Program.cs",
|
|
581
|
+
"!**/*ExceptionFilter.cs",
|
|
582
|
+
"!**/*ExceptionFormatter.cs",
|
|
583
|
+
"!**/*LoggerService.cs",
|
|
584
|
+
"!**/*.Designer.cs",
|
|
585
|
+
"!**/Validators/AddressValidator.cs"
|
|
586
|
+
]
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
Pairs with the mutation-kill agent's [infrastructure exclusion detection](../../../../agents/mutation-kill.md#infrastructure-exclusion-detection-before-the-loop-starts) — the agent flags candidates at baseline scan time; this template is what actually removes them from the mutation set.
|
|
592
|
+
|
|
593
|
+
The last entry (`!**/Validators/AddressValidator.cs`) is a **convergence-derived**
|
|
594
|
+
negation, not an infra-exclusion one — the mutation-kill agent's [convergence
|
|
595
|
+
history](../../../../agents/mutation-kill.md#convergence-history-across---all-invocations)
|
|
596
|
+
mechanism added it because that file already converged (or was excluded) at a
|
|
597
|
+
recorded commit that still matches the file's current last-commit SHA. The two
|
|
598
|
+
kinds of negation share the same `mutate` array but differ in permanence: the
|
|
599
|
+
Startup/Program/Filter/etc. negations above are **permanent** (infrastructure
|
|
600
|
+
never becomes testable by adding more tests), while convergence-derived
|
|
601
|
+
negations like `AddressValidator.cs` are **re-checked on every `--all`
|
|
602
|
+
invocation and can drop out** the moment the file's source changes — at that
|
|
603
|
+
point the entry goes stale and the file re-enters scope automatically.
|
|
604
|
+
|
|
605
|
+
## Score formula and NoCoverage
|
|
606
|
+
|
|
607
|
+
Stryker.NET's own score formula (v4.x):
|
|
608
|
+
|
|
609
|
+
```
|
|
610
|
+
score = (Killed + Timeout) / (Killed + Survived + Timeout + NoCoverage)
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
`NoCoverage` sits in the denominator even though those mutants are never executed. A file with 27 `NoCoverage` mutants at 0% score drags the overall score down more than a file with 20 `Survived` mutants at 70%. **Fix `NoCoverage` first** — any test that reaches the line kills a `NoCoverage` mutant, so ROI is higher than crafting value-specific assertions to kill hard `Survived` mutants. This mirrors the canonical [NoCoverage is a first-class signal](../../../../knowledge/mutation-score-formulas.md#nocoverage-is-a-first-class-signal) guidance, shared by the mutation-kill agent and the `/mutation-testing` skill.
|
|
614
|
+
|
|
615
|
+
## Per-mutant timeout flag
|
|
616
|
+
|
|
617
|
+
Configure in `stryker-config.yaml` (or the per-shard JSON config):
|
|
618
|
+
|
|
619
|
+
```yaml
|
|
620
|
+
timeout: 60000 # milliseconds
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
Default shipped: 60 000 ms. Set `timeout` to `timeout_seconds × 1000` (formula in [`SKILL.md`](../../SKILL.md) Step 1b). For xunit.v3 test projects, also set `additional-timeout: 30000` (see the xunit.v3 detection section above) — the two settings compose.
|
|
624
|
+
|
|
625
|
+
## Native report → schema mapping
|
|
626
|
+
|
|
627
|
+
Source: `StrykerOutput/<run>/reports/mutation-report.json` (same shape as JS Stryker). Map identically; `tool` is `"stryker-net"`.
|
|
628
|
+
|
|
629
|
+
```json
|
|
630
|
+
{
|
|
631
|
+
"schema_version": 1,
|
|
632
|
+
"tool": "stryker-net",
|
|
633
|
+
"scope": ["src/Calculator/Calculator.cs"],
|
|
634
|
+
"captured_at": "2026-06-19T14:31:00Z",
|
|
635
|
+
"total": 44,
|
|
636
|
+
"killed": 38,
|
|
637
|
+
"survived": 4,
|
|
638
|
+
"equivalent": 2,
|
|
639
|
+
"survivors": [
|
|
640
|
+
{ "file": "src/Calculator/Calculator.cs", "line": 27, "operator": "ConditionalBoundary", "status": "survived" }
|
|
641
|
+
]
|
|
642
|
+
}
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
## Language-specific notes
|
|
646
|
+
|
|
647
|
+
### Shard-aware execution for large repos
|
|
648
|
+
|
|
649
|
+
For C# repos, `dotnet stryker` against the whole solution can take 60–90 minutes. The mutation gate adapter (`hooks/mutation_adapters/stryker_net.py`) will time out and skip rather than run. The fix is **shard configs** generated by `stryker-setup.py` (from the [nextgen-test-upgrade-process](https://dev.azure.com/acispeedpayportfolio/acispeedpay/_git/nextgen-test-upgrade-process) toolkit):
|
|
650
|
+
|
|
651
|
+
```bash
|
|
652
|
+
export DOTNET_ROOT="${DOTNET_ROOT:-/opt/homebrew/opt/dotnet/libexec}"
|
|
653
|
+
# One-time setup in the target repo — generates stryker-config.shard-*.json
|
|
654
|
+
python3 /path/to/nextgen-test-upgrade-process/scripts/stryker-setup.py
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
Once shard configs exist, the adapter automatically:
|
|
658
|
+
|
|
659
|
+
1. Detects which shard covers the changed file (by matching the shard's `mutate` path prefix).
|
|
660
|
+
2. Passes `--config-file stryker-config.shard-<name>.json` to scope Stryker to that source project + its tests.
|
|
661
|
+
3. Further narrows with `--mutate "**/ChangedFile.cs"` so only the one changed file is mutated.
|
|
662
|
+
4. Writes results to `StrykerOutput/gate-shard/` (via `-O`) so gate runs don't overwrite full pipeline reports.
|
|
663
|
+
|
|
664
|
+
This drops the wall-clock time from 60–90 min (whole repo) to **5–15 min** (one file in one shard), which fits within the adapter's 600-second outer timeout.
|
|
665
|
+
|
|
666
|
+
**Without shard configs**, the adapter falls back to `stryker-config.json` (master config). If the master config also mutates the whole codebase this will still time out — run `stryker-setup.py` to fix it.
|
|
667
|
+
|
|
668
|
+
### Batch improvement pipeline
|
|
669
|
+
|
|
670
|
+
For the full improvement pipeline (not the per-test gate), use `stryker-pipeline.py` instead of bare `dotnet stryker`. It runs shards sequentially, fixes survivors with `mutation-agent.py` using the Claude Code CLI, and is the right tool for batch mutation-score improvement. Pre-build first, then invoke:
|
|
671
|
+
|
|
672
|
+
```bash
|
|
673
|
+
export DOTNET_ROOT="${DOTNET_ROOT:-/opt/homebrew/opt/dotnet/libexec}"
|
|
674
|
+
dotnet build <solution> -c Debug --nologo
|
|
675
|
+
python3 /path/to/nextgen-test-upgrade-process/scripts/stryker-pipeline.py
|
|
676
|
+
```
|