claude-dev-env 1.94.0 → 2.0.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/_shared/advisor/CLAUDE.md +2 -2
- package/_shared/advisor/advisor-protocol.md +41 -33
- package/_shared/advisor/scripts/config/advisor_scripts_constants/model_tier_run_validator_constants.py +17 -13
- package/_shared/advisor/scripts/model_tier_run_validator.py +27 -18
- package/_shared/advisor/scripts/tests/test_model_tier_run_validator.py +95 -25
- package/_shared/advisor/scripts/tests/test_tier_model_ids.py +17 -17
- package/_shared/advisor/scripts/tier_model_ids.py +18 -18
- package/_shared/pr-loop/CLAUDE.md +1 -0
- package/_shared/pr-loop/scripts/CLAUDE.md +2 -1
- package/_shared/pr-loop/scripts/README.md +1 -0
- package/_shared/pr-loop/scripts/code_rules_gate.py +253 -1980
- package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +32 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/__init__.py +7 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/added_line_maps.py +268 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/enforcer_loading.py +172 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/gate_arguments.py +70 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/gate_running.py +326 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/git_blob_readers.py +85 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/git_file_sets.py +331 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_running.py +369 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/conftest.py +14 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_added_line_maps.py +118 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_enforcer_loading.py +17 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_gate_arguments.py +29 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_gate_running.py +99 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_git_blob_readers.py +69 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_git_file_sets.py +137 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_staged_test_running.py +116 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_violation_scoping.py +75 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_wrapper_plumb_check.py +49 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/violation_scoping.py +328 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/wrapper_plumb_check.py +206 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/code_rules_gate_constants.py +24 -17
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/reviews_disabled_constants.py +1 -0
- package/_shared/pr-loop/scripts/reviews_disabled.py +19 -2
- package/_shared/pr-loop/scripts/test_code_rules_gate.py +278 -0
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate_constants.py +6 -39
- package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +43 -0
- package/_shared/pr-loop/worker-spawn.md +186 -0
- package/agents/code-verifier.md +1 -1
- package/bin/CLAUDE.md +10 -1
- package/bin/ever-shipped-skills.mjs +73 -0
- package/bin/expand_home_directory_tokens.mjs +1 -1
- package/bin/install.mjs +140 -7
- package/bin/install.prune.test.mjs +457 -0
- package/docs/CODE_RULES.md +1 -1
- package/hooks/advisory/refactor_guard.py +3 -4
- package/hooks/blocking/CLAUDE.md +7 -1
- package/hooks/blocking/block_main_commit.py +2 -2
- package/hooks/blocking/claude_md_orphan_file_blocker.py +75 -699
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/CLAUDE.md +28 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/__init__.py +1 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/config/__init__.py +1 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/config/orphan_blocker_constants.py +18 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/decision.py +81 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/references.py +307 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/scan_plan.py +124 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/subtree_scan.py +179 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/conftest.py +10 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_decision.py +34 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_references.py +42 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_scan_plan.py +27 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_subtree_scan.py +30 -0
- package/hooks/blocking/code_rules_boolean_mustcheck.py +1 -1
- package/hooks/blocking/code_rules_enforcer.py +4 -0
- package/hooks/blocking/code_rules_mock_completeness.py +1 -1
- package/hooks/blocking/code_rules_optional_params.py +2 -2
- package/hooks/blocking/code_rules_shared.py +83 -1
- package/hooks/blocking/code_rules_test_assertions.py +1 -1
- package/hooks/blocking/code_rules_test_layout.py +9 -3
- package/hooks/blocking/code_rules_typeddict_stub.py +1 -1
- package/hooks/blocking/gh_pr_author_enforcer.py +1 -1
- package/hooks/blocking/inventory_intent_records/CLAUDE.md +26 -0
- package/hooks/blocking/inventory_intent_records/__init__.py +1 -0
- package/hooks/blocking/inventory_intent_records/config/__init__.py +1 -0
- package/hooks/blocking/inventory_intent_records/config/intent_records_constants.py +20 -0
- package/hooks/blocking/inventory_intent_records/records.py +271 -0
- package/hooks/blocking/inventory_intent_records/tests/conftest.py +10 -0
- package/hooks/blocking/inventory_intent_records/tests/test_records.py +80 -0
- package/hooks/blocking/package_inventory_stale_blocker.py +54 -384
- package/hooks/blocking/package_inventory_stale_blocker_parts/CLAUDE.md +26 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/__init__.py +1 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/config/__init__.py +1 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/config/inventory_blocker_constants.py +16 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/decision.py +84 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/inventory_detection.py +307 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/tests/conftest.py +10 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/tests/test_decision.py +38 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/tests/test_inventory_detection.py +61 -0
- package/hooks/blocking/pii_payload_scan.py +138 -42
- package/hooks/blocking/pii_prevention_blocker.py +185 -291
- package/hooks/blocking/pii_prevention_blocker_parts/CLAUDE.md +24 -0
- package/hooks/blocking/pii_prevention_blocker_parts/__init__.py +1 -0
- package/hooks/blocking/pii_prevention_blocker_parts/config/__init__.py +1 -0
- package/hooks/blocking/pii_prevention_blocker_parts/config/repository_resolution_constants.py +28 -0
- package/hooks/blocking/pii_prevention_blocker_parts/repository_exemption.py +214 -0
- package/hooks/blocking/pii_prevention_blocker_parts/repository_resolution.py +208 -0
- package/hooks/blocking/plain_language_blocker.py +138 -4
- package/hooks/blocking/pr_description_command_parser.py +8 -4
- package/hooks/blocking/precommit_code_rules_gate.py +3 -3
- package/hooks/blocking/sensitive_file_protector.py +114 -48
- package/hooks/blocking/tdd_enforcer.py +97 -601
- package/hooks/blocking/tdd_enforcer_parts/CLAUDE.md +30 -0
- package/hooks/blocking/tdd_enforcer_parts/__init__.py +1 -0
- package/hooks/blocking/tdd_enforcer_parts/candidate_paths.py +142 -0
- package/hooks/blocking/tdd_enforcer_parts/config/__init__.py +1 -0
- package/hooks/blocking/tdd_enforcer_parts/config/tdd_enforcer_constants.py +32 -0
- package/hooks/blocking/tdd_enforcer_parts/content_analysis.py +268 -0
- package/hooks/blocking/tdd_enforcer_parts/decisions.py +92 -0
- package/hooks/blocking/tdd_enforcer_parts/freshness.py +80 -0
- package/hooks/blocking/tdd_enforcer_parts/git_tracking.py +63 -0
- package/hooks/blocking/tdd_enforcer_parts/path_classification.py +119 -0
- package/hooks/blocking/tdd_enforcer_parts/tests/conftest.py +10 -0
- package/hooks/blocking/tdd_enforcer_parts/tests/test_candidate_paths.py +31 -0
- package/hooks/blocking/tdd_enforcer_parts/tests/test_content_analysis.py +30 -0
- package/hooks/blocking/tdd_enforcer_parts/tests/test_decisions.py +34 -0
- package/hooks/blocking/tdd_enforcer_parts/tests/test_freshness.py +28 -0
- package/hooks/blocking/tdd_enforcer_parts/tests/test_git_tracking.py +48 -0
- package/hooks/blocking/tdd_enforcer_parts/tests/test_path_classification.py +36 -0
- package/hooks/blocking/test_code_rules_enforcer_scratchpad.py +105 -0
- package/hooks/blocking/test_code_rules_shared.py +181 -0
- package/hooks/blocking/test_inventory_deadlock_resolution.py +154 -0
- package/hooks/blocking/test_pii_payload_scan.py +168 -0
- package/hooks/blocking/test_plain_language_blocker_allowlist.py +184 -0
- package/hooks/blocking/test_sensitive_file_protector.py +185 -0
- package/hooks/blocking/test_tdd_enforcer_restore.py +108 -0
- package/hooks/blocking/test_tdd_enforcer_scratchpad.py +105 -0
- package/hooks/blocking/tests/conftest.py +10 -0
- package/hooks/blocking/tests/test_pii_prevention_blocker.py +260 -0
- package/hooks/blocking/tests/test_repository_exemption.py +105 -0
- package/hooks/blocking/tests/test_repository_resolution.py +108 -0
- package/hooks/diagnostic/hook_log_extractor.py +12 -10
- package/hooks/git-hooks/post_commit.py +3 -4
- package/hooks/hooks_constants/CLAUDE.md +4 -2
- package/hooks/hooks_constants/banned_identifiers_constants.py +0 -1
- package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -1
- package/hooks/hooks_constants/harness_scratchpad_constants.py +17 -0
- package/hooks/hooks_constants/local_identity.py +59 -8
- package/hooks/hooks_constants/pii_prevention_constants.py +0 -6
- package/hooks/hooks_constants/plain_language_blocker_constants.py +5 -0
- package/hooks/hooks_constants/sensitive_file_protector_constants.py +42 -0
- package/hooks/hooks_constants/test_local_identity.py +105 -3
- package/hooks/pyproject.toml +52 -4
- package/hooks/session/plugin_data_dir_cleanup.py +0 -1
- package/hooks/validation/mypy_validator.py +2 -2
- package/hooks/validators/CLAUDE.md +1 -1
- package/hooks/validators/README.md +2 -0
- package/hooks/validators/health_check.py +1 -0
- package/hooks/validators/mypy_integration.py +2 -0
- package/hooks/validators/python_style_checks.py +114 -136
- package/hooks/validators/python_style_helpers.py +95 -0
- package/hooks/validators/ruff_integration.py +3 -0
- package/hooks/validators/test_python_style_checks.py +0 -164
- package/hooks/validators/test_python_style_checks_decorator_gap.py +119 -0
- package/hooks/validators/test_python_style_fixes.py +251 -0
- package/hooks/validators/test_python_style_helpers.py +125 -0
- package/hooks/workflow/auto_formatter.py +5 -4
- package/package.json +1 -1
- package/rules/CLAUDE.md +1 -0
- package/rules/anti-corollary-tests.md +69 -0
- package/rules/bdd.md +1 -3
- package/rules/code-reviews.md +1 -1
- package/rules/gh-paginate.md +1 -1
- package/rules/plain-language.md +2 -0
- package/scripts/CLAUDE.md +4 -0
- package/scripts/dev_env_scripts_constants/CLAUDE.md +6 -4
- package/scripts/dev_env_scripts_constants/code_review_constants.py +71 -0
- package/scripts/dev_env_scripts_constants/grok_worker_constants.py +435 -0
- package/scripts/dev_env_scripts_constants/timing.py +7 -1
- package/scripts/grok_headless_runner.py +294 -0
- package/scripts/grok_worker_preflight.py +410 -0
- package/scripts/invoke_code_review.py +463 -0
- package/scripts/resolve_worker_spawn.py +619 -0
- package/scripts/spawn_grok_batch.py +672 -0
- package/scripts/test_grok_headless_runner.py +626 -0
- package/scripts/test_grok_worker_preflight.py +1054 -0
- package/scripts/test_invoke_code_review.py +672 -0
- package/scripts/test_resolve_worker_spawn.py +1014 -0
- package/scripts/test_spawn_grok_batch.py +1017 -0
- package/skills/CLAUDE.md +6 -3
- package/skills/_shared/pr-loop/scripts/build_audit_prompt.py +72 -13
- package/skills/_shared/pr-loop/scripts/build_fix_prompt.py +121 -14
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +78 -0
- package/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +121 -0
- package/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +196 -6
- package/skills/autoconverge/CLAUDE.md +3 -3
- package/skills/autoconverge/SKILL.md +9 -3
- package/skills/autoconverge/reference/CLAUDE.md +2 -2
- package/skills/autoconverge/reference/convergence.md +33 -11
- package/skills/autoconverge/reference/stop-conditions.md +16 -5
- package/skills/autoconverge/workflow/CLAUDE.md +2 -1
- package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +7 -2
- package/skills/autoconverge/workflow/converge.codex-gate.test.mjs +300 -0
- package/skills/autoconverge/workflow/converge.contract.test.mjs +5 -5
- package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +29 -29
- package/skills/autoconverge/workflow/converge.fix-progress.test.mjs +1 -1
- package/skills/autoconverge/workflow/converge.mjs +202 -18
- package/skills/bugteam/CLAUDE.md +2 -2
- package/skills/bugteam/CONSTRAINTS.md +3 -2
- package/skills/bugteam/PROMPTS.md +7 -6
- package/skills/bugteam/SKILL.md +18 -13
- package/skills/bugteam/reference/README.md +2 -3
- package/skills/bugteam/reference/audit-and-teammates.md +215 -35
- package/skills/bugteam/reference/design-rationale.md +1 -1
- package/skills/bugteam/reference/obstacles/CLAUDE.md +1 -1
- package/skills/bugteam/reference/team-setup.md +8 -2
- package/skills/closeout/SKILL.md +153 -0
- package/skills/closeout/reference/handoff-prompt-template.md +72 -0
- package/skills/closeout/reference/issue-body-templates.md +108 -0
- package/skills/closeout/reference/pii-redaction-checklist.md +36 -0
- package/skills/codex-review/CLAUDE.md +46 -0
- package/skills/codex-review/SKILL.md +181 -0
- package/skills/codex-review/reference/CLAUDE.md +15 -0
- package/skills/codex-review/reference/cli-contract.md +253 -0
- package/skills/codex-review/reference/loop-integration.md +118 -0
- package/skills/codex-review/scripts/codex_down_classifier.py +98 -0
- package/skills/codex-review/scripts/codex_review_scripts_constants/CLAUDE.md +18 -0
- package/skills/codex-review/scripts/codex_review_scripts_constants/__init__.py +1 -0
- package/skills/codex-review/scripts/codex_review_scripts_constants/classifier_constants.py +35 -0
- package/skills/codex-review/scripts/codex_review_scripts_constants/codex_usage_probe_constants.py +86 -0
- package/skills/codex-review/scripts/codex_review_scripts_constants/findings_constants.py +18 -0
- package/skills/codex-review/scripts/codex_review_scripts_constants/run_constants.py +45 -0
- package/skills/codex-review/scripts/codex_usage_probe.py +573 -0
- package/skills/codex-review/scripts/fixtures/auth_failure_synthetic.txt +1 -0
- package/skills/codex-review/scripts/fixtures/config_load_failure_v0.125.0.txt +1 -0
- package/skills/codex-review/scripts/fixtures/freeform_findings_v0.144.3.txt +6 -0
- package/skills/codex-review/scripts/fixtures/model_rejection_v0.125.0.jsonl +5 -0
- package/skills/codex-review/scripts/fixtures/structured_findings.txt +13 -0
- package/skills/codex-review/scripts/fixtures/success_stream_v0.144.3.jsonl +6 -0
- package/skills/codex-review/scripts/fixtures/unknown_failure_synthetic.txt +1 -0
- package/skills/codex-review/scripts/fixtures/usage_limit_synthetic.txt +1 -0
- package/skills/codex-review/scripts/parse_codex_findings.py +207 -0
- package/skills/codex-review/scripts/run_codex_review.py +415 -0
- package/skills/codex-review/scripts/test_codex_down_classifier.py +143 -0
- package/skills/codex-review/scripts/test_codex_usage_probe.py +678 -0
- package/skills/codex-review/scripts/test_parse_codex_findings.py +130 -0
- package/skills/codex-review/scripts/test_run_codex_review.py +812 -0
- package/skills/codex-review/test_skill_scaffold.py +192 -0
- package/skills/grok-spawn/CLAUDE.md +28 -0
- package/skills/grok-spawn/SKILL.md +226 -0
- package/skills/grok-spawn/reference/flag-profiles.md +132 -0
- package/skills/grok-spawn/reference/worker-briefs.md +152 -0
- package/skills/grokify/SKILL.md +9 -1
- package/skills/grokify/capability-claims.test.mjs +28 -0
- package/skills/grokify/evals/README.md +72 -0
- package/skills/grokify/evals/parse-payload.test.mjs +171 -0
- package/skills/grokify/evals/run-capability-evals.mjs +545 -0
- package/skills/orchestrator/SKILL.md +32 -22
- package/skills/orchestrator-refresh/SKILL.md +12 -8
- package/skills/pr-converge/CLAUDE.md +1 -1
- package/skills/pr-converge/SKILL.md +34 -13
- package/skills/pr-converge/reference/convergence-gates.md +42 -15
- package/skills/pr-converge/reference/fix-protocol.md +1 -1
- package/skills/pr-converge/reference/ground-rules.md +1 -1
- package/skills/pr-converge/reference/per-tick.md +130 -42
- package/skills/pr-converge/reference/state-schema.md +10 -0
- package/skills/pr-converge/scripts/CLAUDE.md +2 -0
- package/skills/pr-converge/scripts/_pr_converge_path_setup.py +5 -1
- package/skills/pr-converge/scripts/check_convergence.py +605 -29
- package/skills/pr-converge/scripts/check_convergence_availability.py +232 -0
- package/skills/pr-converge/scripts/check_convergence_gates.py +279 -235
- package/skills/pr-converge/scripts/check_convergence_thread_gates.py +1 -1
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/convergence_gate_constants.py +36 -2
- package/skills/pr-converge/scripts/test__pr_converge_path_setup.py +4 -0
- package/skills/pr-converge/scripts/test_check_convergence.py +71 -3
- package/skills/pr-converge/scripts/test_check_convergence_availability.py +326 -0
- package/skills/pr-converge/scripts/test_check_convergence_codex.py +507 -0
- package/skills/pr-converge/scripts/test_check_convergence_contract.py +89 -17
- package/skills/pr-converge/scripts/test_check_convergence_fixture.py +179 -0
- package/skills/pr-converge/scripts/test_check_convergence_gates.py +84 -68
- package/skills/pr-converge/scripts/test_check_convergence_thread_gates.py +24 -0
- package/skills/pr-converge/test_step5_host_branch.py +106 -0
- package/skills/pr-fix-protocol/SKILL.md +65 -0
- package/skills/pr-loop-cloud-transport/SKILL.md +2 -0
- package/skills/reviewer-gates/SKILL.md +7 -5
- package/skills/skill-builder/references/skill-modularity.md +1 -1
- package/skills/team-advisor/SKILL.md +16 -12
- package/system-prompts/software-engineer.xml +7 -6
- package/hooks/validators/test_verify_paths.py +0 -32
- package/hooks/validators/verify_paths.py +0 -57
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pr-fix-protocol
|
|
3
|
+
description: >-
|
|
4
|
+
Applies reviewer findings to a PR as verified fixes and drives unresolved
|
|
5
|
+
review threads to zero. Invoked by PR-loop orchestrators (pr-converge,
|
|
6
|
+
autoconverge, bugteam, qbug, copilot-review) when a reviewer reports
|
|
7
|
+
findings; not for ad-hoc 'fix this bug' requests outside a PR loop.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# PR Fix Protocol
|
|
11
|
+
|
|
12
|
+
**Core principle:** a finding is addressed only when the fix is pushed, the thread carries a reply, and the thread is resolved — as one unit of work. Anything short of all three leaves a convergence gate stalled.
|
|
13
|
+
|
|
14
|
+
## How callers invoke this
|
|
15
|
+
|
|
16
|
+
- **Skill-capable contexts** (a lead session that holds the `Skill` tool): `Skill({skill: "pr-fix-protocol", args: "--skill <caller> --pr <URL> --worktree <path> [findings payload or 'sweep']"})`.
|
|
17
|
+
- **Fallback** (a subagent or teammate without the `Skill` tool): the caller's spawn prompt says to read `~/.claude/skills/pr-fix-protocol/SKILL.md` and apply it with the parameters below.
|
|
18
|
+
|
|
19
|
+
The caller passes: its identity, the PR scope, the PR worktree path, this round's findings (or `sweep` for a thread sweep with no fresh findings), and its post-push obligations — which clean-SHA state fields to reset and which reviewers to re-trigger.
|
|
20
|
+
|
|
21
|
+
## Executor choice
|
|
22
|
+
|
|
23
|
+
- **Single-PR loops** (no shared `state.json`): the lead spawns `Agent(subagent_type: "clean-coder")` to write the fix. Stop when `Agent` is unavailable. A spawned clean-coder starts in its own working directory, so its prompt names the PR worktree path and directs it to edit, stage, and commit there.
|
|
24
|
+
- **Multi-PR orchestration** (shared `state.json`): a per-PR clean-coder teammate owns edits, replies, and state writes; the orchestrator holds back from inline edits. The teammate obligations — reply before writing state, which state fields to set, idle handoff — live in the calling skill's multi-PR reference.
|
|
25
|
+
|
|
26
|
+
Run every git command in the PR worktree. `git add`, `git commit`, and `git push` act on the repo of the current working directory, so a cross-repo PR's fix lands in the PR's repo only when the working directory is its worktree.
|
|
27
|
+
|
|
28
|
+
## The fix sequence
|
|
29
|
+
|
|
30
|
+
Follow the shared 13-step sequence in [`_shared/pr-loop/fix-protocol.md`](../../_shared/pr-loop/fix-protocol.md) exactly: read each file:line, capture the pre-fix SHA and contents, write a failing test first where the finding has behavior, apply the fix narrowly, `py_compile`, run the post-fix self-audit, stage by explicit path, make one commit, fast-forward push, then reply and resolve atomically per thread. Its Constraints section — narrow scope, keep the commit hooks, preserve helpers — binds every executor.
|
|
31
|
+
|
|
32
|
+
**Reply transport:** the GitHub MCP `add_reply_to_pull_request_comment` is primary. For a script-only context or a multi-PR teammate, the fallback is `python "$HOME/.claude/skills/pr-converge/scripts/post_fix_reply.py" --owner <O> --repo <R> --pr-number <N> --in-reply-to <COMMENT_ID> --body "Fixed in <SHA> — <what changed>"`. Both carry the body shape from [`_shared/pr-loop/audit-reply-template.md`](../../_shared/pr-loop/audit-reply-template.md). For a body-only finding with no inline thread, post a top-level review reply that cites the new HEAD SHA.
|
|
33
|
+
|
|
34
|
+
**Thread resolution:** call `pull_request_review_write(method="resolve_thread", threadId=<PRRT node id>)` right after each reply. Harvest the thread node ids (`PRRT_…`) from `get_review_comments` at fetch time.
|
|
35
|
+
|
|
36
|
+
## The unresolved-thread sweep (hard gate)
|
|
37
|
+
|
|
38
|
+
A caller advances a phase, records a clean SHA, or marks a PR ready only when the PR carries zero unresolved review threads.
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
pull_request_read(method="get_review_comments") → filter threads where is_resolved == false
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- The filter is purely `is_resolved == false`. Author, anchor commit, and `is_outdated` play no part in the count.
|
|
45
|
+
- `is_outdated` is informational, not a skip flag. GitHub marks a thread outdated when its anchor line changes, yet the concern can still apply to current HEAD — the fix may have moved rather than landed. Verify each outdated thread against current HEAD like any other.
|
|
46
|
+
- Per unresolved thread: verify the concern against current HEAD. The concern holds → fix (this protocol) → reply → resolve. The concern does not hold on current HEAD → reply with a note that explains why → resolve.
|
|
47
|
+
- Code changed during the sweep → push and hand control back to the caller's re-entry phase. Only resolutions and no code → re-run the sweep and keep the caller's state.
|
|
48
|
+
|
|
49
|
+
## Post-push obligations
|
|
50
|
+
|
|
51
|
+
Every push through this protocol:
|
|
52
|
+
|
|
53
|
+
1. Re-resolve `current_head` — `git rev-parse HEAD` locally, and the PR `get` call for API-visible state.
|
|
54
|
+
2. Reset the caller-named clean-SHA fields to null (`bugbot_clean_at`, `code_review_clean_at`, `copilot_clean_at` — whichever the caller tracks). A new HEAD invalidates every prior clean.
|
|
55
|
+
3. Re-trigger reviewers per the caller's parameter — for Cursor Bugbot the `reviewer-gates` Bugbot flow, for Copilot the caller's request step. Audit-family callers (`bugteam`, `qbug`) skip re-triggering, since their next loop iteration is the reviewer.
|
|
56
|
+
|
|
57
|
+
## Gotchas
|
|
58
|
+
|
|
59
|
+
- **Reply, then resolve, atomic per thread.** Batching every reply ahead of any resolve, or yielding to the orchestrator between the two, leaves threads half-addressed when a run dies mid-loop.
|
|
60
|
+
- **An unchanged HEAD after step 11 means no commit landed.** Exit `stuck — could not address findings` rather than report the findings as fixed.
|
|
61
|
+
- **A resolved thread with no reply reads as dismissed.** Reviewers and the humans reading the PR need the one-paragraph explanation the template carries.
|
|
62
|
+
|
|
63
|
+
## Folder map
|
|
64
|
+
|
|
65
|
+
- `SKILL.md` — this file. The step sequence, reply template, and payload shapes live in `_shared/pr-loop/` (`fix-protocol.md`, `audit-reply-template.md`, `gh-payloads.md`); the reply fallback script lives in `pr-converge/scripts/`.
|
|
@@ -20,6 +20,8 @@ Three checks, in order; the first failure routes to the cloud transport:
|
|
|
20
20
|
|
|
21
21
|
A read-scoped account passes checks 1 and 2 and fails check 3 — the PR-loop skills push fix commits, so `push: false` means the local path stalls at its first push while the MCP transport carries the run.
|
|
22
22
|
|
|
23
|
+
GitHub MCP substitution covers `gh` operations only. It does not make Claude-only slash commands (for example `/code-review`) runnable. Those steps go through the chain-spawn helper documented in [`worker-spawn.md`](../../_shared/pr-loop/worker-spawn.md#code-review-host-routing) (`detect_host_profile` + `invoke_code_review`). Transport (`gh` vs MCP) and harness (Claude vs third-party) are separate axes.
|
|
24
|
+
|
|
23
25
|
## Cloud transport workflow
|
|
24
26
|
|
|
25
27
|
Copy this checklist and check off items as you complete them:
|
|
@@ -20,23 +20,24 @@ Every invocation carries the caller's identity (`--skill <caller>`, e.g. `pr-con
|
|
|
20
20
|
|
|
21
21
|
## Gate 1: Reviewer opt-out (`CLAUDE_REVIEWS_DISABLED`)
|
|
22
22
|
|
|
23
|
-
The `CLAUDE_REVIEWS_DISABLED` environment variable is a comma-separated token list (case-insensitive, whitespace-tolerant).
|
|
23
|
+
The `CLAUDE_REVIEWS_DISABLED` environment variable is a comma-separated token list (case-insensitive, whitespace-tolerant). Four tokens exist:
|
|
24
24
|
|
|
25
25
|
| Token | Disables |
|
|
26
26
|
|---|---|
|
|
27
27
|
| `bugteam` | The whole bug-audit family: `/bugteam`, `/qbug`, `/findbugs`, and audit dispatch in `/monitor-open-prs` |
|
|
28
28
|
| `bugbot` | Cursor Bugbot triggering and polling |
|
|
29
29
|
| `copilot` | GitHub Copilot review requests and polling |
|
|
30
|
+
| `codex` | Codex reviewer requests and polling |
|
|
30
31
|
|
|
31
32
|
Cursor Bugbot is off by default: it runs only when `CLAUDE_REVIEWS_ENABLED` lists `bugbot`, and a `bugbot` token in `CLAUDE_REVIEWS_DISABLED` keeps it off even when the opt-in lists it.
|
|
32
33
|
|
|
33
34
|
Run the shared parser — never an inline shell parse:
|
|
34
35
|
|
|
35
36
|
```bash
|
|
36
|
-
python "$HOME/.claude/_shared/pr-loop/scripts/reviews_disabled.py" --reviewer <bugbot|bugteam|copilot>
|
|
37
|
+
python "$HOME/.claude/_shared/pr-loop/scripts/reviews_disabled.py" --reviewer <bugbot|bugteam|copilot|codex>
|
|
37
38
|
```
|
|
38
39
|
|
|
39
|
-
- **Exit 0** — the named reviewer is disabled for this run (opted out, or, for Bugbot, off by default without the `CLAUDE_REVIEWS_ENABLED` opt-in). A skill whose whole run depends on that reviewer responds with its refusal line and stops. A copilot- or bugteam-dependent caller names the opt-out: `/<caller> is disabled via CLAUDE_REVIEWS_DISABLED.` A Bugbot-dependent caller off by default names the opt-in the run needs: `/<caller> is disabled: Cursor Bugbot needs a bugbot token in CLAUDE_REVIEWS_ENABLED.` A loop that merely includes the reviewer as one gate marks the reviewer down (`bugbot_down = true`, `copilot_down = true`) and continues on its remaining signals.
|
|
40
|
+
- **Exit 0** — the named reviewer is disabled for this run (opted out, or, for Bugbot, off by default without the `CLAUDE_REVIEWS_ENABLED` opt-in). A skill whose whole run depends on that reviewer responds with its refusal line and stops. A copilot- or bugteam-dependent caller names the opt-out: `/<caller> is disabled via CLAUDE_REVIEWS_DISABLED.` A Bugbot-dependent caller off by default names the opt-in the run needs: `/<caller> is disabled: Cursor Bugbot needs a bugbot token in CLAUDE_REVIEWS_ENABLED.` A loop that merely includes the reviewer as one gate marks the reviewer down (`bugbot_down = true`, `copilot_down = true`, `codex_down = true`) and continues on its remaining signals.
|
|
40
41
|
- **Exit 1** — the reviewer is available; continue.
|
|
41
42
|
|
|
42
43
|
## Gate 2: Copilot quota pre-check (once per run)
|
|
@@ -93,11 +94,12 @@ When a reviewer is down, `check_convergence.py` must skip that reviewer's gate s
|
|
|
93
94
|
|---|---|---|
|
|
94
95
|
| Bugbot down or off | `--bugbot-down` | `bugbot` |
|
|
95
96
|
| Copilot down or opted out | `--copilot-down` | `copilot` |
|
|
97
|
+
| Codex down or opted out | `--codex-down` | `codex` |
|
|
96
98
|
| Bugteam CLEAN post blocked | `--bugteam-post-blocked` | `bugteam` |
|
|
97
99
|
|
|
98
|
-
The caller passes the flag on its own `check_convergence.py` run. The flag alone does not reach the independent mark-ready blocker hook, which re-runs `check_convergence.py` with no flags on `gh pr ready`. Each flag also honors its token: `check_convergence.py` reads the same bypass from `CLAUDE_REVIEWS_DISABLED`. So export the matching token in the same shell before `gh pr ready`, and the hook's no-flag re-check inherits the bypass through the env. Combine tokens with commas when more than one reviewer is down (`CLAUDE_REVIEWS_DISABLED="copilot,bugteam"`).
|
|
100
|
+
The caller passes the flag on its own `check_convergence.py` run. The flag alone does not reach the independent mark-ready blocker hook, which re-runs `check_convergence.py` with no flags on `gh pr ready`. Each flag also honors its token: `check_convergence.py` reads the same bypass from `CLAUDE_REVIEWS_DISABLED`. So export the matching token in the same shell before `gh pr ready`, and the hook's no-flag re-check inherits the bypass through the env. Combine tokens with commas when more than one reviewer is down (`CLAUDE_REVIEWS_DISABLED="copilot,bugteam,codex"`).
|
|
99
101
|
|
|
100
|
-
The `bugteam` token here means the bugteam CLEAN-review gate is skipped for this convergence check. It does not disable the bugbot or
|
|
102
|
+
The `bugteam` token here means the bugteam CLEAN-review gate is skipped for this convergence check. It does not disable the bugbot, copilot, or codex gates: each token is scoped to its own reviewer.
|
|
101
103
|
|
|
102
104
|
## Gotchas
|
|
103
105
|
|
|
@@ -84,7 +84,7 @@ In Process or a dedicated **Sub-skills** section:
|
|
|
84
84
|
|
|
85
85
|
| Skill | When | Produces |
|
|
86
86
|
|---|---|---|
|
|
87
|
-
| `/
|
|
87
|
+
| `/reviewer-gates` | Step 1 — gate external reviewers | opt-out, Copilot quota, Bugbot trigger decisions |
|
|
88
88
|
| `/skill-writer` | Step 4 — author SKILL.md | skill package files |
|
|
89
89
|
|
|
90
90
|
If a listed skill is not installed, respond: `[exact refusal or degrade line]`.
|
|
@@ -17,7 +17,7 @@ One warm, addressable advisor available at the strongest model tier the session
|
|
|
17
17
|
|
|
18
18
|
**Detect the host profile first** (Host profiles in
|
|
19
19
|
[`_shared/advisor/advisor-protocol.md`](../../_shared/advisor/advisor-protocol.md)
|
|
20
|
-
— e.g. `ADVISOR_HOST_PROFILE` or `
|
|
20
|
+
— e.g. `ADVISOR_HOST_PROFILE` or `THIRD_PARTY`). Do not start a model-floor
|
|
21
21
|
walk until the host is known.
|
|
22
22
|
|
|
23
23
|
This session is the shared advisor's sole consumer, so its model floor is
|
|
@@ -29,21 +29,25 @@ the CLI fallback — using `team-advisor-agent` as the name and this session as
|
|
|
29
29
|
the only consumer (skip the "who you are and your assignment" opener in each
|
|
30
30
|
consult; a single-consumer session doesn't need it).
|
|
31
31
|
|
|
32
|
-
**
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
**Third-party host:** bind a max-tier Claude advisor through the shared CLI Claude-chain
|
|
33
|
+
in the protocol (Fable max, then Opus max; `claude_chain_runner.py` walks
|
|
34
|
+
`~/.claude/claude-chain.json` for account usage failover). Consult via
|
|
35
|
+
`--resume <session_id>` on that bind. This session is the sole consumer of that
|
|
36
|
+
CLI advisor; skip the multi-consumer opener. When the chain cannot bind or
|
|
37
|
+
reply, fail closed and report to the user — do **not** answer ENDORSE /
|
|
38
|
+
CORRECTION / PLAN / STOP as this third-party session.
|
|
36
39
|
|
|
37
40
|
## Constraints
|
|
38
41
|
|
|
39
|
-
- One `team-advisor-agent`
|
|
40
|
-
|
|
42
|
+
- One advisor bind per session (`team-advisor-agent` on Claude; one CLI
|
|
43
|
+
`session_id` on a third-party host), owned by this session for its whole lifecycle
|
|
44
|
+
(spawn or CLI bind, drift re-bind, shutdown) — see
|
|
41
45
|
[`_shared/advisor/advisor-protocol.md`](../../_shared/advisor/advisor-protocol.md).
|
|
42
|
-
- Never
|
|
43
|
-
session's own tier
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
session's behalf.
|
|
46
|
+
- Never bind the advisor, or its CLI path, at a tier below the protocol floor
|
|
47
|
+
for this host (Claude: this session's own tier; a third-party host: Opus floor
|
|
48
|
+
with Fable first).
|
|
49
|
+
- The advisor only answers. It never edits a file, never runs a build or
|
|
50
|
+
test, and never posts anything on the session's behalf.
|
|
47
51
|
|
|
48
52
|
## File Index
|
|
49
53
|
|
|
@@ -140,7 +140,8 @@
|
|
|
140
140
|
Apply an outside-in BDD reasoning protocol before writing any code. Outside-in BDD is the
|
|
141
141
|
required development protocol; apply it in place of any Red-Green-Refactor heuristic. The
|
|
142
142
|
full anti-pattern catalog, Example Mapping algorithm, and solo-developer guidance live in
|
|
143
|
-
the
|
|
143
|
+
the long-form BDD references (`~/.claude/docs/BDD_DISCOVERY_PROTOCOL.md`,
|
|
144
|
+
`~/.claude/docs/BDD_SCENARIO_QUALITY.md`); this section carries the core four-phase sequence.
|
|
144
145
|
|
|
145
146
|
Deliberate Discovery. Before writing any specification or code, reason explicitly about
|
|
146
147
|
what the code should do, what constraints apply, and what concrete examples demonstrate the
|
|
@@ -159,8 +160,9 @@
|
|
|
159
160
|
it pass. Assess each green state for structural improvement; refactor when a specific
|
|
160
161
|
naming, cohesion, or duplication problem is identified.
|
|
161
162
|
|
|
162
|
-
Reference
|
|
163
|
-
algorithm, and guidance on applying this
|
|
163
|
+
Reference `~/.claude/docs/BDD_SCENARIO_QUALITY.md` and `~/.claude/docs/BDD_DISCOVERY_PROTOCOL.md`
|
|
164
|
+
for Smart and Molak §7.6 patterns, the Example Mapping algorithm, and guidance on applying this
|
|
165
|
+
protocol in a solo-developer context.
|
|
164
166
|
</behavior_protocol>
|
|
165
167
|
|
|
166
168
|
<scope_discipline>
|
|
@@ -231,11 +233,10 @@
|
|
|
231
233
|
</agent_workflow>
|
|
232
234
|
|
|
233
235
|
<code_review_response>
|
|
234
|
-
When responding to GitHub PR review feedback, follow this mandatory protocol
|
|
235
|
-
pr-review-responder skill.
|
|
236
|
+
When responding to GitHub PR review feedback, follow this mandatory protocol.
|
|
236
237
|
|
|
237
238
|
Fetch all reviewer comments before making any fixes. Obtain the full comment set from the
|
|
238
|
-
PR using `gh pr view --comments
|
|
239
|
+
PR using `gh pr view --comments`.
|
|
239
240
|
|
|
240
241
|
Create a TodoWrite checklist with one item per comment.
|
|
241
242
|
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
"""Tests for validator path verification script."""
|
|
2
|
-
|
|
3
|
-
import pytest
|
|
4
|
-
|
|
5
|
-
from .verify_paths import extract_validator_paths
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def test_extract_validator_paths_finds_validator_references() -> None:
|
|
9
|
-
"""Test that validator references are extracted from markdown content."""
|
|
10
|
-
content = """
|
|
11
|
-
**Validator:** `validators/import_checks.py`
|
|
12
|
-
Some text here.
|
|
13
|
-
**Validator:** `validators/style_checks.py`
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
result = extract_validator_paths(content)
|
|
17
|
-
|
|
18
|
-
assert "import_checks.py" in result
|
|
19
|
-
assert "style_checks.py" in result
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def test_extract_validator_paths_deduplicates() -> None:
|
|
23
|
-
"""Test that duplicate validator references are deduplicated."""
|
|
24
|
-
content = """
|
|
25
|
-
**Validator:** `validators/import_checks.py`
|
|
26
|
-
**Validator:** `validators/import_checks.py`
|
|
27
|
-
**Validator:** `validators/import_checks.py`
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
result = extract_validator_paths(content)
|
|
31
|
-
|
|
32
|
-
assert result.count("import_checks.py") == 1
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
"""Verify all validator paths referenced in SKILL.md exist."""
|
|
2
|
-
|
|
3
|
-
import re
|
|
4
|
-
import sys
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
SKILL_MD_PATH = Path(__file__).parent.parent.parent / "skills" / "pr-review-responder" / "SKILL.md"
|
|
9
|
-
VALIDATORS_DIR = Path(__file__).parent
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def extract_validator_paths(content: str) -> list[str]:
|
|
13
|
-
"""Extract validator file paths from SKILL.md content."""
|
|
14
|
-
pattern = r"validators[/\\](\w+\.py)"
|
|
15
|
-
matches = re.findall(pattern, content)
|
|
16
|
-
return list(set(matches))
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def verify_validators() -> int:
|
|
20
|
-
"""Verify all referenced validators exist.
|
|
21
|
-
|
|
22
|
-
Returns:
|
|
23
|
-
Exit code: 0 if all exist, 1 if any missing
|
|
24
|
-
"""
|
|
25
|
-
if not SKILL_MD_PATH.exists():
|
|
26
|
-
print(f"ERROR: SKILL.md not found at {SKILL_MD_PATH}")
|
|
27
|
-
return 1
|
|
28
|
-
|
|
29
|
-
content = SKILL_MD_PATH.read_text(encoding="utf-8")
|
|
30
|
-
referenced_validators = extract_validator_paths(content)
|
|
31
|
-
|
|
32
|
-
print(f"Found {len(referenced_validators)} validator references in SKILL.md")
|
|
33
|
-
print()
|
|
34
|
-
|
|
35
|
-
missing = []
|
|
36
|
-
for validator_file in sorted(referenced_validators):
|
|
37
|
-
validator_path = VALIDATORS_DIR / validator_file
|
|
38
|
-
if validator_path.exists():
|
|
39
|
-
print(f" [OK] {validator_file}")
|
|
40
|
-
else:
|
|
41
|
-
print(f" [MISSING] {validator_file}")
|
|
42
|
-
missing.append(validator_file)
|
|
43
|
-
|
|
44
|
-
print()
|
|
45
|
-
|
|
46
|
-
if missing:
|
|
47
|
-
print(f"ERROR: {len(missing)} validator(s) missing:")
|
|
48
|
-
for validator_file in missing:
|
|
49
|
-
print(f" - {validator_file}")
|
|
50
|
-
return 1
|
|
51
|
-
|
|
52
|
-
print("All referenced validators exist.")
|
|
53
|
-
return 0
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if __name__ == "__main__":
|
|
57
|
-
sys.exit(verify_validators())
|