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,253 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""refactor_test_bash_guard.py — PreToolUse hook (Bash), issue #906.
|
|
3
|
+
|
|
4
|
+
The preventive, Bash-aware half of the tests-frozen-during-refactor
|
|
5
|
+
invariant (#813). `refactor_test_freeze_guard.py` blocks Write/Edit at a
|
|
6
|
+
test file during a recorded REFACTOR phase, but Bash-driven edits (`sed -i`,
|
|
7
|
+
`tee`, shell redirection, `mv`/`cp` onto a target, `python -c` with an
|
|
8
|
+
`open(..., "w")`) bypass that guard entirely and were previously only
|
|
9
|
+
caught reactively, after the fact, by `refactor_test_revert_guard.py`
|
|
10
|
+
(PostToolUse) — which reverts/removes the damage once it has already
|
|
11
|
+
landed on disk.
|
|
12
|
+
|
|
13
|
+
This hook recognizes a conservative library of common file-modifying Bash
|
|
14
|
+
shapes (`hooks/refactor-bash-write-patterns.json`), extracts the apparent
|
|
15
|
+
write target, and — only when a recorded REFACTOR phase is active AND the
|
|
16
|
+
target resolves to a file in the step's `test_files_staged` (or would newly
|
|
17
|
+
create a file `test_file_classify.is_test_file()` classifies as a test) —
|
|
18
|
+
blocks with exit 2 before the command ever runs.
|
|
19
|
+
|
|
20
|
+
Ambiguous/unparseable commands (no pattern matches, or the matched target
|
|
21
|
+
cannot be confidently resolved) are NEVER blocked: the false-positive budget
|
|
22
|
+
favors letting the command through and relying on
|
|
23
|
+
`refactor_test_revert_guard.py` as the safety net (defense-in-depth, not a
|
|
24
|
+
replacement — see the issue's Non-goals). This is not a general-purpose
|
|
25
|
+
shell parser.
|
|
26
|
+
|
|
27
|
+
Fails OPEN on any internal error, with one audit line in
|
|
28
|
+
`.claude/metrics/refactor-freeze.jsonl` (hook="bash-freeze") — a broken
|
|
29
|
+
guard must never block work.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import json
|
|
35
|
+
import re
|
|
36
|
+
import sys
|
|
37
|
+
from pathlib import Path
|
|
38
|
+
|
|
39
|
+
_SCRIPT_DIR = Path(__file__).resolve().parent
|
|
40
|
+
_LIB_DIR = _SCRIPT_DIR / "lib"
|
|
41
|
+
if str(_LIB_DIR) not in sys.path:
|
|
42
|
+
sys.path.insert(0, str(_LIB_DIR))
|
|
43
|
+
|
|
44
|
+
import artifact_paths
|
|
45
|
+
from boundary_events import emit_boundary_event as _emit_boundary_event
|
|
46
|
+
from refactor_test_freeze_guard import audit
|
|
47
|
+
from stdin_json import read_stdin_json
|
|
48
|
+
from test_file_classify import is_test_file, read_build_phase
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def emit_boundary_event(*args, **kwargs) -> None:
|
|
52
|
+
"""Local safety net (#859): even a misbehaving helper must never affect
|
|
53
|
+
this hook's exit code, stdout, or stderr."""
|
|
54
|
+
try:
|
|
55
|
+
_emit_boundary_event(*args, **kwargs)
|
|
56
|
+
except Exception: # noqa: BLE001, S110 - fail-open by design
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
_PATTERNS_FILE = _SCRIPT_DIR / "refactor-bash-write-patterns.json"
|
|
61
|
+
|
|
62
|
+
RECOVERY = (
|
|
63
|
+
"tests are frozen during REFACTOR; return to the TEST phase, make the "
|
|
64
|
+
"change there, re-verify green, then re-enter REFACTOR"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Inline fallback — kept in the same order as the shipped JSON so behavior
|
|
68
|
+
# is byte-identical when the config file is missing or malformed.
|
|
69
|
+
_DEFAULT_PATTERNS: list[tuple[str, str]] = [
|
|
70
|
+
(
|
|
71
|
+
"sed-i",
|
|
72
|
+
r"\bsed\s+-i(?:\.\S+)?\s+(?:-e\s+)?(?:'[^']*'|\"[^\"]*\")\s+(?P<target>[^\s;&|]+)",
|
|
73
|
+
),
|
|
74
|
+
(
|
|
75
|
+
"perl-i",
|
|
76
|
+
r"\bperl\s+-i(?:\.\S+)?\s+(?:-[a-zA-Z]+\s+)*(?:'[^']*'|\"[^\"]*\")\s+(?P<target>[^\s;&|]+)",
|
|
77
|
+
),
|
|
78
|
+
("tee", r"\btee\s+(?:-a\s+)?(?P<target>[^\s;&|]+)"),
|
|
79
|
+
("redirect", r"(?<![\w&])>{1,2}(?!\S*&)\s*(?P<target>[^\s;&|>]+)"),
|
|
80
|
+
(
|
|
81
|
+
"mv-cp",
|
|
82
|
+
r"\b(?:mv|cp)\s+(?:-\S+\s+)*(?P<src>[^\s;&|]+)\s+(?P<target>[^\s;&|]+)\s*(?:[;&|]|$)",
|
|
83
|
+
),
|
|
84
|
+
(
|
|
85
|
+
"python-open-write",
|
|
86
|
+
r"open\(\s*['\"](?P<target>[^'\"]+)['\"]\s*,\s*['\"](?:w|a|wb|ab|w\+|a\+)['\"]",
|
|
87
|
+
),
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _load_patterns() -> list[tuple[str, str]]:
|
|
92
|
+
"""Load (id, regex) pairs from the config file, falling back to inline
|
|
93
|
+
defaults on any error — attempt-and-degrade, matches destructive_guard.py."""
|
|
94
|
+
try:
|
|
95
|
+
data = json.loads(_PATTERNS_FILE.read_text(encoding="utf-8"))
|
|
96
|
+
except (OSError, ValueError):
|
|
97
|
+
return list(_DEFAULT_PATTERNS)
|
|
98
|
+
if not isinstance(data, dict):
|
|
99
|
+
return list(_DEFAULT_PATTERNS)
|
|
100
|
+
raw = data.get("patterns")
|
|
101
|
+
if not isinstance(raw, list):
|
|
102
|
+
return list(_DEFAULT_PATTERNS)
|
|
103
|
+
pairs: list[tuple[str, str]] = []
|
|
104
|
+
for entry in raw:
|
|
105
|
+
if not isinstance(entry, dict):
|
|
106
|
+
continue
|
|
107
|
+
rule_id = entry.get("id")
|
|
108
|
+
regex = entry.get("regex")
|
|
109
|
+
if isinstance(rule_id, str) and rule_id and isinstance(regex, str) and regex:
|
|
110
|
+
pairs.append((rule_id, regex))
|
|
111
|
+
return pairs if pairs else list(_DEFAULT_PATTERNS)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _extract_all_targets(
|
|
115
|
+
command: str, patterns: list[tuple[str, str]]
|
|
116
|
+
) -> list[tuple[str, str]]:
|
|
117
|
+
"""Return (rule_id, raw_target) for every occurrence of every pattern
|
|
118
|
+
that matches the command, evaluated independently rather than
|
|
119
|
+
short-circuited at the first hit (#914).
|
|
120
|
+
|
|
121
|
+
A compound command (`;`/`&&`/`|`-joined) can carry a harmless match for
|
|
122
|
+
an earlier-listed pattern (e.g. a `redirect` onto a scratch file) while,
|
|
123
|
+
elsewhere in the same string, a later-listed pattern (e.g. `mv-cp`)
|
|
124
|
+
matches a genuinely dangerous target — stopping at the first *pattern*
|
|
125
|
+
match let the earlier, unrelated hit mask the real one. The same masking
|
|
126
|
+
can happen within a single rule too (e.g. two `mv` segments, only the
|
|
127
|
+
second targeting a test file), so every occurrence of a matching pattern
|
|
128
|
+
is collected via `re.finditer`, not just its first occurrence via
|
|
129
|
+
`re.search`. Never raises."""
|
|
130
|
+
matches: list[tuple[str, str]] = []
|
|
131
|
+
for rule_id, regex in patterns:
|
|
132
|
+
try:
|
|
133
|
+
found = list(re.finditer(regex, command))
|
|
134
|
+
except re.error:
|
|
135
|
+
continue
|
|
136
|
+
for match in found:
|
|
137
|
+
target = match.groupdict().get("target")
|
|
138
|
+
if target:
|
|
139
|
+
matches.append((rule_id, target))
|
|
140
|
+
return matches
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _normalize_target(target: str) -> str:
|
|
144
|
+
"""Strip a matching pair of quotes and a leading './' — best-effort only."""
|
|
145
|
+
stripped = target.strip()
|
|
146
|
+
if len(stripped) >= 2 and stripped[0] == stripped[-1] and stripped[0] in ("'", '"'):
|
|
147
|
+
stripped = stripped[1:-1]
|
|
148
|
+
stripped = stripped.removeprefix("./")
|
|
149
|
+
return stripped
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _resolve_relative(target: str, project_dir: Path) -> str:
|
|
153
|
+
"""Best-effort project-relative posix path for `target`. Falls back to
|
|
154
|
+
the normalized target string when it can't be resolved under
|
|
155
|
+
`project_dir` (e.g. an absolute path outside the project)."""
|
|
156
|
+
normalized = _normalize_target(target)
|
|
157
|
+
candidate = Path(normalized)
|
|
158
|
+
if candidate.is_absolute():
|
|
159
|
+
try:
|
|
160
|
+
return candidate.resolve().relative_to(project_dir.resolve()).as_posix()
|
|
161
|
+
except (OSError, ValueError):
|
|
162
|
+
return normalized
|
|
163
|
+
return normalized
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _matches_staged_or_new_test(rel_target: str, staged: list[str]) -> bool:
|
|
167
|
+
if rel_target in staged:
|
|
168
|
+
return True
|
|
169
|
+
return is_test_file(rel_target)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def evaluate(
|
|
173
|
+
command: str, project_dir: Path, now: float | None = None
|
|
174
|
+
) -> tuple[int, list[str], str | None]:
|
|
175
|
+
"""Return (exit_code, stdout_lines, matched_rule_id).
|
|
176
|
+
|
|
177
|
+
`matched_rule_id` is the pattern id that triggered a block, or None
|
|
178
|
+
(including for every non-blocking outcome).
|
|
179
|
+
"""
|
|
180
|
+
if not command:
|
|
181
|
+
return 0, [], None
|
|
182
|
+
state, error = read_build_phase(project_dir, now=now)
|
|
183
|
+
if error is not None:
|
|
184
|
+
audit(project_dir, "bash-freeze", "fail-open", reason=error)
|
|
185
|
+
return 0, [], None
|
|
186
|
+
if state is None or state.get("phase") != "refactor":
|
|
187
|
+
return 0, [], None
|
|
188
|
+
|
|
189
|
+
staged = state.get("test_files_staged", [])
|
|
190
|
+
for rule_id, raw_target in _extract_all_targets(command, _load_patterns()):
|
|
191
|
+
rel_target = _resolve_relative(raw_target, project_dir)
|
|
192
|
+
if not _matches_staged_or_new_test(rel_target, staged):
|
|
193
|
+
continue
|
|
194
|
+
|
|
195
|
+
step = state.get("step") if isinstance(state.get("step"), str) else None
|
|
196
|
+
audit(project_dir, "bash-freeze", "block", file=rel_target, step=step)
|
|
197
|
+
step_label = f" (step {step})" if step else ""
|
|
198
|
+
return (
|
|
199
|
+
2,
|
|
200
|
+
[
|
|
201
|
+
f"[BLOCK] Tests are frozen during REFACTOR{step_label}.",
|
|
202
|
+
"A refactor step must never change a test — refactoring is",
|
|
203
|
+
"behavior-preserving by definition (tests-frozen invariant, Rec 4,",
|
|
204
|
+
"docs/experiments/RECOMMENDATIONS.md).",
|
|
205
|
+
f"File: {rel_target}",
|
|
206
|
+
"Recovery: leave REFACTOR and return to the TEST phase, make the",
|
|
207
|
+
"test change there, re-verify the full suite green (pasted",
|
|
208
|
+
"evidence), then re-enter REFACTOR.",
|
|
209
|
+
],
|
|
210
|
+
rule_id,
|
|
211
|
+
)
|
|
212
|
+
return 0, [], None
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def main() -> int:
|
|
216
|
+
project_dir = artifact_paths.project_root()
|
|
217
|
+
exit_code, lines = 0, []
|
|
218
|
+
try:
|
|
219
|
+
payload = read_stdin_json()
|
|
220
|
+
tool_input = payload.get("tool_input") if isinstance(payload, dict) else None
|
|
221
|
+
command = ""
|
|
222
|
+
if isinstance(tool_input, dict):
|
|
223
|
+
raw = tool_input.get("command")
|
|
224
|
+
if isinstance(raw, str):
|
|
225
|
+
command = raw
|
|
226
|
+
exit_code, lines, rule_id = evaluate(command, project_dir)
|
|
227
|
+
if exit_code == 2:
|
|
228
|
+
session_id = (
|
|
229
|
+
payload.get("session_id") if isinstance(payload, dict) else None
|
|
230
|
+
)
|
|
231
|
+
emit_boundary_event(
|
|
232
|
+
project_dir,
|
|
233
|
+
"refactor_test_bash_guard",
|
|
234
|
+
"Bash",
|
|
235
|
+
"block",
|
|
236
|
+
rule_id or "bash-write",
|
|
237
|
+
session_id,
|
|
238
|
+
)
|
|
239
|
+
except Exception as exc: # noqa: BLE001 - fail open — a broken guard never blocks work
|
|
240
|
+
audit(
|
|
241
|
+
project_dir,
|
|
242
|
+
"bash-freeze",
|
|
243
|
+
"fail-open",
|
|
244
|
+
reason=f"internal error: {exc}",
|
|
245
|
+
)
|
|
246
|
+
return 0
|
|
247
|
+
for line in lines:
|
|
248
|
+
print(line)
|
|
249
|
+
return exit_code
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
if __name__ == "__main__": # pragma: no cover
|
|
253
|
+
sys.exit(main())
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""refactor_test_freeze_guard.py — PreToolUse hook (Write|Edit), issue #813.
|
|
3
|
+
|
|
4
|
+
Enforces the tests-frozen-during-refactor invariant mechanically: while
|
|
5
|
+
`/build` has recorded that the current step is in its REFACTOR phase
|
|
6
|
+
(`.claude/memory/build-phase.json`), any Write/Edit targeting a test file is denied
|
|
7
|
+
(exit 2, `[BLOCK]` per docs/python-hook-contract.md). A refactor step must
|
|
8
|
+
never change a test — the invariant held at zero violations across the
|
|
9
|
+
experiment campaigns (Rec 4, docs/experiments/RECOMMENDATIONS.md).
|
|
10
|
+
|
|
11
|
+
Fails OPEN on any internal error, with one audit line in
|
|
12
|
+
`.claude/metrics/refactor-freeze.jsonl` — a broken guard must never block
|
|
13
|
+
work.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import json
|
|
19
|
+
import sys
|
|
20
|
+
from datetime import datetime, timezone
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
_LIB_DIR = Path(__file__).resolve().parent / "lib"
|
|
24
|
+
sys.path.insert(0, str(_LIB_DIR))
|
|
25
|
+
|
|
26
|
+
import artifact_paths
|
|
27
|
+
from atomic_state import append_line_locked
|
|
28
|
+
from boundary_events import emit_boundary_event as _emit_boundary_event
|
|
29
|
+
from stdin_json import read_stdin_json
|
|
30
|
+
from test_file_classify import is_test_file, read_build_phase
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def emit_boundary_event(*args, **kwargs) -> None:
|
|
34
|
+
"""Local safety net (#859): even a misbehaving helper must never affect
|
|
35
|
+
this hook's exit code, stdout, or stderr."""
|
|
36
|
+
try:
|
|
37
|
+
_emit_boundary_event(*args, **kwargs)
|
|
38
|
+
except Exception: # noqa: BLE001, S110 - fail-open by design
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
def _project_dir() -> Path:
|
|
42
|
+
"""Resolve the project root via git, not the possibly-unset/stale
|
|
43
|
+
CLAUDE_PROJECT_DIR env var."""
|
|
44
|
+
return artifact_paths.project_root()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def audit(
|
|
48
|
+
project_dir: Path,
|
|
49
|
+
hook: str,
|
|
50
|
+
event: str,
|
|
51
|
+
file: str | None = None,
|
|
52
|
+
step: str | None = None,
|
|
53
|
+
reason: str | None = None,
|
|
54
|
+
) -> None:
|
|
55
|
+
"""Append one JSONL audit line under .claude/metrics/refactor-freeze.jsonl.
|
|
56
|
+
|
|
57
|
+
Best-effort — a failure to resolve the path, create the directory, or
|
|
58
|
+
write the line is fail-open: log a diagnostic and never crash the guard.
|
|
59
|
+
"""
|
|
60
|
+
entry = {
|
|
61
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
62
|
+
"hook": hook,
|
|
63
|
+
"event": event,
|
|
64
|
+
"file": file,
|
|
65
|
+
"step": step,
|
|
66
|
+
"reason": reason,
|
|
67
|
+
}
|
|
68
|
+
try:
|
|
69
|
+
path = artifact_paths.resolve_file("metrics", "refactor-freeze.jsonl", project_dir)
|
|
70
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
71
|
+
append_line_locked(path, json.dumps(entry) + "\n", fail_open=False)
|
|
72
|
+
except OSError as exc:
|
|
73
|
+
sys.stderr.write(f"[refactor_test_freeze_guard] failed to write audit line: {exc}\n")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _extract_file_path(payload: dict | None) -> str:
|
|
77
|
+
if not isinstance(payload, dict):
|
|
78
|
+
return ""
|
|
79
|
+
tool_input = payload.get("tool_input") or {}
|
|
80
|
+
if not isinstance(tool_input, dict):
|
|
81
|
+
return ""
|
|
82
|
+
for key in ("file_path", "path"):
|
|
83
|
+
value = tool_input.get(key)
|
|
84
|
+
if isinstance(value, str) and value:
|
|
85
|
+
return value
|
|
86
|
+
return ""
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def evaluate(
|
|
90
|
+
file_path: str, project_dir: Path, now: float | None = None
|
|
91
|
+
) -> tuple[int, list[str]]:
|
|
92
|
+
"""Return (exit_code, stdout_lines) for one Write/Edit decision."""
|
|
93
|
+
if not file_path:
|
|
94
|
+
return 0, []
|
|
95
|
+
state, error = read_build_phase(project_dir, now=now)
|
|
96
|
+
if error is not None:
|
|
97
|
+
audit(project_dir, "freeze", "fail-open", file=file_path, reason=error)
|
|
98
|
+
return 0, []
|
|
99
|
+
if state is None or state.get("phase") != "refactor":
|
|
100
|
+
return 0, []
|
|
101
|
+
if not is_test_file(file_path):
|
|
102
|
+
return 0, []
|
|
103
|
+
step = state.get("step") if isinstance(state.get("step"), str) else None
|
|
104
|
+
audit(project_dir, "freeze", "block", file=file_path, step=step)
|
|
105
|
+
step_label = f" (step {step})" if step else ""
|
|
106
|
+
return 2, [
|
|
107
|
+
f"[BLOCK] Tests are frozen during REFACTOR{step_label}.",
|
|
108
|
+
"A refactor step must never change a test — refactoring is",
|
|
109
|
+
"behavior-preserving by definition (tests-frozen invariant, Rec 4,",
|
|
110
|
+
"docs/experiments/RECOMMENDATIONS.md).",
|
|
111
|
+
f"File: {file_path}",
|
|
112
|
+
"Recovery: leave REFACTOR and return to the TEST phase, make the test",
|
|
113
|
+
"change there, re-verify the full suite green (pasted evidence), then",
|
|
114
|
+
"re-enter REFACTOR.",
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def main() -> int:
|
|
119
|
+
project_dir = _project_dir()
|
|
120
|
+
try:
|
|
121
|
+
payload = read_stdin_json()
|
|
122
|
+
file_path = _extract_file_path(payload)
|
|
123
|
+
exit_code, lines = evaluate(file_path, project_dir)
|
|
124
|
+
if exit_code == 2:
|
|
125
|
+
session_id = payload.get("session_id") if isinstance(payload, dict) else None
|
|
126
|
+
emit_boundary_event(
|
|
127
|
+
project_dir, "refactor_test_freeze_guard", "Write", "block",
|
|
128
|
+
"refactor-test-freeze", session_id,
|
|
129
|
+
)
|
|
130
|
+
except Exception as exc: # noqa: BLE001 # fail open — a broken guard never blocks work
|
|
131
|
+
audit(project_dir, "freeze", "fail-open", reason=f"internal error: {exc}")
|
|
132
|
+
return 0
|
|
133
|
+
for line in lines:
|
|
134
|
+
print(line)
|
|
135
|
+
return exit_code
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
if __name__ == "__main__": # pragma: no cover
|
|
139
|
+
sys.exit(main())
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""refactor_test_revert_guard.py — PostToolUse hook (Bash), issue #813.
|
|
3
|
+
|
|
4
|
+
The revert half of the tests-frozen-during-refactor enforcement: Bash-driven
|
|
5
|
+
edits bypass the PreToolUse freeze guard, so after each Bash call during a
|
|
6
|
+
recorded REFACTOR phase this hook restores any test file that drifted from
|
|
7
|
+
the staged baseline `/build` captured at the TEST→REFACTOR transition
|
|
8
|
+
(`git add` of the step's test files, recorded in `test_files_staged`).
|
|
9
|
+
|
|
10
|
+
- Baseline carryover (working tree matches the index) is never reverted.
|
|
11
|
+
- A test file dirtied after the baseline is restored via `git checkout --`.
|
|
12
|
+
- A test file newly created during refactor (untracked, absent from the
|
|
13
|
+
baseline) is removed — no unreviewed test file is silently left in place.
|
|
14
|
+
- Fails OPEN on unreadable/malformed state or git failure: never reverts on
|
|
15
|
+
fail-open, one audit line in `metrics/refactor-freeze.jsonl`.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import os
|
|
21
|
+
import subprocess
|
|
22
|
+
import sys
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
_LIB_DIR = Path(__file__).resolve().parent / "lib"
|
|
26
|
+
sys.path.insert(0, str(_LIB_DIR))
|
|
27
|
+
|
|
28
|
+
from boundary_events import emit_boundary_event as _emit_boundary_event
|
|
29
|
+
from refactor_test_freeze_guard import audit
|
|
30
|
+
from stdin_json import read_stdin_json
|
|
31
|
+
from test_file_classify import is_test_file, read_build_phase
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def emit_boundary_event(*args, **kwargs) -> None:
|
|
35
|
+
"""Local safety net (#859): even a misbehaving helper must never affect
|
|
36
|
+
this hook's exit code, stdout, or stderr. Also degrades silently (no
|
|
37
|
+
error, no extra output) on a tree that predates #859/PR #887 and lacks
|
|
38
|
+
the boundary-events channel — attempt-and-degrade, same pattern #862
|
|
39
|
+
uses."""
|
|
40
|
+
try:
|
|
41
|
+
_emit_boundary_event(*args, **kwargs)
|
|
42
|
+
except Exception: # noqa: BLE001, S110 - fail-open by design
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
RECOVERY = (
|
|
47
|
+
"tests are frozen during REFACTOR; return to the TEST phase, make the "
|
|
48
|
+
"change there, re-verify green, then re-enter REFACTOR"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _git(project_dir: Path, args: list[str]) -> str | None:
|
|
53
|
+
"""Run git in the project dir; stdout on success, None on any failure."""
|
|
54
|
+
try:
|
|
55
|
+
result = subprocess.run(
|
|
56
|
+
["git"] + args,
|
|
57
|
+
cwd=str(project_dir),
|
|
58
|
+
capture_output=True,
|
|
59
|
+
text=True,
|
|
60
|
+
timeout=60,
|
|
61
|
+
check=False,
|
|
62
|
+
)
|
|
63
|
+
except (OSError, subprocess.SubprocessError):
|
|
64
|
+
return None
|
|
65
|
+
if result.returncode != 0:
|
|
66
|
+
return None
|
|
67
|
+
return result.stdout
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def evaluate(
|
|
71
|
+
project_dir: Path,
|
|
72
|
+
now: float | None = None,
|
|
73
|
+
session_id: str | None = None,
|
|
74
|
+
) -> tuple[int, list[str]]:
|
|
75
|
+
"""Return (exit_code, stdout_lines). Always exits 0 — advisory only."""
|
|
76
|
+
state, error = read_build_phase(project_dir, now=now)
|
|
77
|
+
if error is not None:
|
|
78
|
+
audit(project_dir, "revert", "fail-open", reason=error)
|
|
79
|
+
return 0, []
|
|
80
|
+
if state is None or state.get("phase") != "refactor":
|
|
81
|
+
return 0, []
|
|
82
|
+
step = state.get("step") if isinstance(state.get("step"), str) else None
|
|
83
|
+
lines: list[str] = []
|
|
84
|
+
|
|
85
|
+
# Post-baseline drift on baseline files: the index IS the baseline.
|
|
86
|
+
baseline = state.get("test_files_staged", [])
|
|
87
|
+
if baseline:
|
|
88
|
+
diff_out = _git(project_dir, ["diff", "--name-only", "--"] + baseline)
|
|
89
|
+
if diff_out is None:
|
|
90
|
+
audit(
|
|
91
|
+
project_dir,
|
|
92
|
+
"revert",
|
|
93
|
+
"fail-open",
|
|
94
|
+
step=step,
|
|
95
|
+
reason="git diff against staged baseline failed",
|
|
96
|
+
)
|
|
97
|
+
return 0, lines
|
|
98
|
+
for dirty in [f for f in diff_out.splitlines() if f.strip()]:
|
|
99
|
+
restored = _git(project_dir, ["checkout", "--", dirty])
|
|
100
|
+
if restored is None:
|
|
101
|
+
audit(
|
|
102
|
+
project_dir,
|
|
103
|
+
"revert",
|
|
104
|
+
"fail-open",
|
|
105
|
+
file=dirty,
|
|
106
|
+
step=step,
|
|
107
|
+
reason="git checkout failed",
|
|
108
|
+
)
|
|
109
|
+
continue
|
|
110
|
+
audit(project_dir, "revert", "revert", file=dirty, step=step)
|
|
111
|
+
emit_boundary_event(
|
|
112
|
+
project_dir,
|
|
113
|
+
"refactor_test_revert_guard",
|
|
114
|
+
"Bash",
|
|
115
|
+
"revert",
|
|
116
|
+
"restore-baseline",
|
|
117
|
+
session_id,
|
|
118
|
+
)
|
|
119
|
+
lines.append(
|
|
120
|
+
f"ADVISORY: restored test file '{dirty}' to its TEST-phase baseline "
|
|
121
|
+
f"({RECOVERY})."
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# Test files created during refactor: untracked and absent from baseline.
|
|
125
|
+
others_out = _git(project_dir, ["ls-files", "--others", "--exclude-standard"])
|
|
126
|
+
if others_out is None:
|
|
127
|
+
audit(
|
|
128
|
+
project_dir,
|
|
129
|
+
"revert",
|
|
130
|
+
"fail-open",
|
|
131
|
+
step=step,
|
|
132
|
+
reason="git ls-files --others failed",
|
|
133
|
+
)
|
|
134
|
+
return 0, lines
|
|
135
|
+
for rel in [f for f in others_out.splitlines() if f.strip()]:
|
|
136
|
+
candidate = project_dir / rel
|
|
137
|
+
if not is_test_file(str(candidate)):
|
|
138
|
+
continue
|
|
139
|
+
try:
|
|
140
|
+
candidate.unlink()
|
|
141
|
+
except OSError as exc:
|
|
142
|
+
audit(
|
|
143
|
+
project_dir,
|
|
144
|
+
"revert",
|
|
145
|
+
"fail-open",
|
|
146
|
+
file=rel,
|
|
147
|
+
step=step,
|
|
148
|
+
reason=f"could not remove: {exc}",
|
|
149
|
+
)
|
|
150
|
+
continue
|
|
151
|
+
audit(project_dir, "revert", "remove", file=rel, step=step)
|
|
152
|
+
emit_boundary_event(
|
|
153
|
+
project_dir,
|
|
154
|
+
"refactor_test_revert_guard",
|
|
155
|
+
"Bash",
|
|
156
|
+
"revert",
|
|
157
|
+
"remove-untracked-test",
|
|
158
|
+
session_id,
|
|
159
|
+
)
|
|
160
|
+
lines.append(
|
|
161
|
+
f"ADVISORY: removed test file '{rel}' created during REFACTOR "
|
|
162
|
+
f"({RECOVERY})."
|
|
163
|
+
)
|
|
164
|
+
return 0, lines
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def main() -> int:
|
|
168
|
+
project_dir = Path(os.environ.get("CLAUDE_PROJECT_DIR") or os.getcwd())
|
|
169
|
+
# The guard inspects disk state, not the payload — but stdin must still
|
|
170
|
+
# be drained (so the hook runner never blocks on a full pipe) and the
|
|
171
|
+
# session_id, when present, is worth threading into the boundary-events
|
|
172
|
+
# emission for cross-stream joins with session-digest.jsonl.
|
|
173
|
+
payload = read_stdin_json()
|
|
174
|
+
session_id = payload.get("session_id") if isinstance(payload, dict) else None
|
|
175
|
+
try:
|
|
176
|
+
exit_code, lines = evaluate(project_dir, session_id=session_id)
|
|
177
|
+
except Exception as exc: # noqa: BLE001 - fail open — never revert, never block
|
|
178
|
+
audit(project_dir, "revert", "fail-open", reason=f"internal error: {exc}")
|
|
179
|
+
return 0
|
|
180
|
+
for line in lines:
|
|
181
|
+
print(line)
|
|
182
|
+
return exit_code
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
if __name__ == "__main__": # pragma: no cover
|
|
186
|
+
sys.exit(main())
|