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,446 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Finding identity across review rounds — the round ledger (#1625).
|
|
3
|
+
|
|
4
|
+
`/code-review`'s fix loop has an iteration cap but no notion of finding
|
|
5
|
+
*identity* across rounds: nothing can tell "this round found the same problem
|
|
6
|
+
again" from "this round found something genuinely new", so nothing can detect
|
|
7
|
+
that the loop is churning. #1619's case study ran 9 dispatch rounds over ~4
|
|
8
|
+
files, several of them re-verifying fixes to defects the previous round's fix
|
|
9
|
+
had introduced.
|
|
10
|
+
|
|
11
|
+
This module mirrors `/build`'s failure-signature dead-end detection (#864) —
|
|
12
|
+
the same normalize / compare / terminate pattern, applied to review findings —
|
|
13
|
+
and is the single shared implementation for both `/code-review`'s step 6a
|
|
14
|
+
loop and `/build`'s inline checkpoint loops.
|
|
15
|
+
|
|
16
|
+
## Why the line number is not inside the hash
|
|
17
|
+
|
|
18
|
+
The design sketch describes the signature as a tuple including a
|
|
19
|
+
"line-bucket ±3". A hashed bucket (`line // 7`) is *not* the same relation:
|
|
20
|
+
two reports of the same finding at lines 6 and 7 land in different buckets
|
|
21
|
+
and would read as two distinct findings, which is exactly the false-new
|
|
22
|
+
result the severity floor and loop-until-dry rules must not get. Proximity
|
|
23
|
+
is not an equivalence relation, so it cannot be folded into a hash without
|
|
24
|
+
introducing boundary artifacts.
|
|
25
|
+
|
|
26
|
+
So `signature()` hashes the *stable* identity — agent, file, category,
|
|
27
|
+
and the normalized message — and the line is carried alongside it in
|
|
28
|
+
`FindingKey`. `same_finding()` then applies the true ±`LINE_TOLERANCE`
|
|
29
|
+
proximity test. Callers that want one hashable key for set membership use
|
|
30
|
+
`FindingKey.signature`; callers deciding new-vs-carried use
|
|
31
|
+
`match_carried()`, which is the one that respects the tolerance.
|
|
32
|
+
|
|
33
|
+
## Message normalization
|
|
34
|
+
|
|
35
|
+
Volatile text is stripped before hashing so a finding re-reported after an
|
|
36
|
+
unrelated fix keeps its identity:
|
|
37
|
+
|
|
38
|
+
- line/column references (`:120:4`, `line 120`, `L120`)
|
|
39
|
+
- ISO-8601 timestamps
|
|
40
|
+
- hex digests of 7+ chars (commit shas, content hashes)
|
|
41
|
+
- quoted spans (`'x'`, `"x"`, `` `x` ``) — an identifier the fix renamed must
|
|
42
|
+
not read as a different finding
|
|
43
|
+
- whitespace runs and letter case
|
|
44
|
+
|
|
45
|
+
Stdlib-only. See docs/python-hook-contract.md.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
from __future__ import annotations
|
|
49
|
+
|
|
50
|
+
import argparse
|
|
51
|
+
import hashlib
|
|
52
|
+
import json
|
|
53
|
+
import re
|
|
54
|
+
import sys
|
|
55
|
+
from typing import NamedTuple
|
|
56
|
+
|
|
57
|
+
#: Two reports of the same normalized finding within this many lines of each
|
|
58
|
+
#: other are the same finding. Fixes shift line numbers slightly; a finding
|
|
59
|
+
#: that moved further than this is treated as new, which is the conservative
|
|
60
|
+
#: direction (an extra round is cheaper than terminating on an unfixed defect).
|
|
61
|
+
LINE_TOLERANCE = 3
|
|
62
|
+
|
|
63
|
+
#: Severities that justify another fix-dispatch round from round 2 onward.
|
|
64
|
+
ACTIONABLE_SEVERITIES = frozenset({"error", "warning"})
|
|
65
|
+
|
|
66
|
+
#: Confidences that justify another fix-dispatch round from round 2 onward.
|
|
67
|
+
ACTIONABLE_CONFIDENCES = frozenset({"high", "medium"})
|
|
68
|
+
|
|
69
|
+
#: Total dispatch rounds (initial panel + fix-loop rounds) after which the
|
|
70
|
+
#: loop escalates to a human with the round ledger as evidence. Applied to
|
|
71
|
+
#: #1619's case study this would have surfaced the churn at round 4 rather
|
|
72
|
+
#: than round 9.
|
|
73
|
+
MAX_ROUNDS = 4
|
|
74
|
+
|
|
75
|
+
_TIMESTAMP_RE = re.compile(r"\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?")
|
|
76
|
+
_LINE_REF_RE = re.compile(r"(?::\d+(?::\d+)?\b)|(?:\bl(?:ine)?s?\.?\s*\d+(?:\s*[-,]\s*\d+)*)", re.IGNORECASE)
|
|
77
|
+
_HEX_RE = re.compile(r"\b[0-9a-f]{7,}\b", re.IGNORECASE)
|
|
78
|
+
_QUOTED_RE = re.compile(r"`[^`]*`|\"[^\"]*\"|'[^']*'")
|
|
79
|
+
_NUMBER_RE = re.compile(r"\b\d+\b")
|
|
80
|
+
_WS_RE = re.compile(r"\s+")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class FindingKey(NamedTuple):
|
|
84
|
+
"""A finding's identity: a stable hash plus the line it was reported at.
|
|
85
|
+
|
|
86
|
+
`signature` is hashable and stable across rounds; `line` is compared with
|
|
87
|
+
`LINE_TOLERANCE` rather than folded into the hash (see module docstring).
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
signature: str
|
|
91
|
+
line: int
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def normalize_message(message: str) -> str:
|
|
95
|
+
"""Strip volatile text from a finding message so the same problem hashes
|
|
96
|
+
identically after a fix shifts lines or renames an identifier.
|
|
97
|
+
|
|
98
|
+
Order matters: timestamps and hex digests are removed before the bare
|
|
99
|
+
number sweep, so a sha or a date can't leave stray digit fragments behind.
|
|
100
|
+
"""
|
|
101
|
+
text = str(message or "")
|
|
102
|
+
text = _TIMESTAMP_RE.sub(" ", text)
|
|
103
|
+
text = _HEX_RE.sub(" ", text)
|
|
104
|
+
text = _QUOTED_RE.sub(" ", text)
|
|
105
|
+
text = _LINE_REF_RE.sub(" ", text)
|
|
106
|
+
text = _NUMBER_RE.sub(" ", text)
|
|
107
|
+
text = _WS_RE.sub(" ", text)
|
|
108
|
+
return text.strip().lower()
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _normalize_path(value) -> str:
|
|
112
|
+
text = str(value or "").replace("\\", "/")
|
|
113
|
+
while text.startswith("./"):
|
|
114
|
+
text = text[2:]
|
|
115
|
+
return text
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def finding_agent(finding: dict) -> str:
|
|
119
|
+
"""The reporting agent's name: `agent` (the aggregated/flattened finding
|
|
120
|
+
shape `consolidate.py` produces) falling back to `agentName` (the raw
|
|
121
|
+
per-agent-result field name). Shared by `signature()` below and by
|
|
122
|
+
`render_tiered_findings.py`'s finding-id scheme (#2170) — the same
|
|
123
|
+
fallback, one place, so a future field-name change can't silently
|
|
124
|
+
desync the two."""
|
|
125
|
+
return str(finding.get("agent") or finding.get("agentName") or "")
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def finding_category(finding: dict) -> str:
|
|
129
|
+
"""The taxonomy tag for this finding: `category` -> `smell` -> `rule` ->
|
|
130
|
+
`ruleId`, first truthy wins (see `signature()`'s docstring for why each
|
|
131
|
+
fallback exists). Shared by `signature()` below and by
|
|
132
|
+
`render_tiered_findings.py`'s finding-id scheme (#2170)."""
|
|
133
|
+
return str(
|
|
134
|
+
finding.get("category")
|
|
135
|
+
or finding.get("smell")
|
|
136
|
+
or finding.get("rule")
|
|
137
|
+
or finding.get("ruleId")
|
|
138
|
+
or ""
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def signature(finding: dict) -> str:
|
|
143
|
+
"""Stable identity hash for one finding: agent, file, category, and the
|
|
144
|
+
normalized message. Deliberately excludes the line number.
|
|
145
|
+
|
|
146
|
+
`category` is the canonical taxonomy field (#1639) — settled on `category`
|
|
147
|
+
rather than `rule` because that is what the three agents on this contract
|
|
148
|
+
already emitting one (`security-review`, `ai-provenance-review`,
|
|
149
|
+
`spec-compliance-review`) already spell it as, so no existing agent needed
|
|
150
|
+
to migrate. `rule` and `ruleId` remain accepted fallbacks for a finding
|
|
151
|
+
shaped by a future agent or an external tool that uses the more
|
|
152
|
+
conventional linter-rule name — never required, never the preferred
|
|
153
|
+
spelling to emit.
|
|
154
|
+
|
|
155
|
+
`smell` is also accepted (#1692): `test-smell-review` carries its
|
|
156
|
+
taxonomy in a `smell` field per `review-agent-output-contract.md`'s
|
|
157
|
+
"Documented per-agent extensions" section, not `category`/`rule`/
|
|
158
|
+
`ruleId`. Without this fallback every `test-smell-review` finding hashed
|
|
159
|
+
with an empty taxonomy segment, risking false "carried" collisions
|
|
160
|
+
between genuinely different smells whose normalized messages happen to
|
|
161
|
+
be similar within `same_finding()`'s line-proximity window. It sits
|
|
162
|
+
between `category` and `rule` in the fallback chain — after the
|
|
163
|
+
genuinely canonical field, before the linter-style fallbacks.
|
|
164
|
+
"""
|
|
165
|
+
agent = finding_agent(finding)
|
|
166
|
+
path = _normalize_path(finding.get("file"))
|
|
167
|
+
category = finding_category(finding)
|
|
168
|
+
message = normalize_message(finding.get("message"))
|
|
169
|
+
payload = f"{agent.lower()}\x1f{path}\x1f{category.lower()}\x1f{message}"
|
|
170
|
+
return hashlib.sha256(payload.encode("utf-8")).hexdigest()
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def finding_key(finding: dict) -> FindingKey:
|
|
174
|
+
"""`FindingKey` for one finding. A missing/unusable line becomes `0`,
|
|
175
|
+
which still compares correctly (two line-less reports of the same
|
|
176
|
+
normalized finding are within tolerance of each other)."""
|
|
177
|
+
line = finding.get("line")
|
|
178
|
+
if isinstance(line, bool) or not isinstance(line, int) or line < 0:
|
|
179
|
+
line = 0
|
|
180
|
+
return FindingKey(signature(finding), line)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def same_finding(a: FindingKey, b: FindingKey, tolerance: int = LINE_TOLERANCE) -> bool:
|
|
184
|
+
"""True when two keys denote the same finding: identical stable hash and
|
|
185
|
+
lines within `tolerance`."""
|
|
186
|
+
return a.signature == b.signature and abs(a.line - b.line) <= tolerance
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def match_carried(key: FindingKey, prior_keys, tolerance: int = LINE_TOLERANCE):
|
|
190
|
+
"""Return the prior key this finding carries forward from, or `None` when
|
|
191
|
+
it is genuinely new."""
|
|
192
|
+
for prior in prior_keys:
|
|
193
|
+
candidate = prior if isinstance(prior, FindingKey) else FindingKey(*prior)
|
|
194
|
+
if same_finding(key, candidate, tolerance):
|
|
195
|
+
return candidate
|
|
196
|
+
return None
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def is_actionable(finding: dict) -> bool:
|
|
200
|
+
"""The severity floor (rounds >= 2): only error/warning findings at
|
|
201
|
+
high/medium confidence justify another fix-dispatch round.
|
|
202
|
+
|
|
203
|
+
Round 1 keeps `/code-review` step 5b's existing actionability table
|
|
204
|
+
unchanged — this predicate governs round 2 onward only, where the
|
|
205
|
+
question is "does this finding justify paying for another round?" rather
|
|
206
|
+
than "should this be fixed at all?". A suggestion-tier finding from a
|
|
207
|
+
later round is still recorded and still written to `corrections/`; it
|
|
208
|
+
just never triggers a re-dispatch.
|
|
209
|
+
"""
|
|
210
|
+
severity = str(finding.get("severity", "")).lower()
|
|
211
|
+
confidence = str(finding.get("confidence", "")).lower()
|
|
212
|
+
return severity in ACTIONABLE_SEVERITIES and confidence in ACTIONABLE_CONFIDENCES
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def classify_round(findings, prior_keys, round_number: int) -> dict:
|
|
216
|
+
"""Split one round's findings into new / carried, and decide whether the
|
|
217
|
+
loop continues.
|
|
218
|
+
|
|
219
|
+
Returns a dict with:
|
|
220
|
+
`new`, `carried` — finding lists
|
|
221
|
+
`new_keys` — `[[signature, line], ...]` for the durable ledger
|
|
222
|
+
`all_keys` — every key seen through this round (for the next call)
|
|
223
|
+
`actionable_new` — new findings clearing the severity floor
|
|
224
|
+
`terminate` — True when the loop must stop
|
|
225
|
+
`reason` — `converged` | `round-cap` | `null` (continue)
|
|
226
|
+
|
|
227
|
+
Termination rules, first match wins (issue #1625 design item 3):
|
|
228
|
+
|
|
229
|
+
1. **Hard round cap** — `round_number >= MAX_ROUNDS` escalates to a human
|
|
230
|
+
with the ledger as evidence, whatever was found.
|
|
231
|
+
2. **Loop-until-dry** — a round producing zero *new-signature* findings
|
|
232
|
+
that clear the severity floor is converged. Carried signatures that
|
|
233
|
+
survived a fix attempt are already handled by the existing "same
|
|
234
|
+
issues persist -> escalate" exit, so they are not a reason to continue
|
|
235
|
+
here.
|
|
236
|
+
3. Otherwise the loop continues.
|
|
237
|
+
|
|
238
|
+
Round 1 never terminates on rule 2 with findings outstanding: its
|
|
239
|
+
actionability is step 5b's table, not this severity floor. Callers pass
|
|
240
|
+
`round_number=1` for the initial panel and it is treated as continuing
|
|
241
|
+
whenever any finding is actionable under either definition.
|
|
242
|
+
"""
|
|
243
|
+
prior = [p if isinstance(p, FindingKey) else FindingKey(*p) for p in prior_keys]
|
|
244
|
+
new, carried = [], []
|
|
245
|
+
keys_this_round = []
|
|
246
|
+
for finding in findings:
|
|
247
|
+
if not isinstance(finding, dict):
|
|
248
|
+
continue
|
|
249
|
+
key = finding_key(finding)
|
|
250
|
+
keys_this_round.append(key)
|
|
251
|
+
if match_carried(key, prior) is None:
|
|
252
|
+
new.append(finding)
|
|
253
|
+
else:
|
|
254
|
+
carried.append(finding)
|
|
255
|
+
|
|
256
|
+
actionable_new = [f for f in new if is_actionable(f)]
|
|
257
|
+
|
|
258
|
+
if round_number >= MAX_ROUNDS:
|
|
259
|
+
terminate, reason = True, "round-cap"
|
|
260
|
+
elif not actionable_new:
|
|
261
|
+
terminate, reason = True, "converged"
|
|
262
|
+
else:
|
|
263
|
+
terminate, reason = False, None
|
|
264
|
+
|
|
265
|
+
seen = list(prior)
|
|
266
|
+
for key in keys_this_round:
|
|
267
|
+
if match_carried(key, seen) is None:
|
|
268
|
+
seen.append(key)
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
"round": round_number,
|
|
272
|
+
"new": new,
|
|
273
|
+
"carried": carried,
|
|
274
|
+
"new_keys": [list(finding_key(f)) for f in new],
|
|
275
|
+
"all_keys": [list(k) for k in seen],
|
|
276
|
+
"actionable_new": actionable_new,
|
|
277
|
+
"terminate": terminate,
|
|
278
|
+
"reason": reason,
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
#: A stored ledger older than this is discarded rather than reused. A review
|
|
283
|
+
#: run does not legitimately span a day; a state file that old is abandoned
|
|
284
|
+
#: residue, and reusing it would suppress genuinely-new findings as "carried"
|
|
285
|
+
#: against signatures from unrelated work.
|
|
286
|
+
STATE_TTL_SECONDS = 24 * 60 * 60
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def _now_iso() -> str:
|
|
290
|
+
from datetime import datetime, timezone
|
|
291
|
+
|
|
292
|
+
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def _age_seconds(iso: str) -> float | None:
|
|
296
|
+
from datetime import datetime, timezone
|
|
297
|
+
|
|
298
|
+
try:
|
|
299
|
+
stamp = datetime.strptime(iso, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=timezone.utc)
|
|
300
|
+
except (TypeError, ValueError):
|
|
301
|
+
return None
|
|
302
|
+
return (datetime.now(timezone.utc) - stamp).total_seconds()
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def _empty_state() -> dict:
|
|
306
|
+
return {"rounds": [], "all_keys": [], "run_id": None, "started_at": None}
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def _load_state(state_path, run_id, round_number: int, force_reset: bool):
|
|
310
|
+
"""Load the durable ledger, discarding it when it belongs to a different
|
|
311
|
+
run. Returns `(state, reset_reason)`; `reset_reason` is `None` when a
|
|
312
|
+
stored ledger was legitimately resumed.
|
|
313
|
+
|
|
314
|
+
Four reset triggers, in precedence order — each one exists because
|
|
315
|
+
reusing the ledger in that situation would silently misclassify a genuinely
|
|
316
|
+
new finding as "carried" (suppressing a round that should have run) or
|
|
317
|
+
inflate the round counter toward the cap on unrelated history:
|
|
318
|
+
|
|
319
|
+
1. `--reset` — explicit.
|
|
320
|
+
2. **Round 1** — the initial panel *is* the start of a new run by
|
|
321
|
+
definition. This is the common case and needs no caller bookkeeping:
|
|
322
|
+
`/code-review` always calls round 1 first, so an abandoned ledger from
|
|
323
|
+
a previous review can never leak into the next one. `/continue`
|
|
324
|
+
resuming mid-loop calls round >= 2 and correctly resumes.
|
|
325
|
+
3. **`run_id` mismatch** — the stored ledger was built for a different
|
|
326
|
+
changeset. Catches a resume that legitimately starts at round >= 2 but
|
|
327
|
+
against different targets.
|
|
328
|
+
4. **Staleness** — `STATE_TTL_SECONDS` since the run started.
|
|
329
|
+
|
|
330
|
+
Fails toward a reset: an unreadable or malformed state file starts fresh
|
|
331
|
+
rather than propagating a half-parsed ledger. Starting fresh only ever
|
|
332
|
+
costs an extra round; reusing a wrong ledger silently skips one.
|
|
333
|
+
"""
|
|
334
|
+
if state_path is None or not state_path.is_file():
|
|
335
|
+
return _empty_state(), None
|
|
336
|
+
|
|
337
|
+
if force_reset:
|
|
338
|
+
return _empty_state(), "explicit-reset"
|
|
339
|
+
if round_number <= 1:
|
|
340
|
+
return _empty_state(), "new-run-round-1"
|
|
341
|
+
|
|
342
|
+
try:
|
|
343
|
+
stored = json.loads(state_path.read_text("utf-8"))
|
|
344
|
+
except (OSError, ValueError):
|
|
345
|
+
return _empty_state(), "unreadable-state"
|
|
346
|
+
if not isinstance(stored, dict):
|
|
347
|
+
return _empty_state(), "unreadable-state"
|
|
348
|
+
|
|
349
|
+
if run_id is not None and stored.get("run_id") != run_id:
|
|
350
|
+
return _empty_state(), "run-id-mismatch"
|
|
351
|
+
|
|
352
|
+
age = _age_seconds(stored.get("started_at"))
|
|
353
|
+
if age is not None and age > STATE_TTL_SECONDS:
|
|
354
|
+
return _empty_state(), "stale-state"
|
|
355
|
+
|
|
356
|
+
stored.setdefault("rounds", [])
|
|
357
|
+
stored.setdefault("all_keys", [])
|
|
358
|
+
return stored, None
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def main(argv=None) -> int:
|
|
362
|
+
parser = argparse.ArgumentParser(
|
|
363
|
+
description="Classify one review round's findings against the prior rounds' ledger."
|
|
364
|
+
)
|
|
365
|
+
parser.add_argument("--round", type=int, required=True, dest="round_number")
|
|
366
|
+
parser.add_argument(
|
|
367
|
+
"--findings", default="-", help="Path to this round's findings JSON; '-' for stdin"
|
|
368
|
+
)
|
|
369
|
+
parser.add_argument(
|
|
370
|
+
"--state",
|
|
371
|
+
default=None,
|
|
372
|
+
help="Path to the durable round-ledger state file (read + rewritten in place)",
|
|
373
|
+
)
|
|
374
|
+
parser.add_argument(
|
|
375
|
+
"--run-id",
|
|
376
|
+
default=None,
|
|
377
|
+
dest="run_id",
|
|
378
|
+
help=(
|
|
379
|
+
"Stable identity for this review run (e.g. the digest of the sorted "
|
|
380
|
+
"target-file list). A stored ledger with a different run_id belongs "
|
|
381
|
+
"to another changeset and is discarded rather than reused."
|
|
382
|
+
),
|
|
383
|
+
)
|
|
384
|
+
parser.add_argument(
|
|
385
|
+
"--reset",
|
|
386
|
+
action="store_true",
|
|
387
|
+
help="Discard any stored ledger and start a fresh run.",
|
|
388
|
+
)
|
|
389
|
+
args = parser.parse_args(argv)
|
|
390
|
+
|
|
391
|
+
from pathlib import Path
|
|
392
|
+
|
|
393
|
+
raw = sys.stdin.read() if args.findings == "-" else Path(args.findings).read_text("utf-8")
|
|
394
|
+
data = json.loads(raw) if raw.strip() else []
|
|
395
|
+
if isinstance(data, dict):
|
|
396
|
+
data = data.get("findings", [])
|
|
397
|
+
|
|
398
|
+
state_path = Path(args.state) if args.state else None
|
|
399
|
+
state, reset_reason = _load_state(state_path, args.run_id, args.round_number, args.reset)
|
|
400
|
+
|
|
401
|
+
result = classify_round(data, state.get("all_keys", []), args.round_number)
|
|
402
|
+
|
|
403
|
+
if state_path is not None:
|
|
404
|
+
state["all_keys"] = result["all_keys"]
|
|
405
|
+
state["run_id"] = args.run_id
|
|
406
|
+
# `setdefault` is wrong here: `_empty_state()` seeds an explicit None,
|
|
407
|
+
# which setdefault would preserve — leaving every fresh run with no
|
|
408
|
+
# start time and so permanently exempt from the staleness TTL.
|
|
409
|
+
if not state.get("started_at"):
|
|
410
|
+
state["started_at"] = _now_iso()
|
|
411
|
+
state["updated_at"] = _now_iso()
|
|
412
|
+
state.setdefault("rounds", []).append(
|
|
413
|
+
{
|
|
414
|
+
"round": result["round"],
|
|
415
|
+
"new": len(result["new"]),
|
|
416
|
+
"carried": len(result["carried"]),
|
|
417
|
+
"actionable_new": len(result["actionable_new"]),
|
|
418
|
+
"terminate": result["terminate"],
|
|
419
|
+
"reason": result["reason"],
|
|
420
|
+
}
|
|
421
|
+
)
|
|
422
|
+
try:
|
|
423
|
+
state_path.parent.mkdir(parents=True, exist_ok=True)
|
|
424
|
+
state_path.write_text(json.dumps(state, indent=2, sort_keys=True) + "\n", "utf-8")
|
|
425
|
+
except OSError as exc:
|
|
426
|
+
sys.stderr.write(f"[finding_signature] could not write {state_path}: {exc}\n")
|
|
427
|
+
|
|
428
|
+
print(
|
|
429
|
+
json.dumps(
|
|
430
|
+
{
|
|
431
|
+
"round": result["round"],
|
|
432
|
+
"new": len(result["new"]),
|
|
433
|
+
"carried": len(result["carried"]),
|
|
434
|
+
"actionable_new": len(result["actionable_new"]),
|
|
435
|
+
"ledger_reset": reset_reason,
|
|
436
|
+
"terminate": result["terminate"],
|
|
437
|
+
"reason": result["reason"],
|
|
438
|
+
},
|
|
439
|
+
sort_keys=True,
|
|
440
|
+
)
|
|
441
|
+
)
|
|
442
|
+
return 0
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
if __name__ == "__main__":
|
|
446
|
+
raise SystemExit(main(sys.argv[1:]))
|