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,596 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Operator decision gate for the xunit.v3 / Stryker shim block (#1791).
|
|
3
|
+
|
|
4
|
+
Detection of the xunit.v3-blocks-Stryker problem already existed in three
|
|
5
|
+
places — the ``stryker_xunit_shim_guard.py`` PreToolUse hook,
|
|
6
|
+
``xunit_v3_feature_detector.py``, and ``mutation_feasibility_gate.py`` — but
|
|
7
|
+
none of it guaranteed the **operator** saw a clear explanation and a set of
|
|
8
|
+
choices. The guard printed what it scaffolded and blocked; the detector
|
|
9
|
+
classified constructs for a gate that was never wired end-to-end; the
|
|
10
|
+
feasibility gate recorded a fixed waiver string. All three are informative
|
|
11
|
+
for a report, not a decision point: the operator could discover after a
|
|
12
|
+
multi-hour run that the shim was silently built, silently declined, or
|
|
13
|
+
silently degraded, and never learn what their options had been.
|
|
14
|
+
|
|
15
|
+
This module is that decision point. It has two halves, both pure/stdlib:
|
|
16
|
+
|
|
17
|
+
1. **The question.** :func:`build_question` turns the detector's per-construct
|
|
18
|
+
classification into an :class:`OperatorQuestion` — what is blocking (per
|
|
19
|
+
construct, per file, with coverage impact) plus the four remediation
|
|
20
|
+
options with their tradeoffs. :func:`render_question` renders it for the
|
|
21
|
+
guard's block body and the feasibility gate's ``ask-operator`` payload, so
|
|
22
|
+
both decision points speak with one voice.
|
|
23
|
+
|
|
24
|
+
2. **The guarantee.** A rendered question is still just text an agent could
|
|
25
|
+
paraphrase or skip. What makes the gate enforceable is that the guard stays
|
|
26
|
+
blocked until the operator's choice is *recorded* — :func:`record_decision`
|
|
27
|
+
writes it, :func:`decision_for` reads it back, and a decision only covers
|
|
28
|
+
the blocker set it was made about (:attr:`OperatorQuestion.fingerprint`),
|
|
29
|
+
so a newly-appeared blocker re-asks instead of riding on a stale answer.
|
|
30
|
+
|
|
31
|
+
The four options mirror the issue verbatim: ``port`` the flagged files,
|
|
32
|
+
``exclude`` them from the shim's compile set, ``skip`` (temporarily
|
|
33
|
+
deactivate) just the offending tests, or ``degrade`` to the no-shim floor.
|
|
34
|
+
|
|
35
|
+
Version scope (#2184): this whole gate is a < 5.0.0 concern.
|
|
36
|
+
``stryker_xunit_shim_guard.py`` silent-passes a known >= 5.0.0 install
|
|
37
|
+
before ever reaching this module, since ``-t mtp`` +
|
|
38
|
+
``coverage-analysis: perTest`` observes kills through xunit.v3 directly on
|
|
39
|
+
that version and above (stryker-net#3752) — no shim, no port/exclude/skip
|
|
40
|
+
tradeoff, and no degrade fallback to weigh. An undetermined version still
|
|
41
|
+
fails closed to this gate.
|
|
42
|
+
|
|
43
|
+
Audit trail (#1870): the decision store on its own is silent — the same
|
|
44
|
+
agent the gate constrains can record its own choice (most plausibly
|
|
45
|
+
``exclude``, narrowing mutation coverage) with nothing else in the harness
|
|
46
|
+
ever seeing it happen. :func:`record_decision` and :func:`decision_for`
|
|
47
|
+
each emit a `boundary_events` entry (a "record"-decision `matched_rule` of
|
|
48
|
+
`xunit-v3-shim-decision-record-<choice>` on write, `-honor-<choice>` when a
|
|
49
|
+
stored decision is read back and used to drive the guard's outcome), bound
|
|
50
|
+
to the question's `fingerprint` as `subject_hash` — the same audit stream
|
|
51
|
+
`hooks/pre_commit_review.py`'s dispatch-ledger corroboration is reviewed
|
|
52
|
+
from. This does not stop a self-recorded `exclude` from taking effect (the
|
|
53
|
+
operator's call is still trusted, per this module's whole design) — it
|
|
54
|
+
makes the choice visible to anyone auditing the stream, closing the
|
|
55
|
+
"nothing else in the harness ever seeing it happen" gap #1870 raised.
|
|
56
|
+
|
|
57
|
+
Formerly, ``DEV_TEAM_XUNIT3_SHIM_DECISION_FILE`` let any caller relocate the
|
|
58
|
+
decision store at runtime with no audit trail on either the record or honor
|
|
59
|
+
path — dropped entirely (#1870): no legitimate caller needs to relocate the
|
|
60
|
+
store, so removing the seam closes the unaudited-relocation vector outright
|
|
61
|
+
rather than trying to retrofit an audit onto it. The store's location is
|
|
62
|
+
always ``artifact_paths.resolve_file(DECISION_CATEGORY, DECISION_FILENAME,
|
|
63
|
+
cwd)``.
|
|
64
|
+
|
|
65
|
+
Stdlib-only. See docs/python-hook-contract.md.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
from __future__ import annotations
|
|
69
|
+
|
|
70
|
+
import argparse
|
|
71
|
+
import hashlib
|
|
72
|
+
import json
|
|
73
|
+
import sys
|
|
74
|
+
from collections.abc import Iterable, Sequence
|
|
75
|
+
from dataclasses import dataclass
|
|
76
|
+
from datetime import datetime, timezone
|
|
77
|
+
from pathlib import Path
|
|
78
|
+
|
|
79
|
+
_LIB_DIR = Path(__file__).resolve().parent
|
|
80
|
+
if str(_LIB_DIR) not in sys.path: # pragma: no cover - import bootstrap
|
|
81
|
+
sys.path.insert(0, str(_LIB_DIR))
|
|
82
|
+
|
|
83
|
+
import artifact_paths
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
from boundary_events import emit_boundary_event as _emit_boundary_event
|
|
87
|
+
except ImportError: # pragma: no cover - degraded fallback, hooks/lib unreachable
|
|
88
|
+
|
|
89
|
+
def _emit_boundary_event(*_args, **_kwargs) -> None: # type: ignore[misc]
|
|
90
|
+
return None
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
#: Where a recorded choice lives, relative to `.claude/`.
|
|
94
|
+
DECISION_CATEGORY = "metrics"
|
|
95
|
+
DECISION_FILENAME = "xunit-v3-shim-decisions.json"
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@dataclass(frozen=True)
|
|
99
|
+
class Option:
|
|
100
|
+
"""One remediation the operator can choose, with its cost stated.
|
|
101
|
+
|
|
102
|
+
``tradeoff`` is not decoration: the whole point of the gate is that the
|
|
103
|
+
operator picks with the cost in view, so an option without one is a
|
|
104
|
+
non-choice dressed up as a choice.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
id: str
|
|
108
|
+
label: str
|
|
109
|
+
tradeoff: str
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
#: The four choices, in the issue's order — cheapest/most-faithful first,
|
|
113
|
+
#: the measurement floor last. `degrade` is deliberately NOT the default:
|
|
114
|
+
#: silently taking it on the operator's behalf is the defect this gate fixes.
|
|
115
|
+
REMEDIATION_OPTIONS: tuple[Option, ...] = (
|
|
116
|
+
Option(
|
|
117
|
+
id="port",
|
|
118
|
+
label="Port the flagged files to v2-compatible syntax",
|
|
119
|
+
tradeoff="Cheapest when only a couple of files/constructs are flagged, and "
|
|
120
|
+
"the only option that leaves mutation coverage complete. Costs test edits "
|
|
121
|
+
"in the real project (the shim links the same sources, so one edit serves "
|
|
122
|
+
"both) and each replacement must still compile under v3.",
|
|
123
|
+
),
|
|
124
|
+
Option(
|
|
125
|
+
id="exclude",
|
|
126
|
+
label="Exclude the flagged files from the shim's compile set",
|
|
127
|
+
tradeoff="No test edits — generate_shim.py --compile-exclude drops them and "
|
|
128
|
+
"the shim measures the rest. The excluded files stay UNMEASURED by "
|
|
129
|
+
"mutation, so every mutant they alone would have killed shows up as a "
|
|
130
|
+
"survivor. Safe for coverage-neutral hits, blinding for coverage-bearing "
|
|
131
|
+
"ones.",
|
|
132
|
+
),
|
|
133
|
+
Option(
|
|
134
|
+
id="skip",
|
|
135
|
+
label="Temporarily deactivate/skip just the offending tests",
|
|
136
|
+
tradeoff="Deactivate the tests instead of rewriting what they assert — a "
|
|
137
|
+
"smaller edit than a full port. It clears the gate ONLY where the "
|
|
138
|
+
"deactivation itself removes the offending construct, e.g. "
|
|
139
|
+
'[Fact(Explicit = true)] becoming [Fact(Skip = "...")]. A construct in the '
|
|
140
|
+
"test BODY (Assert.Skip, TestContext) or on a data attribute ([AutoData], "
|
|
141
|
+
"TheoryDataRow) stays in the source the shim links, so deactivating alone "
|
|
142
|
+
"will not make it compile — those need port or exclude. The deactivated "
|
|
143
|
+
"tests stop protecting their code meanwhile: scaffolding to undo at "
|
|
144
|
+
"teardown, not a permanent change.",
|
|
145
|
+
),
|
|
146
|
+
Option(
|
|
147
|
+
id="degrade",
|
|
148
|
+
label="Degrade to the no-shim floor (single slow advisory pass)",
|
|
149
|
+
tradeoff="Drives the REAL v3 suite (dotnet-stryker -t mtp with "
|
|
150
|
+
"coverage-analysis off), so nothing is excluded and nothing is edited — "
|
|
151
|
+
"but it is whole-suite-per-mutant, so expect a single, much slower "
|
|
152
|
+
"advisory pass and no mutant-kill loop.",
|
|
153
|
+
),
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
VALID_CHOICES: tuple[str, ...] = tuple(option.id for option in REMEDIATION_OPTIONS)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@dataclass(frozen=True)
|
|
160
|
+
class ConstructGroup:
|
|
161
|
+
"""One classified construct rolled up across the files that use it."""
|
|
162
|
+
|
|
163
|
+
construct: str
|
|
164
|
+
compile_ability: str
|
|
165
|
+
coverage_impact: str
|
|
166
|
+
count: int
|
|
167
|
+
files: tuple[str, ...]
|
|
168
|
+
example: str
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
@dataclass(frozen=True)
|
|
172
|
+
class Blocker:
|
|
173
|
+
"""One detector finding, normalised to this module's shape."""
|
|
174
|
+
|
|
175
|
+
file: str
|
|
176
|
+
line: int
|
|
177
|
+
construct: str
|
|
178
|
+
compile_ability: str
|
|
179
|
+
coverage_impact: str
|
|
180
|
+
snippet: str
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@dataclass(frozen=True)
|
|
184
|
+
class OperatorQuestion:
|
|
185
|
+
"""The always-fires question: what blocks, and which four ways out."""
|
|
186
|
+
|
|
187
|
+
project: str
|
|
188
|
+
blockers: tuple[Blocker, ...]
|
|
189
|
+
breakdown: tuple[ConstructGroup, ...]
|
|
190
|
+
files: tuple[str, ...]
|
|
191
|
+
unclassified_files: tuple[str, ...]
|
|
192
|
+
fingerprint: str
|
|
193
|
+
options: tuple[Option, ...] = REMEDIATION_OPTIONS
|
|
194
|
+
|
|
195
|
+
@property
|
|
196
|
+
def blocking(self) -> bool:
|
|
197
|
+
"""True when there is something to ask about at all."""
|
|
198
|
+
return bool(self.blockers or self.unclassified_files)
|
|
199
|
+
|
|
200
|
+
@property
|
|
201
|
+
def bearing_count(self) -> int:
|
|
202
|
+
return sum(1 for b in self.blockers if b.coverage_impact == "bearing")
|
|
203
|
+
|
|
204
|
+
@property
|
|
205
|
+
def neutral_count(self) -> int:
|
|
206
|
+
return sum(1 for b in self.blockers if b.coverage_impact == "neutral")
|
|
207
|
+
|
|
208
|
+
@property
|
|
209
|
+
def headline(self) -> str:
|
|
210
|
+
"""The one-sentence "what's blocking" the issue asks for by example."""
|
|
211
|
+
if not self.blocking:
|
|
212
|
+
return (
|
|
213
|
+
f"No shim-breaking xunit.v3 constructs in '{self.project}' — "
|
|
214
|
+
"the v2 shim path is viable as-is."
|
|
215
|
+
)
|
|
216
|
+
file_count = len(set(self.files) | set(self.unclassified_files))
|
|
217
|
+
names = ", ".join(group.construct for group in self.breakdown)
|
|
218
|
+
if self.unclassified_files:
|
|
219
|
+
names = f"{names}, unclassified" if names else "unclassified"
|
|
220
|
+
plural = "s" if file_count != 1 else ""
|
|
221
|
+
return (
|
|
222
|
+
f"{file_count} test file{plural} in '{self.project}' use "
|
|
223
|
+
f"{names}, which the xunit.v2 shim can't compile."
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
def as_dict(self) -> dict:
|
|
227
|
+
return {
|
|
228
|
+
"project": self.project,
|
|
229
|
+
"headline": self.headline,
|
|
230
|
+
"fingerprint": self.fingerprint,
|
|
231
|
+
"files": list(self.files),
|
|
232
|
+
"unclassified_files": list(self.unclassified_files),
|
|
233
|
+
"bearing_count": self.bearing_count,
|
|
234
|
+
"neutral_count": self.neutral_count,
|
|
235
|
+
"breakdown": [
|
|
236
|
+
{
|
|
237
|
+
"construct": g.construct,
|
|
238
|
+
"compile_ability": g.compile_ability,
|
|
239
|
+
"coverage_impact": g.coverage_impact,
|
|
240
|
+
"count": g.count,
|
|
241
|
+
"files": list(g.files),
|
|
242
|
+
"example": g.example,
|
|
243
|
+
}
|
|
244
|
+
for g in self.breakdown
|
|
245
|
+
],
|
|
246
|
+
"options": [
|
|
247
|
+
{"id": o.id, "label": o.label, "tradeoff": o.tradeoff}
|
|
248
|
+
for o in self.options
|
|
249
|
+
],
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _as_blocker(finding) -> Blocker:
|
|
254
|
+
"""Accept either the detector's dataclass or its ``--json`` dict form."""
|
|
255
|
+
get = finding.get if isinstance(finding, dict) else lambda k, d=None: getattr(finding, k, d)
|
|
256
|
+
try:
|
|
257
|
+
line = int(get("line", 0) or 0)
|
|
258
|
+
except (TypeError, ValueError):
|
|
259
|
+
line = 0
|
|
260
|
+
return Blocker(
|
|
261
|
+
file=str(get("file", "") or ""),
|
|
262
|
+
line=line,
|
|
263
|
+
construct=str(get("construct", "") or ""),
|
|
264
|
+
compile_ability=str(get("compile_ability", "") or ""),
|
|
265
|
+
coverage_impact=str(get("coverage_impact", "") or ""),
|
|
266
|
+
snippet=str(get("snippet", "") or ""),
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def _dedup(values: Iterable[str]) -> tuple[str, ...]:
|
|
271
|
+
"""First-seen order, deduped — mirrors the detector's own file ordering so
|
|
272
|
+
the operator sees the same sequence in both tools."""
|
|
273
|
+
seen: list[str] = []
|
|
274
|
+
for value in values:
|
|
275
|
+
if value and value not in seen:
|
|
276
|
+
seen.append(value)
|
|
277
|
+
return tuple(seen)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def _breakdown(blockers: Sequence[Blocker]) -> tuple[ConstructGroup, ...]:
|
|
281
|
+
order: list[str] = []
|
|
282
|
+
grouped: dict[str, list[Blocker]] = {}
|
|
283
|
+
for blocker in blockers:
|
|
284
|
+
if blocker.construct not in grouped:
|
|
285
|
+
grouped[blocker.construct] = []
|
|
286
|
+
order.append(blocker.construct)
|
|
287
|
+
grouped[blocker.construct].append(blocker)
|
|
288
|
+
groups: list[ConstructGroup] = []
|
|
289
|
+
for construct in order:
|
|
290
|
+
members = grouped[construct]
|
|
291
|
+
groups.append(
|
|
292
|
+
ConstructGroup(
|
|
293
|
+
construct=construct,
|
|
294
|
+
compile_ability=members[0].compile_ability,
|
|
295
|
+
coverage_impact=members[0].coverage_impact,
|
|
296
|
+
count=len(members),
|
|
297
|
+
files=_dedup(m.file for m in members),
|
|
298
|
+
example=members[0].snippet,
|
|
299
|
+
)
|
|
300
|
+
)
|
|
301
|
+
return tuple(groups)
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def fingerprint(
|
|
305
|
+
blockers: Sequence[Blocker], unclassified_files: Sequence[str] = ()
|
|
306
|
+
) -> str:
|
|
307
|
+
"""A stable digest of *which* blockers exist, not where they sit.
|
|
308
|
+
|
|
309
|
+
Deliberately excludes line numbers: an unrelated edit that shifts a
|
|
310
|
+
flagged line must not invalidate a decision the operator already made,
|
|
311
|
+
while a genuinely new blocking file or construct must.
|
|
312
|
+
"""
|
|
313
|
+
keys = sorted({f"{b.file}::{b.construct}" for b in blockers})
|
|
314
|
+
keys += sorted(f"{f}::unclassified" for f in set(unclassified_files))
|
|
315
|
+
digest = hashlib.sha256("\n".join(keys).encode("utf-8")).hexdigest()
|
|
316
|
+
return digest[:16]
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def build_question(
|
|
320
|
+
project: str,
|
|
321
|
+
findings: Iterable,
|
|
322
|
+
unclassified_files: Sequence[str] = (),
|
|
323
|
+
) -> OperatorQuestion:
|
|
324
|
+
"""Compose the operator question from the detector's classification."""
|
|
325
|
+
blockers = tuple(_as_blocker(f) for f in findings)
|
|
326
|
+
unclassified = _dedup(unclassified_files)
|
|
327
|
+
return OperatorQuestion(
|
|
328
|
+
project=project,
|
|
329
|
+
blockers=blockers,
|
|
330
|
+
breakdown=_breakdown(blockers),
|
|
331
|
+
files=_dedup(b.file for b in blockers),
|
|
332
|
+
unclassified_files=unclassified,
|
|
333
|
+
fingerprint=fingerprint(blockers, unclassified),
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def render_question(
|
|
338
|
+
question: OperatorQuestion, *, record_command: str | None = None
|
|
339
|
+
) -> list[str]:
|
|
340
|
+
"""Render the question as operator-facing lines.
|
|
341
|
+
|
|
342
|
+
One renderer for both decision points (the guard's block body and the
|
|
343
|
+
feasibility gate's ``ask-operator`` payload) so the operator cannot get a
|
|
344
|
+
different story depending on which one fired.
|
|
345
|
+
"""
|
|
346
|
+
if not question.blocking:
|
|
347
|
+
return [question.headline]
|
|
348
|
+
|
|
349
|
+
lines = [question.headline, ""]
|
|
350
|
+
lines.append("What's blocking:")
|
|
351
|
+
for group in question.breakdown:
|
|
352
|
+
lines.append(
|
|
353
|
+
f" - {group.construct} ({group.compile_ability}, "
|
|
354
|
+
f"coverage-{group.coverage_impact}) — {group.count} hit(s) in "
|
|
355
|
+
f"{len(group.files)} file(s)"
|
|
356
|
+
)
|
|
357
|
+
for blocker in question.blockers:
|
|
358
|
+
if blocker.construct == group.construct:
|
|
359
|
+
lines.append(f" {blocker.file}:{blocker.line} {blocker.snippet}")
|
|
360
|
+
if question.unclassified_files:
|
|
361
|
+
lines.append(
|
|
362
|
+
" - unclassified v3-only usage (needs manual triage — the detector "
|
|
363
|
+
"flagged the file but cannot classify the construct):"
|
|
364
|
+
)
|
|
365
|
+
lines += [f" {name}" for name in question.unclassified_files]
|
|
366
|
+
lines.append("")
|
|
367
|
+
if question.bearing_count:
|
|
368
|
+
lines.append(
|
|
369
|
+
f"{question.bearing_count} of these hit(s) are coverage-BEARING: "
|
|
370
|
+
"excluding them leaves their lines unmeasured, so mutants there will "
|
|
371
|
+
"report as survivors."
|
|
372
|
+
)
|
|
373
|
+
if question.neutral_count:
|
|
374
|
+
lines.append(
|
|
375
|
+
f"{question.neutral_count} hit(s) are coverage-NEUTRAL (skipped by "
|
|
376
|
+
"default), so excluding those changes no coverage."
|
|
377
|
+
)
|
|
378
|
+
lines.append("")
|
|
379
|
+
lines.append("Your options (pick one — this is the operator's call):")
|
|
380
|
+
for option in question.options:
|
|
381
|
+
lines.append(f" {option.id}: {option.label}")
|
|
382
|
+
lines.append(f" Tradeoff: {option.tradeoff}")
|
|
383
|
+
lines.append("")
|
|
384
|
+
lines.append(
|
|
385
|
+
"Present these four options to the operator (AskUserQuestion) and let "
|
|
386
|
+
"them pick. Do NOT choose on their behalf, and do not silently take the "
|
|
387
|
+
"degrade path — that is the failure this gate exists to prevent."
|
|
388
|
+
)
|
|
389
|
+
if record_command:
|
|
390
|
+
lines.append("Then record their choice so this gate can let the run through:")
|
|
391
|
+
lines.append(f" {record_command}")
|
|
392
|
+
return lines
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
# --- decision record --------------------------------------------------------
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def decision_store_path(cwd: Path | str | None = None) -> Path:
|
|
399
|
+
"""Where recorded choices live — always
|
|
400
|
+
`artifact_paths.resolve_file(DECISION_CATEGORY, DECISION_FILENAME, cwd)`.
|
|
401
|
+
|
|
402
|
+
No env-var override (#1870): a prior `DEV_TEAM_XUNIT3_SHIM_DECISION_FILE`
|
|
403
|
+
seam let any caller relocate the store at runtime with no audit trail on
|
|
404
|
+
either side — removed rather than audited, since no legitimate caller
|
|
405
|
+
needs it.
|
|
406
|
+
"""
|
|
407
|
+
return artifact_paths.resolve_file(DECISION_CATEGORY, DECISION_FILENAME, cwd)
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def _emit_decision_event(kind: str, entry: dict, cwd: Path | str | None) -> None:
|
|
411
|
+
"""Shared boundary-event emission for the record and honor paths (#1870).
|
|
412
|
+
|
|
413
|
+
`kind` is `"record"` (a fresh write in `record_decision`) or `"honor"` (a
|
|
414
|
+
stored decision read back and used to drive the guard's outcome in
|
|
415
|
+
`decision_for`) — folded into `matched_rule` as
|
|
416
|
+
`xunit-v3-shim-decision-<kind>-<choice>`, a closed vocabulary derived
|
|
417
|
+
from `VALID_CHOICES` (never free text). Bound to the entry's own
|
|
418
|
+
`fingerprint` as `subject_hash`, mirroring how the dispatch-ledger
|
|
419
|
+
corroboration binds its own evidence to a content hash — so an audit of
|
|
420
|
+
the stream can tell which blocker set a given decision covered.
|
|
421
|
+
|
|
422
|
+
Fail-open, matching `boundary_events.emit_boundary_event`'s own
|
|
423
|
+
contract: a malformed `choice` (should be unreachable given both
|
|
424
|
+
callers' own validation) or any emission failure is swallowed, never
|
|
425
|
+
raised — this is telemetry, not a gate.
|
|
426
|
+
"""
|
|
427
|
+
choice = entry.get("choice")
|
|
428
|
+
if choice not in VALID_CHOICES:
|
|
429
|
+
return
|
|
430
|
+
try:
|
|
431
|
+
_emit_boundary_event(
|
|
432
|
+
cwd,
|
|
433
|
+
"xunit_v3_operator_gate",
|
|
434
|
+
"Bash",
|
|
435
|
+
"record",
|
|
436
|
+
f"xunit-v3-shim-decision-{kind}-{choice}",
|
|
437
|
+
subject_hash=entry.get("fingerprint"),
|
|
438
|
+
)
|
|
439
|
+
except Exception: # noqa: BLE001, S110 - fail-open by design
|
|
440
|
+
pass
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def _read_store(cwd: Path | str | None = None) -> dict:
|
|
444
|
+
path = decision_store_path(cwd)
|
|
445
|
+
try:
|
|
446
|
+
raw = path.read_text(encoding="utf-8")
|
|
447
|
+
except (OSError, ValueError):
|
|
448
|
+
return {}
|
|
449
|
+
try:
|
|
450
|
+
data = json.loads(raw)
|
|
451
|
+
except (json.JSONDecodeError, ValueError):
|
|
452
|
+
return {}
|
|
453
|
+
return data if isinstance(data, dict) else {}
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
def record_decision(
|
|
457
|
+
project: str,
|
|
458
|
+
choice: str,
|
|
459
|
+
cwd: Path | str | None = None,
|
|
460
|
+
*,
|
|
461
|
+
fingerprint: str,
|
|
462
|
+
files: Sequence[str] = (),
|
|
463
|
+
note: str | None = None,
|
|
464
|
+
) -> dict:
|
|
465
|
+
"""Persist the operator's choice for ``project``. Returns the entry.
|
|
466
|
+
|
|
467
|
+
Raises ``ValueError`` on a choice outside :data:`VALID_CHOICES` — an
|
|
468
|
+
unrecognised answer must be re-asked, never coerced into one of the four —
|
|
469
|
+
and on a missing ``fingerprint``, without which the entry would cover no
|
|
470
|
+
blocker set at all (see :func:`decision_for`). Refusing loudly at write time
|
|
471
|
+
beats writing a record the operator believes answered the gate while the
|
|
472
|
+
gate keeps asking.
|
|
473
|
+
"""
|
|
474
|
+
if choice not in VALID_CHOICES:
|
|
475
|
+
raise ValueError(
|
|
476
|
+
f"invalid choice {choice!r}: expected one of {', '.join(VALID_CHOICES)}"
|
|
477
|
+
)
|
|
478
|
+
if not fingerprint:
|
|
479
|
+
raise ValueError(
|
|
480
|
+
"a fingerprint is required: it scopes the decision to the blockers "
|
|
481
|
+
"the operator actually saw. Use the value the guard printed."
|
|
482
|
+
)
|
|
483
|
+
entry = {
|
|
484
|
+
"project": project,
|
|
485
|
+
"choice": choice,
|
|
486
|
+
"fingerprint": fingerprint,
|
|
487
|
+
"files": list(files),
|
|
488
|
+
"note": note,
|
|
489
|
+
"recorded_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
|
490
|
+
}
|
|
491
|
+
store = _read_store(cwd)
|
|
492
|
+
store[project] = entry
|
|
493
|
+
path = decision_store_path(cwd)
|
|
494
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
495
|
+
path.write_text(json.dumps(store, indent=2) + "\n", encoding="utf-8")
|
|
496
|
+
_emit_decision_event("record", entry, cwd)
|
|
497
|
+
return entry
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
def read_decision(project: str, cwd: Path | str | None = None) -> dict | None:
|
|
501
|
+
"""The raw recorded entry for ``project``, ignoring fingerprint staleness."""
|
|
502
|
+
entry = _read_store(cwd).get(project)
|
|
503
|
+
return entry if isinstance(entry, dict) else None
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
def decision_for(
|
|
507
|
+
question: OperatorQuestion, cwd: Path | str | None = None
|
|
508
|
+
) -> dict | None:
|
|
509
|
+
"""The decision that covers ``question``, or None when the operator must
|
|
510
|
+
(re-)decide.
|
|
511
|
+
|
|
512
|
+
Fails closed on every axis, because every "yes" here is a run that proceeds
|
|
513
|
+
without asking:
|
|
514
|
+
|
|
515
|
+
- A recorded choice covers only the blocker set it was made about. When the
|
|
516
|
+
fingerprint differs — or is absent, which would otherwise make the entry a
|
|
517
|
+
blanket answer covering every future blocker set — the operator has not
|
|
518
|
+
seen these blockers, and riding on the old answer would silently exclude
|
|
519
|
+
something they never agreed to.
|
|
520
|
+
- A stored ``choice`` outside :data:`VALID_CHOICES` (or missing entirely)
|
|
521
|
+
re-asks rather than being coerced into whichever branch happens to be
|
|
522
|
+
last. ``record_decision`` rejects those on the write side, so reaching
|
|
523
|
+
here means a hand-edited or externally-produced store — precisely why the
|
|
524
|
+
read side is where the guarantee has to hold.
|
|
525
|
+
|
|
526
|
+
Emits a `boundary_events` "honor" entry (#1870) whenever a decision
|
|
527
|
+
actually covers ``question`` and is about to drive the guard's outcome —
|
|
528
|
+
every caller that reaches a non-None return here is *using* the decision,
|
|
529
|
+
so this is the single choke point for "on every honor path" without each
|
|
530
|
+
call site (today: `stryker_xunit_shim_guard.py`) needing its own emission.
|
|
531
|
+
"""
|
|
532
|
+
entry = read_decision(question.project, cwd)
|
|
533
|
+
if entry is None:
|
|
534
|
+
return None
|
|
535
|
+
if entry.get("choice") not in VALID_CHOICES:
|
|
536
|
+
return None
|
|
537
|
+
if entry.get("fingerprint") != question.fingerprint:
|
|
538
|
+
return None
|
|
539
|
+
_emit_decision_event("honor", entry, cwd)
|
|
540
|
+
return entry
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
def _cli(argv: Sequence[str]) -> int:
|
|
544
|
+
parser = argparse.ArgumentParser(
|
|
545
|
+
description="Record/inspect the operator's xunit.v3 shim remediation choice."
|
|
546
|
+
)
|
|
547
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
548
|
+
|
|
549
|
+
rec = sub.add_parser("record", help="record the operator's choice")
|
|
550
|
+
rec.add_argument("--project", required=True, help="test project name (csproj stem)")
|
|
551
|
+
rec.add_argument("--choice", required=True, choices=list(VALID_CHOICES))
|
|
552
|
+
rec.add_argument(
|
|
553
|
+
"--fingerprint",
|
|
554
|
+
required=True,
|
|
555
|
+
help="blocker-set fingerprint, as printed by the guard's block body — "
|
|
556
|
+
"required, since it is what scopes the decision to the blockers the "
|
|
557
|
+
"operator saw",
|
|
558
|
+
)
|
|
559
|
+
rec.add_argument(
|
|
560
|
+
"--file", action="append", default=[], help="flagged file the choice covers"
|
|
561
|
+
)
|
|
562
|
+
rec.add_argument("--note", default=None, help="free-text rationale")
|
|
563
|
+
|
|
564
|
+
chk = sub.add_parser("check", help="print the recorded choice, if any")
|
|
565
|
+
chk.add_argument("--project", required=True)
|
|
566
|
+
|
|
567
|
+
sub.add_parser("options", help="print the four remediation options")
|
|
568
|
+
|
|
569
|
+
args = parser.parse_args(list(argv))
|
|
570
|
+
|
|
571
|
+
if args.command == "options":
|
|
572
|
+
for option in REMEDIATION_OPTIONS:
|
|
573
|
+
print(f"{option.id}: {option.label}")
|
|
574
|
+
print(f" Tradeoff: {option.tradeoff}")
|
|
575
|
+
return 0
|
|
576
|
+
|
|
577
|
+
if args.command == "record":
|
|
578
|
+
entry = record_decision(
|
|
579
|
+
args.project,
|
|
580
|
+
args.choice,
|
|
581
|
+
fingerprint=args.fingerprint,
|
|
582
|
+
files=args.file,
|
|
583
|
+
note=args.note,
|
|
584
|
+
)
|
|
585
|
+
print(json.dumps(entry, indent=2))
|
|
586
|
+
return 0
|
|
587
|
+
|
|
588
|
+
entry = read_decision(args.project)
|
|
589
|
+
if entry is None:
|
|
590
|
+
return 1
|
|
591
|
+
print(json.dumps(entry, indent=2))
|
|
592
|
+
return 0
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
if __name__ == "__main__": # pragma: no cover
|
|
596
|
+
sys.exit(_cli(sys.argv[1:]))
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""mcp_json_repowise_nudge — Claude Code SessionStart hook (#1747).
|
|
3
|
+
|
|
4
|
+
`project-init/SKILL.md`'s `.mcp.json` standing check can only relocate a
|
|
5
|
+
stale, git-tracked `repowise` entry when someone actually runs
|
|
6
|
+
`/project-init` (or `/setup`). For an already-initialized project, nobody
|
|
7
|
+
is prompted to do that — the entry sits untouched indefinitely. This hook
|
|
8
|
+
is that proactive nudge, mirroring `pending_review_notify.py`'s /
|
|
9
|
+
`repo_review_nudge.py`'s shape: read a small state signal, print a one-line
|
|
10
|
+
stdout notice, fail-open, stdlib-only.
|
|
11
|
+
|
|
12
|
+
Shares its detection predicate — `hooks/lib/mcp_json_repowise.py::detect()`
|
|
13
|
+
— with the standing check itself (invoked from skill markdown via that
|
|
14
|
+
module's own CLI), so the two can never disagree on what counts as "needs
|
|
15
|
+
fixing" (#1747's single-commit requirement: this hook is meaningless
|
|
16
|
+
without that module's `relocate()` existing, so the two ship together).
|
|
17
|
+
|
|
18
|
+
Nudges every session until the condition clears (no snooze/debounce) — same
|
|
19
|
+
posture as the existing pending-review-queue and repo-review nudges.
|
|
20
|
+
|
|
21
|
+
Contract (docs/python-hook-contract.md):
|
|
22
|
+
Input : SessionStart JSON on stdin (hook_event_name, cwd, model, ...).
|
|
23
|
+
Output: notification text on stdout. Exit 0 always.
|
|
24
|
+
Posture: fail-open — a buggy notifier must never block a session; this
|
|
25
|
+
hook only ever suggests, it never gates.
|
|
26
|
+
|
|
27
|
+
Stdlib-only.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
|
|
32
|
+
import sys
|
|
33
|
+
from pathlib import Path
|
|
34
|
+
|
|
35
|
+
_HOOK_DIR = Path(__file__).resolve().parent
|
|
36
|
+
_LIB_DIR = _HOOK_DIR / "lib"
|
|
37
|
+
if str(_LIB_DIR) not in sys.path:
|
|
38
|
+
sys.path.insert(0, str(_LIB_DIR))
|
|
39
|
+
|
|
40
|
+
from stdin_json import read_stdin_json, resolve_cwd # type: ignore[import-not-found]
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
from mcp_json_repowise import detect # type: ignore[import-not-found]
|
|
44
|
+
except ImportError: # pragma: no cover
|
|
45
|
+
|
|
46
|
+
def detect(cwd): # type: ignore[misc]
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
_NUDGE_MESSAGE = (
|
|
51
|
+
"⚠️ .mcp.json is git-tracked and registers repowise with a "
|
|
52
|
+
"machine-specific path (breaks for every other clone/teammate) — run "
|
|
53
|
+
"/project-init (or /setup) to relocate it to local scope\n"
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def main() -> int:
|
|
58
|
+
payload = read_stdin_json()
|
|
59
|
+
if payload is None:
|
|
60
|
+
return 0
|
|
61
|
+
cwd = resolve_cwd(payload)
|
|
62
|
+
|
|
63
|
+
if detect(Path(cwd)) is None:
|
|
64
|
+
return 0
|
|
65
|
+
|
|
66
|
+
sys.stdout.write(_NUDGE_MESSAGE)
|
|
67
|
+
return 0
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
if __name__ == "__main__": # pragma: no cover
|
|
71
|
+
try:
|
|
72
|
+
sys.exit(main())
|
|
73
|
+
except Exception: # noqa: BLE001 - fail-open: a hook bug must never block a session
|
|
74
|
+
sys.exit(0)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"""Mutation-testing adapters — Python port of hooks/mutation-adapters/*.sh (#578).
|
|
2
|
+
|
|
3
|
+
Public surface mirrors the bash lib.sh + adapter contract so mutation-gate can
|
|
4
|
+
switch consumers one at a time. See `lib.py` for the shared library and
|
|
5
|
+
`stryker.py`, `stryker_net.py`, `pitest.py`, `mutmut.py` for the per-runner
|
|
6
|
+
adapters.
|
|
7
|
+
"""
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|