claude-dev-env 2.9.0 → 2.11.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/CLAUDE.md +2 -2
- package/_shared/advisor/CLAUDE.md +3 -2
- package/_shared/advisor/advisor-protocol.md +74 -108
- package/_shared/advisor/reference/advisor-block.md +37 -0
- package/_shared/advisor/reference/cli-chain.md +45 -0
- package/_shared/advisor/reference/consult-format.md +41 -0
- package/_shared/advisor/reference/lifecycle.md +21 -0
- package/_shared/advisor/reference/sol-rung.md +31 -0
- package/_shared/advisor/reference/spawn-walk-log.md +31 -0
- package/_shared/advisor/reference/third-party-bind.md +30 -0
- package/_shared/advisor/reference/warm-up.md +33 -0
- package/_shared/advisor/scripts/codex_sol_advisor.py +449 -0
- package/_shared/advisor/scripts/config/advisor_scripts_constants/advisor_route_constants.py +21 -0
- package/_shared/advisor/scripts/config/advisor_scripts_constants/model_tier_run_validator_constants.py +19 -17
- package/_shared/advisor/scripts/config/advisor_scripts_constants/sol_advisor_constants.py +28 -0
- package/_shared/advisor/scripts/model_tier_run_validator.py +32 -9
- package/_shared/advisor/scripts/tests/test_codex_sol_advisor.py +474 -0
- package/_shared/advisor/scripts/tests/test_model_tier_run_validator.py +79 -0
- package/_shared/advisor/scripts/tests/test_tier_model_ids.py +39 -17
- package/_shared/advisor/scripts/tier_model_ids.py +24 -0
- package/_shared/pr-loop/CLAUDE.md +1 -1
- package/_shared/pr-loop/audit-contract.md +17 -6
- package/_shared/pr-loop/audit-reply-template.md +4 -4
- package/_shared/pr-loop/code-rules-gate.md +3 -5
- package/_shared/pr-loop/fix-protocol.md +2 -3
- package/_shared/pr-loop/gh-payloads.md +1 -1
- package/_shared/pr-loop/scripts/CLAUDE.md +1 -1
- package/_shared/pr-loop/scripts/README.md +1 -1
- package/_shared/pr-loop/scripts/code_rules_gate.py +2 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/gate_running.py +16 -1
- package/_shared/pr-loop/scripts/code_rules_gate_parts/git_blob_readers.py +11 -5
- package/_shared/pr-loop/scripts/preflight.py +9 -4
- package/_shared/pr-loop/scripts/reviews_disabled.py +50 -22
- package/_shared/pr-loop/scripts/tests/conftest.py +20 -0
- package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +6 -6
- package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +50 -6
- package/_shared/pr-loop/scripts/tests/test_revoke_project_claude_permissions.py +1 -1
- package/_shared/pr-loop/state-schema.md +5 -14
- package/agents/CLAUDE.md +2 -2
- package/agents/clean-coder.md +58 -548
- package/agents/code-quality-agent.md +10 -2
- package/agents/code-verifier.md +1 -1
- package/agents/test_agent_frontmatter.py +32 -40
- package/audit-rubrics/CLAUDE.md +2 -1
- package/audit-rubrics/audit-categories.json +704 -0
- package/audit-rubrics/prompts/category-i-concurrency.md +1 -1
- package/bin/CLAUDE.md +16 -5
- package/bin/ever-shipped-skills.mjs +2 -0
- package/bin/install-plan.mjs +402 -0
- package/bin/install-transaction.mjs +455 -0
- package/bin/install.mjs +593 -147
- package/bin/install.plan.test.mjs +194 -0
- package/bin/install.profile-root.test.mjs +154 -0
- package/bin/install.profiles.test.mjs +253 -0
- package/bin/install.settings-defaults.test.mjs +200 -0
- package/bin/install.transaction.test.mjs +400 -0
- package/bin/install.uninstall-transaction.test.mjs +418 -0
- package/bin/merge_managed_permissions.mjs +130 -0
- package/bin/resolve-install-root.mjs +181 -0
- package/bin/select-install-targets.mjs +401 -0
- package/commands/CLAUDE.md +0 -2
- package/docs/references/CLAUDE.md +3 -1
- package/docs/references/advisor-tool.md +25 -7
- package/docs/references/prose-style-enforcement.md +25 -0
- package/docs/references/team-advisor-skill.md +3 -3
- package/docs/references/weak-executor-advisor.md +91 -0
- package/hooks/blocking/CLAUDE.md +6 -6
- package/hooks/blocking/_path_setup.py +9 -5
- package/hooks/blocking/code_rules_docstrings.py +124 -30
- package/hooks/blocking/code_rules_enforcer.py +161 -16
- package/hooks/blocking/code_rules_shared.py +40 -23
- package/hooks/blocking/config/CLAUDE.md +3 -5
- package/hooks/blocking/config/prose_style_enforcement_constants.py +38 -0
- package/hooks/blocking/config/test_prose_style_enforcement_constants.py +45 -0
- package/hooks/blocking/eli11_reply_enforcer.py +70 -113
- package/hooks/blocking/hedging_language_blocker.py +103 -20
- package/hooks/blocking/hook_prose_detector_consistency.py +6 -0
- package/hooks/blocking/intent_only_ending_blocker.py +6 -0
- package/hooks/blocking/plain_language_blocker.py +139 -20
- package/hooks/blocking/pre_tool_use_dispatcher.py +102 -20
- package/hooks/blocking/state_description_blocker.py +7 -1
- package/hooks/blocking/tdd_enforcer.py +8 -0
- package/hooks/blocking/test__path_setup.py +28 -0
- package/hooks/blocking/test_code_rules_enforcer_agent_home_tooling.py +99 -0
- package/hooks/blocking/test_code_rules_enforcer_docstring_args_span_scope.py +232 -10
- package/hooks/blocking/test_code_rules_enforcer_ephemeral.py +1 -1
- package/hooks/blocking/test_code_rules_enforcer_join_separator_magic.py +41 -0
- package/hooks/blocking/test_code_rules_enforcer_string_magic.py +98 -0
- package/hooks/blocking/test_eli11_reply_enforcer.py +98 -165
- package/hooks/blocking/test_fable_spawn_gate.py +18 -11
- package/hooks/blocking/test_hedging_language_blocker.py +120 -1
- package/hooks/blocking/test_hook_prose_detector_consistency.py +28 -8
- package/hooks/blocking/test_intent_only_ending_blocker.py +27 -2
- package/hooks/blocking/test_package_inventory_stale_blocker.py +11 -4
- package/hooks/blocking/test_plain_language_blocker.py +129 -19
- package/hooks/blocking/test_plain_language_blocker_allowlist.py +70 -26
- package/hooks/blocking/test_pre_tool_use_dispatcher.py +99 -26
- package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +87 -50
- package/hooks/blocking/test_state_description_blocker.py +45 -2
- package/hooks/blocking/test_stop_dispatcher.py +11 -7
- package/hooks/blocking/test_volatile_path_in_post_blocker.py +12 -12
- package/hooks/blocking/volatile_path_in_post_blocker.py +2 -2
- package/hooks/hooks.json +15 -0
- package/hooks/hooks_constants/CLAUDE.md +14 -3
- package/hooks/hooks_constants/ask_user_question_shape.py +281 -0
- package/hooks/hooks_constants/code_rules_enforcer_constants.py +2 -1
- package/hooks/hooks_constants/eli11_reply_enforcer_constants.py +5 -12
- package/hooks/hooks_constants/hedging_uncertainty_constants.py +42 -0
- package/hooks/hooks_constants/issue_tracker_session_starter_constants.py +23 -0
- package/hooks/hooks_constants/orchestrator_auto_starter_constants.py +23 -0
- package/hooks/hooks_constants/piped_pytest_blocker_constants.py +4 -1
- package/hooks/hooks_constants/plain_language_blocker_constants.py +4 -1
- package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +6 -0
- package/hooks/hooks_constants/project_paths_reader.py +31 -4
- package/hooks/hooks_constants/prose_matcher_precision_constants.py +40 -0
- package/hooks/hooks_constants/pytest_invocation.py +354 -0
- package/hooks/hooks_constants/session_start_injector.py +163 -0
- package/hooks/hooks_constants/session_start_injector_constants.py +46 -0
- package/hooks/hooks_constants/shell_command_pipeline.py +397 -0
- package/hooks/hooks_constants/shell_command_segments.py +5 -0
- package/hooks/hooks_constants/test_ask_user_question_shape.py +167 -0
- package/hooks/hooks_constants/test_project_paths_reader.py +29 -0
- package/hooks/hooks_constants/test_prose_metrics_parity.py +8 -0
- package/hooks/hooks_constants/test_pytest_invocation.py +130 -0
- package/hooks/hooks_constants/test_session_start_injector.py +168 -0
- package/hooks/hooks_constants/test_shell_command_pipeline.py +135 -0
- package/hooks/hooks_constants/volatile_path_in_post_blocker_constants.py +1 -1
- package/hooks/hooks_constants/working_style_prompt_constants.py +30 -0
- package/hooks/observability/CLAUDE.md +2 -0
- package/hooks/observability/prose_matcher_advisory.py +237 -0
- package/hooks/observability/test_prose_matcher_advisory.py +143 -0
- package/hooks/session/CLAUDE.md +9 -1
- package/hooks/session/_path_setup.py +13 -0
- package/hooks/session/issue_tracker_session_starter.py +135 -0
- package/hooks/session/orchestrator_auto_starter.py +100 -0
- package/hooks/session/test__path_setup.py +28 -0
- package/hooks/session/test_issue_tracker_session_starter.py +104 -0
- package/hooks/session/test_orchestrator_auto_starter.py +99 -0
- package/hooks/session/test_working_style_prompt.py +47 -0
- package/hooks/session/untracked_repo_detector.py +1 -24
- package/hooks/session/working_style_prompt.py +36 -0
- package/hooks/validators/_path_setup.py +19 -0
- package/hooks/validators/run_all_validators.py +8 -13
- package/installable-surfaces.manifest.json +21 -0
- package/output-styles/CLAUDE.md +1 -3
- package/package.json +4 -2
- package/rules/CLAUDE.md +1 -0
- package/rules/durable-post-artifacts.md +2 -2
- package/rules/eli11-replies.md +6 -1
- package/rules/hedging-claims.md +4 -2
- package/rules/long-horizon-autonomy.md +3 -1
- package/rules/opus5-communication-contract.md +45 -0
- package/rules/plain-language.md +2 -2
- package/rules/research-mode.md +1 -1
- package/scripts/CLAUDE.md +11 -0
- package/scripts/Sync-RepoMain.ps1 +215 -0
- package/scripts/active_capability_references.py +218 -0
- package/scripts/ci/windows-installer-lifecycle.ps1 +78 -0
- package/scripts/claude_chain_runner.py +394 -6
- package/scripts/claude_chain_usage.py +1 -1
- package/scripts/codex_compat_materializer.py +105 -85
- package/scripts/dev_env_scripts_constants/CLAUDE.md +2 -0
- package/scripts/dev_env_scripts_constants/active_capability_constants.py +46 -0
- package/scripts/dev_env_scripts_constants/claude_chain_constants.py +74 -0
- package/scripts/dev_env_scripts_constants/verify_installable_package_constants.py +116 -0
- package/scripts/profile-isolation-launchers/config/mcp-bundles.json +25 -0
- package/scripts/profile-isolation-launchers/config/profile-isolation-constants.mjs +60 -0
- package/scripts/profile-isolation-launchers/config/profiles.manifest.json +54 -0
- package/scripts/profile-isolation-launchers/config/shared-allowlist.json +64 -0
- package/scripts/profile-isolation-launchers/launcher-runtime.mjs +180 -0
- package/scripts/profile-isolation-launchers/lib/profile-manifest.mjs +288 -0
- package/scripts/profile-isolation-launchers/mcp-bundles.mjs +275 -0
- package/scripts/profile-isolation-launchers/profile-isolation-contract.test.mjs +221 -0
- package/scripts/profile-isolation-launchers/tests/launcher-runtime.test.mjs +108 -0
- package/scripts/profile-isolation-launchers/tests/mcp-bundles.test.mjs +147 -0
- package/scripts/profile-isolation-launchers/tests/shortcut-contract.test.ps1 +102 -0
- package/scripts/profile-isolation-launchers/tests/version-compatibility.test.mjs +210 -0
- package/scripts/profile-isolation-launchers/version-compatibility.mjs +299 -0
- package/scripts/profile-isolation-launchers/windows/shortcut-inventory.ps1 +127 -0
- package/scripts/profile-isolation-launchers/windows/shortcut-manifest.json +51 -0
- package/scripts/profile-isolation-launchers/windows/shortcut-reconcile.ps1 +77 -0
- package/scripts/spawn_grok_batch.py +3 -0
- package/scripts/test_active_capability_references.py +108 -0
- package/scripts/test_claude_chain_runner.py +414 -82
- package/scripts/test_claude_chain_usage.py +12 -12
- package/scripts/test_resolve_worker_spawn.py +2 -2
- package/scripts/test_verify_installable_package.py +208 -0
- package/scripts/tests/test_codex_compat_materializer.py +33 -0
- package/scripts/verify_installable_package.py +612 -0
- package/settings.json +10 -0
- package/skills/CLAUDE.md +2 -0
- package/skills/_shared/advisor/CLAUDE.md +1 -1
- package/skills/_shared/advisor/scripts/README.md +2 -0
- package/skills/_shared/pr-loop/scripts/CLAUDE.md +1 -0
- package/skills/_shared/pr-loop/scripts/audit_category_schema.py +355 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +1 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +32 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +7 -19
- package/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +94 -0
- package/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +21 -0
- package/skills/autoconverge/reference/convergence.md +2 -1
- package/skills/autoconverge/reference/stop-conditions.md +5 -3
- package/skills/beat-sheet/SKILL.md +54 -0
- package/skills/beat-sheet/reference/visual-beats.md +29 -0
- package/skills/bugteam/CONSTRAINTS.md +4 -4
- package/skills/bugteam/EXAMPLES.md +1 -1
- package/skills/bugteam/reference/README.md +1 -1
- package/skills/e-code-review/SKILL.md +26 -5
- package/skills/e-code-review/reference/effort-evaluation.md +35 -0
- package/skills/e-code-review/reference/medium.md +15 -4
- package/skills/e-code-review/scripts/config/e_code_review_effort_constants/__init__.py +41 -0
- package/skills/e-code-review/scripts/config/e_code_review_effort_constants/effort_constants.py +40 -0
- package/skills/e-code-review/scripts/e_code_review_scripts_constants/finding_pipeline_constants.py +49 -0
- package/skills/e-code-review/scripts/effort_defaults_evidence.json +186 -0
- package/skills/e-code-review/scripts/effort_evaluation.py +362 -0
- package/skills/e-code-review/scripts/finding_pipeline.py +140 -0
- package/skills/e-code-review/scripts/fixtures/demanding.json +26 -0
- package/skills/e-code-review/scripts/fixtures/easy.json +14 -0
- package/skills/e-code-review/scripts/fixtures/medium.json +20 -0
- package/skills/e-code-review/scripts/grok_code_review.py +16 -7
- package/skills/e-code-review/scripts/test_effort_evaluation.py +180 -0
- package/skills/e-code-review/scripts/test_finding_pipeline.py +197 -0
- package/skills/e-code-review/scripts/test_grok_code_review.py +77 -0
- package/skills/grokify/SKILL.md +1 -1
- package/skills/grokify/templates/handoff-template.md +2 -2
- package/skills/orchestrator/SKILL.md +5 -4
- package/skills/plan-to-pr/scripts/create_packet.py +4 -4
- package/skills/plan-to-pr/scripts/load_skill_constants.py +41 -0
- package/skills/plan-to-pr/scripts/validate_packet.py +4 -4
- package/skills/plan-to-pr/scripts/validate_protocol.py +4 -1
- package/skills/plan-to-pr/scripts/validate_run.py +4 -1
- package/skills/pr-converge/scripts/check_convergence.py +21 -19
- package/skills/pr-converge/scripts/check_convergence_availability.py +50 -7
- package/skills/pr-converge/scripts/conftest.py +35 -0
- package/skills/pr-converge/scripts/test_check_convergence_availability.py +65 -0
- package/skills/pr-converge/scripts/test_check_convergence_codex.py +11 -1
- package/skills/pr-converge/scripts/test_check_convergence_contract.py +9 -2
- package/skills/pr-loop-cloud-transport/SKILL.md +1 -1
- package/skills/rebase/SKILL.md +15 -3
- package/skills/reviewer-gates/SKILL.md +2 -2
- package/skills/show/SKILL.md +51 -0
- package/skills/show/references/accessibility.md +7 -0
- package/skills/show/references/art.md +3 -0
- package/skills/show/references/charts.md +3 -0
- package/skills/show/references/core-design.md +14 -0
- package/skills/show/references/erds.md +3 -0
- package/skills/show/references/flowcharts.md +3 -0
- package/skills/show/references/host-and-html.md +3 -0
- package/skills/show/references/illustrative-diagrams.md +10 -0
- package/skills/show/references/interaction.md +3 -0
- package/skills/show/references/mockups.md +3 -0
- package/skills/show/references/quality-gates.md +7 -0
- package/skills/show/references/structural-diagrams.md +3 -0
- package/skills/show/references/subject-inventory.md +21 -0
- package/skills/show/references/svg-contract.md +22 -0
- package/skills/show/routing.yaml +30 -0
- package/skills/show/samples/pr1262-v2.svg +222 -0
- package/skills/show/scripts/README.md +6 -0
- package/skills/show/scripts/validate-artifact.py +91 -0
- package/skills/show/scripts/validate-package.py +18 -0
- package/skills/show/templates/html-widget.html +4 -0
- package/skills/show/templates/svg-base.svg +19 -0
- package/skills/show/tests/fixtures/css-var.svg +6 -0
- package/skills/show/tests/fixtures/dead-ref.svg +7 -0
- package/skills/show/tests/fixtures/filled-glyph.svg +8 -0
- package/skills/show/tests/fixtures/inherited-fill.svg +18 -0
- package/skills/show/tests/fixtures/invalid.svg +1 -0
- package/skills/show/tests/fixtures/large-canvas.svg +21 -0
- package/skills/show/tests/fixtures/unfilled-connector.svg +15 -0
- package/skills/show/tests/fixtures/valid.html +1 -0
- package/skills/show/tests/test_validate-artifact.py +74 -0
- package/skills/show/tests/test_validators.py +59 -0
- package/skills/show/workflows/create-visual.md +13 -0
- package/skills/show/workflows/review-visual.md +20 -0
- package/skills/split-pr/SKILL.md +85 -0
- package/skills/split-pr/reference/path-layers.md +16 -0
- package/skills/split-pr/reference/proposal-format.md +15 -0
- package/skills/split-pr/reference/split-further-loop.md +10 -0
- package/skills/split-pr/reference/splitting-principles.md +26 -0
- package/skills/split-pr/scripts/analyze_pr.py +279 -0
- package/skills/split-pr/scripts/categorize_files.py +106 -0
- package/skills/split-pr/scripts/config/__init__.py +1 -0
- package/skills/split-pr/scripts/config/dependency_constants.py +14 -0
- package/skills/split-pr/scripts/config/git_operations_constants.py +36 -0
- package/skills/split-pr/scripts/config/packing_constants.py +61 -0
- package/skills/split-pr/scripts/config/plan_constants.py +49 -0
- package/skills/split-pr/scripts/config/split_pr_constants.py +110 -0
- package/skills/split-pr/scripts/execute_split_slices.py +82 -0
- package/skills/split-pr/scripts/pack_files_into_slices.py +212 -0
- package/skills/split-pr/scripts/split_pr_dependency_graph.py +70 -0
- package/skills/split-pr/scripts/split_pr_git_operations.py +184 -0
- package/skills/split-pr/scripts/split_pr_layer_order.py +58 -0
- package/skills/split-pr/scripts/split_pr_paginate.py +119 -0
- package/skills/split-pr/scripts/split_pr_process_runner.py +52 -0
- package/skills/split-pr/scripts/split_pr_script_types.py +126 -0
- package/skills/split-pr/scripts/split_pr_title.py +41 -0
- package/skills/split-pr/scripts/test_analyze_pr.py +228 -0
- package/skills/split-pr/scripts/test_categorize_files.py +55 -0
- package/skills/split-pr/scripts/test_categorize_files_packing.py +59 -0
- package/skills/split-pr/scripts/test_execute_split_slices.py +99 -0
- package/skills/split-pr/scripts/test_split_pr_dependency_graph.py +47 -0
- package/skills/split-pr/scripts/test_split_pr_git_operations.py +125 -0
- package/skills/split-pr/scripts/test_split_pr_layer_order.py +36 -0
- package/skills/split-pr/scripts/test_split_pr_paginate.py +65 -0
- package/skills/split-pr/scripts/test_split_pr_script_types.py +73 -0
- package/skills/split-pr/scripts/test_split_pr_title.py +28 -0
- package/skills/split-pr/scripts/test_verify_dependency_graph.py +46 -0
- package/skills/split-pr/scripts/test_verify_plan.py +56 -0
- package/skills/split-pr/scripts/test_verify_plan_contract.py +50 -0
- package/skills/split-pr/scripts/test_verify_plan_path_normalization.py +45 -0
- package/skills/split-pr/scripts/verify_dependency_graph.py +111 -0
- package/skills/split-pr/scripts/verify_plan.py +139 -0
- package/skills/team-advisor/SKILL.md +7 -4
- package/skills/team-advisor/reference/advisor-docs-review.md +207 -0
- package/system-prompts/software-engineer.xml +11 -2
- package/commands/initialize.md +0 -90
- package/commands/stubcheck.md +0 -88
- package/output-styles/caveman-agent.md +0 -37
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Audit contract
|
|
2
2
|
|
|
3
|
-
Shared output schema and audit-loop contract used by `/bugteam`,
|
|
3
|
+
Shared output schema and audit-loop contract used by `/bugteam`, `clean-room audit (code-quality-agent)`, and `/pr-fix-protocol`. Changing a shape here is a breaking change for every consuming skill.
|
|
4
4
|
|
|
5
5
|
## Contents
|
|
6
6
|
|
|
@@ -11,6 +11,17 @@ Shared output schema and audit-loop contract used by `/bugteam`, `/qbug`, `/find
|
|
|
11
11
|
- De-dup and merge
|
|
12
12
|
- Persistence (loop-<L>-audit.json, loop-<L>-diagnostics.json)
|
|
13
13
|
|
|
14
|
+
## Collection before severity filtering
|
|
15
|
+
|
|
16
|
+
Audit collection reports every real finding. The collection record retains all
|
|
17
|
+
seeded severities (`P0`, `P1`, `P2`) and every Shape A field (`file`, `line`,
|
|
18
|
+
`category`, `severity`, `excerpt`, `failure_mode`, `evidence_files`). Do not drop a real finding because its severity is low.
|
|
19
|
+
|
|
20
|
+
Severity or action filtering is a **separate consumer stage** after collection
|
|
21
|
+
is complete. A consumer may select a subset for fix or posting; it must not
|
|
22
|
+
rewrite the collection record or strip file, line, evidence, or category from
|
|
23
|
+
retained entries.
|
|
24
|
+
|
|
14
25
|
## Finding schema
|
|
15
26
|
|
|
16
27
|
Each finding an audit produces MUST be one of exactly two shapes.
|
|
@@ -30,7 +41,7 @@ Each finding an audit produces MUST be one of exactly two shapes.
|
|
|
30
41
|
}
|
|
31
42
|
```
|
|
32
43
|
|
|
33
|
-
`id` is `loop<L>-<K>` where `L` is the loop counter (1-based) and `K` is the 1-based index within the loop. For
|
|
44
|
+
`id` is `loop<L>-<K>` where `L` is the loop counter (1-based) and `K` is the 1-based index within the loop. For `clean-room audit (code-quality-agent)` which runs once, use `find<K>`.
|
|
34
45
|
|
|
35
46
|
### Shape B — structured proof-of-absence
|
|
36
47
|
|
|
@@ -92,10 +103,10 @@ The audit must either produce new Shape A findings citing new file:line referenc
|
|
|
92
103
|
|
|
93
104
|
## Haiku secondary auditor
|
|
94
105
|
|
|
95
|
-
For single-subagent skills (`/
|
|
106
|
+
For single-subagent skills (`/bugteam`, `clean-room audit (code-quality-agent)`) the LEAD spawns two `Agent()` calls in one message:
|
|
96
107
|
|
|
97
|
-
- **Primary** — `subagent_type=clean-coder`, `model=sonnet` (for
|
|
98
|
-
- **Secondary (Haiku)** — `subagent_type=code-quality-agent`, `model=haiku`, same self-contained clean-room prompt shape used by
|
|
108
|
+
- **Primary** — `subagent_type=clean-coder`, `model=sonnet` (for `/bugteam` cycle) or `subagent_type=code-quality-agent`, `model=sonnet` (for clean-room audit).
|
|
109
|
+
- **Secondary (Haiku)** — `subagent_type=code-quality-agent`, `model=haiku`, same self-contained clean-room prompt shape used by `clean-room audit (code-quality-agent)`.
|
|
99
110
|
|
|
100
111
|
Both audit the same diff. The secondary returns findings to the LEAD only — never posted to the PR.
|
|
101
112
|
|
|
@@ -112,7 +123,7 @@ For `/bugteam`, the single audit agent provides per-category coverage by walking
|
|
|
112
123
|
|
|
113
124
|
## Post-fix self-audit
|
|
114
125
|
|
|
115
|
-
Audit-and-fix skills (`/
|
|
126
|
+
Audit-and-fix skills (`/bugteam`) MUST re-audit modified files between `py_compile` and `git add`. This catches fix-induced regressions in the same loop that introduced them rather than on loop N+1.
|
|
116
127
|
|
|
117
128
|
Sequence:
|
|
118
129
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Audit reply template
|
|
2
2
|
|
|
3
|
-
Canonical reply shape for every orchestrator-to-thread reply posted by the PR-loop suite (`pr-converge`, `bugteam`,
|
|
3
|
+
Canonical reply shape for every orchestrator-to-thread reply posted by the PR-loop suite (`pr-converge`, `bugteam`, and the `clean-coder` agent). Every reply Claude posts to an unresolved review thread on a draft PR uses this template.
|
|
4
4
|
|
|
5
|
-
Read this doc before authoring any code that posts a reply. The template is the contract emitted by every `clean-coder` reply path; the audit-skill wiring (`bugteam`, `
|
|
5
|
+
Read this doc before authoring any code that posts a reply. The template is the contract emitted by every `clean-coder` reply path; the audit-skill wiring (`bugteam`, `pr-converge`) reads it before authoring a reply.
|
|
6
6
|
|
|
7
|
-
This doc has two surfaces, called out separately so consumers do not conflate them: the **reply template** (this section and below) shapes the body Claude posts back to a single review thread; the **audit body skeleton** in [Relationship to the audit review body](#relationship-to-the-audit-review-body) shapes the parent review `post_audit_thread.py` posts at audit time. The reply-template consumers are the
|
|
7
|
+
This doc has two surfaces, called out separately so consumers do not conflate them: the **reply template** (this section and below) shapes the body Claude posts back to a single review thread; the **audit body skeleton** in [Relationship to the audit review body](#relationship-to-the-audit-review-body) shapes the parent review `post_audit_thread.py` posts at audit time. The reply-template consumers are the skills/agents listed above (read-only `clean-room audit` is excluded — it posts an audit review via `post_audit_thread.py` but never authors thread replies). The audit-body-skeleton consumers include `clean-room audit` alongside `bugteam` because both post audit reviews via the same script.
|
|
8
8
|
|
|
9
9
|
## Provenance
|
|
10
10
|
|
|
@@ -121,7 +121,7 @@ The thread can be resolved without further action; the reviewer's underlying con
|
|
|
121
121
|
|
|
122
122
|
## Relationship to the audit review body
|
|
123
123
|
|
|
124
|
-
The audit review body posted by `post_audit_thread.py` (consumers: `bugteam`, `
|
|
124
|
+
The audit review body posted by `post_audit_thread.py` (consumers: `bugteam`, `clean-room audit`) shares the same header anchor pattern:
|
|
125
125
|
|
|
126
126
|
<!-- audit-body-skeleton:start -->
|
|
127
127
|
```
|
|
@@ -7,7 +7,7 @@ Pre-audit validator run before each AUDIT (and pre-commit when applicable). Wrap
|
|
|
7
7
|
Canonical: `~/.claude/_shared/pr-loop/scripts/code_rules_gate.py` after install.
|
|
8
8
|
|
|
9
9
|
Workflows reference it via:
|
|
10
|
-
- all skills (bugteam,
|
|
10
|
+
- all skills (bugteam, pr-converge): `${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/code_rules_gate.py`
|
|
11
11
|
|
|
12
12
|
Cross-skill path traversal works because every skill installs as a flat top-level dir under `~/.claude/skills/` and `_shared/` lives alongside `skills/` under `~/.claude/`.
|
|
13
13
|
|
|
@@ -37,9 +37,7 @@ python "<gate_script>" --base origin/<base_branch> --only-under <prefix> [--only
|
|
|
37
37
|
## Workflow integration
|
|
38
38
|
|
|
39
39
|
- **bugteam:** before every AUDIT in Step 3 of the loop. Non-zero → spawn clean-coder for standards fix; loop until exit 0 or 5 consecutive gate failures → `error: code rules gate failed pre-audit`.
|
|
40
|
-
- **
|
|
41
|
-
- **pr-converge:** before every push in the Fix protocol. Halt on non-zero, fix violations, re-run.
|
|
42
|
-
- **monitor-many:** before every commit during the fix loop. Halt on non-zero, fix violations, re-run.
|
|
40
|
+
- **pr-converge:** before every push in the Fix protocol and before every commit during the fix loop. Halt on non-zero, fix violations, re-run.
|
|
43
41
|
|
|
44
42
|
## Coverage
|
|
45
43
|
|
|
@@ -61,4 +59,4 @@ When the gate exits non-zero:
|
|
|
61
59
|
2. Group violations by file
|
|
62
60
|
3. Apply fixes in the smallest change set (extract constants to `config/`, rename collection params with `all_` prefix, replace literals with named constants, etc.)
|
|
63
61
|
4. Re-run the gate with the same arguments
|
|
64
|
-
5. Cap at 5 consecutive failures (bugteam,
|
|
62
|
+
5. Cap at 5 consecutive failures (bugteam, pr-converge); on cap exceeded, exit `error`
|
|
@@ -42,9 +42,8 @@
|
|
|
42
42
|
|
|
43
43
|
Transport: post the reply via [`gh-payloads.md`](gh-payloads.md), then call `pull_request_review_write(method="resolve_thread", threadId=<thread_node_id>, ...)` for the same thread before moving to the next finding (this is the PR review thread node ID — `PRRT_kwDOxxx` — distinct from the numeric comment ID; harvest it at audit time when calling `get_review_comments`, see [`skills/bugteam/reference/obstacles/fix-resolve-thread.md`](../../skills/bugteam/reference/obstacles/fix-resolve-thread.md)).
|
|
44
44
|
13. **Re-trigger reviewer** when the calling workflow specifies. Workflow-specific:
|
|
45
|
-
- `pr-converge`: post `bugbot run` issue comment after every push (Cursor Bugbot)
|
|
46
|
-
- `
|
|
47
|
-
- `bugteam` / `qbug`: skip — Claude itself is the reviewer; the next loop iteration audits
|
|
45
|
+
- `pr-converge`: post `bugbot run` issue comment after every push (Cursor Bugbot); when the multi-PR path also needs Copilot, call `requested_reviewers` for Copilot as well
|
|
46
|
+
- `bugteam`: skip — Claude itself is the reviewer; the next loop iteration audits
|
|
48
47
|
|
|
49
48
|
## Stuck detection
|
|
50
49
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# MCP-based payloads
|
|
2
2
|
|
|
3
|
-
Shared payload shapes for posting PR reviews and replies. Used by `bugteam
|
|
3
|
+
Shared payload shapes for posting PR reviews and replies. Used by `bugteam` and `pr-converge`.
|
|
4
4
|
|
|
5
5
|
## Build payloads with MCP tools
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ Python scripts invoked at runtime by the PR-loop skills. Each script is a standa
|
|
|
14
14
|
| `stale_worktree_rule_sweep.py` | Drops allow/deny rules pointing at deleted `~/.claude/worktrees/<repo>/<worktree>` directories and deduplicates the rule arrays; run by the grant and revoke flows before they write |
|
|
15
15
|
| `code_rules_gate.py` | Pre-commit gate that runs `code_rules_enforcer` checks on staged Python files before a fix commit lands, and the terminology sweep over the staged diff |
|
|
16
16
|
| `terminology_sweep.py` | Flags a prose term that near-misses an identifier introduced on added code lines of a unified diff (shared leading word, divergent tail) |
|
|
17
|
-
| `reviews_disabled.py` | Shared helper for the reviewer opt-out and opt-in gates; parses `CLAUDE_REVIEWS_DISABLED` tokens `bugteam`, `bugbot`, `copilot`, and `codex`, plus `CLAUDE_REVIEWS_ENABLED` for
|
|
17
|
+
| `reviews_disabled.py` | Shared helper for the reviewer opt-out and opt-in gates; parses `CLAUDE_REVIEWS_DISABLED` tokens `bugteam`, `bugbot`, `copilot`, and `codex`, plus `CLAUDE_REVIEWS_ENABLED` for opt-in. `bugbot`, `bugteam`, and `codex` are off by default and each runs only when `CLAUDE_REVIEWS_ENABLED` lists it; `copilot` runs by default and stops only when `CLAUDE_REVIEWS_DISABLED` lists it |
|
|
18
18
|
| `copilot_quota.py` | Copilot premium-request quota pre-check: resolves a configured GitHub account, reads its remaining `premium_interactions` quota via `gh api copilot_internal/user`, and exits 0 (run Copilot) or non-zero (skip: out of quota, API down, or no account configured) |
|
|
19
19
|
| `reviewer_availability.py` | Unified reviewer-availability entry point for Copilot and Bugbot: reuses `copilot_quota.py` and `reviews_disabled.py` and exits 0 when the named `--reviewer` may be spawned, non-zero when it is opted out or (for Copilot) out of quota |
|
|
20
20
|
| `fix_hookspath.py` | Repairs a malformed `core.hooksPath` global git config entry |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Shared PR-loop scripts
|
|
2
2
|
|
|
3
|
-
Runnable helpers used by **bugteam**, **
|
|
3
|
+
Runnable helpers used by **bugteam**, **pr-converge**, and related skills. These files are **executed** from the repository (or a `~/.claude` install); they are not meant as primary model-reading context.
|
|
4
4
|
|
|
5
5
|
## Inventory
|
|
6
6
|
|
|
@@ -314,11 +314,13 @@ def _run_diff_mode(
|
|
|
314
314
|
scoped_added_lines = (
|
|
315
315
|
added_lines_by_file(repository_root, arguments.base, file_paths) if file_paths else {}
|
|
316
316
|
)
|
|
317
|
+
merge_base_ref = resolve_merge_base(repository_root, arguments.base)
|
|
317
318
|
return run_gate(
|
|
318
319
|
validate_content,
|
|
319
320
|
file_paths,
|
|
320
321
|
repository_root,
|
|
321
322
|
all_added_lines_by_path=scoped_added_lines,
|
|
323
|
+
prior_ref=merge_base_ref,
|
|
322
324
|
)
|
|
323
325
|
|
|
324
326
|
|
|
@@ -96,6 +96,7 @@ def _scoped_violations_for_file(
|
|
|
96
96
|
repository_root: Path,
|
|
97
97
|
all_added_lines_for_file: set[int] | None,
|
|
98
98
|
should_read_staged_content: bool = False,
|
|
99
|
+
prior_ref: str = "HEAD",
|
|
99
100
|
) -> tuple[list[str], list[str]] | None:
|
|
100
101
|
"""Validate one resolved file and partition its violations by diff scope."""
|
|
101
102
|
resolved_root = repository_root.resolve()
|
|
@@ -106,7 +107,7 @@ def _scoped_violations_for_file(
|
|
|
106
107
|
if content is None:
|
|
107
108
|
sys.stderr.write(f"code_rules_gate: skip unreadable {resolved_path}\n")
|
|
108
109
|
return None
|
|
109
|
-
prior_content = read_prior_committed_content(resolved_root, relative_posix)
|
|
110
|
+
prior_content = read_prior_committed_content(resolved_root, relative_posix, prior_ref)
|
|
110
111
|
issues = validate_content(
|
|
111
112
|
content,
|
|
112
113
|
relative_posix,
|
|
@@ -135,6 +136,7 @@ def _partition_over_eligible_paths(
|
|
|
135
136
|
repository_root: Path,
|
|
136
137
|
all_added_lines_by_path: dict[Path, set[int]] | None,
|
|
137
138
|
should_read_staged_content: bool,
|
|
139
|
+
prior_ref: str = "HEAD",
|
|
138
140
|
) -> PartitionedViolations:
|
|
139
141
|
"""Validate each already-resolved eligible file and partition the results."""
|
|
140
142
|
blocking_by_file: dict[Path, list[str]] = {}
|
|
@@ -147,6 +149,7 @@ def _partition_over_eligible_paths(
|
|
|
147
149
|
repository_root,
|
|
148
150
|
_added_lines_for(all_added_lines_by_path, each_resolved),
|
|
149
151
|
should_read_staged_content,
|
|
152
|
+
prior_ref,
|
|
150
153
|
)
|
|
151
154
|
if scoped_violations is None:
|
|
152
155
|
skipped_unreadable_count += 1
|
|
@@ -165,6 +168,7 @@ def _collect_partitioned_violations(
|
|
|
165
168
|
repository_root: Path,
|
|
166
169
|
all_added_lines_by_path: dict[Path, set[int]] | None,
|
|
167
170
|
should_read_staged_content: bool = False,
|
|
171
|
+
prior_ref: str = "HEAD",
|
|
168
172
|
) -> PartitionedViolations:
|
|
169
173
|
"""Validate every eligible file and partition results, counting read skips."""
|
|
170
174
|
all_eligible_paths = _eligible_resolved_paths(
|
|
@@ -176,6 +180,7 @@ def _collect_partitioned_violations(
|
|
|
176
180
|
repository_root,
|
|
177
181
|
all_added_lines_by_path,
|
|
178
182
|
should_read_staged_content,
|
|
183
|
+
prior_ref,
|
|
179
184
|
)
|
|
180
185
|
|
|
181
186
|
|
|
@@ -266,6 +271,7 @@ def _validate_and_count(
|
|
|
266
271
|
repository_root: Path,
|
|
267
272
|
all_added_lines_by_path: dict[Path, set[int]] | None,
|
|
268
273
|
should_read_staged_content: bool,
|
|
274
|
+
prior_ref: str = "HEAD",
|
|
269
275
|
) -> PartitionedViolations:
|
|
270
276
|
"""Validate the eligible files, report the inspected count, return partitions."""
|
|
271
277
|
all_eligible_paths = _eligible_resolved_paths(
|
|
@@ -277,6 +283,7 @@ def _validate_and_count(
|
|
|
277
283
|
repository_root,
|
|
278
284
|
all_added_lines_by_path,
|
|
279
285
|
should_read_staged_content,
|
|
286
|
+
prior_ref,
|
|
280
287
|
)
|
|
281
288
|
_report_inspected_count(len(all_eligible_paths) - skipped_count)
|
|
282
289
|
return blocking_by_file, advisory_by_file, skipped_count
|
|
@@ -288,6 +295,7 @@ def run_gate(
|
|
|
288
295
|
repository_root: Path,
|
|
289
296
|
all_added_lines_by_path: dict[Path, set[int]] | None = None,
|
|
290
297
|
should_read_staged_content: bool = False,
|
|
298
|
+
prior_ref: str = "HEAD",
|
|
291
299
|
) -> int:
|
|
292
300
|
"""Run the gate over *all_file_paths* and emit a partitioned report.
|
|
293
301
|
|
|
@@ -297,6 +305,12 @@ def run_gate(
|
|
|
297
305
|
repository_root: Repository root for resolving relative paths.
|
|
298
306
|
all_added_lines_by_path: Per-file added-line maps, or None.
|
|
299
307
|
should_read_staged_content: When True, validate staged blobs.
|
|
308
|
+
prior_ref: The git ref each file's grandfathering baseline is read
|
|
309
|
+
from. Defaults to ``HEAD`` (staged and explicit-paths mode); diff
|
|
310
|
+
mode passes the merge-base with the diff's base branch so a
|
|
311
|
+
fragment-baselined finding (such as ``check_comment_changes``)
|
|
312
|
+
grandfathers against the branch's starting point, not its own
|
|
313
|
+
latest commit.
|
|
300
314
|
|
|
301
315
|
Returns:
|
|
302
316
|
Zero when clean; non-zero on a blocking violation or a skipped file.
|
|
@@ -307,6 +321,7 @@ def run_gate(
|
|
|
307
321
|
repository_root,
|
|
308
322
|
all_added_lines_by_path,
|
|
309
323
|
should_read_staged_content,
|
|
324
|
+
prior_ref,
|
|
310
325
|
)
|
|
311
326
|
return _report_partitioned_violations(
|
|
312
327
|
partitions, repository_root, all_added_lines_by_path is None
|
|
@@ -12,19 +12,25 @@ from pathlib import Path
|
|
|
12
12
|
from terminology_sweep import repository_environment
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
def read_prior_committed_content(
|
|
16
|
-
|
|
15
|
+
def read_prior_committed_content(
|
|
16
|
+
repository_root: Path, relative_path_posix: str, ref: str = "HEAD"
|
|
17
|
+
) -> str:
|
|
18
|
+
"""Return *ref*'s committed content for *relative_path_posix*.
|
|
17
19
|
|
|
18
20
|
Args:
|
|
19
21
|
repository_root: Repository root used as the ``git -C`` target.
|
|
20
22
|
relative_path_posix: Repository-relative POSIX path to read.
|
|
23
|
+
ref: The git ref to read the blob from. Defaults to ``HEAD`` for
|
|
24
|
+
staged and explicit-paths mode; diff mode passes the merge-base
|
|
25
|
+
with the diff's base branch so grandfathering compares against
|
|
26
|
+
the branch's starting point rather than its own latest commit.
|
|
21
27
|
|
|
22
28
|
Returns:
|
|
23
|
-
The committed content at
|
|
24
|
-
tracked or ``git show`` returns non-zero.
|
|
29
|
+
The committed content at *ref*, or an empty string when the path is
|
|
30
|
+
not tracked there or ``git show`` returns non-zero.
|
|
25
31
|
"""
|
|
26
32
|
completed = subprocess.run(
|
|
27
|
-
["git", "show", f"
|
|
33
|
+
["git", "show", f"{ref}:{relative_path_posix}"],
|
|
28
34
|
cwd=str(repository_root),
|
|
29
35
|
capture_output=True,
|
|
30
36
|
text=True,
|
|
@@ -43,6 +43,7 @@ from preflight_self_heal import silently_clear_stale_local_hooks_path_override
|
|
|
43
43
|
from reviews_disabled import (
|
|
44
44
|
CLAUDE_REVIEWS_DISABLED_BUGTEAM_TOKEN,
|
|
45
45
|
CLAUDE_REVIEWS_DISABLED_ENV_VAR_NAME,
|
|
46
|
+
CLAUDE_REVIEWS_ENABLED_ENV_VAR_NAME,
|
|
46
47
|
EXIT_CODE_BUGTEAM_DISABLED_VIA_ENV,
|
|
47
48
|
is_bugteam_disabled_via_env,
|
|
48
49
|
)
|
|
@@ -467,8 +468,10 @@ def main(all_arguments: list[str]) -> int:
|
|
|
467
468
|
|
|
468
469
|
Returns:
|
|
469
470
|
Zero on success. Non-zero exit code on the first failing check.
|
|
470
|
-
Returns :data:`EXIT_CODE_BUGTEAM_DISABLED_VIA_ENV` when
|
|
471
|
-
|
|
471
|
+
Returns :data:`EXIT_CODE_BUGTEAM_DISABLED_VIA_ENV` when bugteam is off
|
|
472
|
+
for this run. Bugteam is off by default, so that happens when
|
|
473
|
+
``CLAUDE_REVIEWS_ENABLED`` omits the ``bugteam`` token, and also when
|
|
474
|
+
``CLAUDE_REVIEWS_DISABLED`` lists it.
|
|
472
475
|
"""
|
|
473
476
|
arguments = parse_arguments(all_arguments)
|
|
474
477
|
skip_env_var_name = BUGTEAM_PREFLIGHT_SKIP_ENV_VAR_NAME
|
|
@@ -480,13 +483,15 @@ def main(all_arguments: list[str]) -> int:
|
|
|
480
483
|
)
|
|
481
484
|
return 0
|
|
482
485
|
reviews_disabled_env_var_name = CLAUDE_REVIEWS_DISABLED_ENV_VAR_NAME
|
|
486
|
+
reviews_enabled_env_var_name = CLAUDE_REVIEWS_ENABLED_ENV_VAR_NAME
|
|
483
487
|
reviews_disabled_bugteam_token = CLAUDE_REVIEWS_DISABLED_BUGTEAM_TOKEN
|
|
484
488
|
disabled_via_env_exit_code = EXIT_CODE_BUGTEAM_DISABLED_VIA_ENV
|
|
485
489
|
if is_bugteam_disabled_via_env():
|
|
486
490
|
print(
|
|
487
491
|
f"bugteam_preflight: halted "
|
|
488
|
-
f"({
|
|
489
|
-
f"'{reviews_disabled_bugteam_token}'
|
|
492
|
+
f"({reviews_enabled_env_var_name} omits "
|
|
493
|
+
f"'{reviews_disabled_bugteam_token}', or "
|
|
494
|
+
f"{reviews_disabled_env_var_name} lists it).",
|
|
490
495
|
file=sys.stderr,
|
|
491
496
|
)
|
|
492
497
|
return disabled_via_env_exit_code
|
|
@@ -5,13 +5,17 @@
|
|
|
5
5
|
enabled lists bugbot, disabled empty -> bugbot ok: runs
|
|
6
6
|
no lists set -> bugbot flag: off (default)
|
|
7
7
|
enabled lists bugbot, disabled bugbot -> bugbot flag: off (opt-out wins)
|
|
8
|
-
disabled empty
|
|
8
|
+
enabled lists bugteam, disabled empty -> bugteam ok: runs
|
|
9
|
+
no lists set -> bugteam flag: off (default)
|
|
10
|
+
no lists set -> codex flag: off (default)
|
|
11
|
+
disabled empty -> copilot ok: runs
|
|
9
12
|
disabled lists copilot -> copilot flag: off
|
|
10
|
-
disabled lists codex -> codex flag: off
|
|
11
13
|
|
|
12
|
-
Bugbot
|
|
13
|
-
|
|
14
|
-
list names
|
|
14
|
+
Bugbot, bugteam, and codex are off by default. Each runs only when the
|
|
15
|
+
enabled list names it. A token in the disabled list forces one off even
|
|
16
|
+
when the enabled list names it too. Copilot runs by default and stops only
|
|
17
|
+
when the disabled list names it. Both lists parse case-insensitively and
|
|
18
|
+
tolerate whitespace.
|
|
15
19
|
"""
|
|
16
20
|
|
|
17
21
|
from __future__ import annotations
|
|
@@ -75,15 +79,42 @@ def _is_reviewer_listed_in_env(
|
|
|
75
79
|
return reviewer_token in all_listed_tokens
|
|
76
80
|
|
|
77
81
|
|
|
78
|
-
def
|
|
79
|
-
"""
|
|
82
|
+
def _is_off_by_default_reviewer_disabled(reviewer_token: str) -> bool:
|
|
83
|
+
"""Decide whether an opt-in reviewer stays off for this run.
|
|
84
|
+
|
|
85
|
+
::
|
|
86
|
+
|
|
87
|
+
enabled lists the token, disabled empty -> False (runs)
|
|
88
|
+
neither list names the token -> True (off by default)
|
|
89
|
+
both lists name the token -> True (opt-out wins)
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
reviewer_token: The lowercase reviewer token to look up in both lists.
|
|
80
93
|
|
|
81
94
|
Returns:
|
|
82
|
-
True when the
|
|
95
|
+
True when the reviewer stays off for this run.
|
|
83
96
|
"""
|
|
84
|
-
|
|
85
|
-
CLAUDE_REVIEWS_DISABLED_ENV_VAR_NAME,
|
|
97
|
+
is_opted_out = _is_reviewer_listed_in_env(
|
|
98
|
+
CLAUDE_REVIEWS_DISABLED_ENV_VAR_NAME, reviewer_token
|
|
86
99
|
)
|
|
100
|
+
is_opted_in = _is_reviewer_listed_in_env(
|
|
101
|
+
CLAUDE_REVIEWS_ENABLED_ENV_VAR_NAME, reviewer_token
|
|
102
|
+
)
|
|
103
|
+
return is_opted_out or not is_opted_in
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def is_bugteam_disabled_via_env() -> bool:
|
|
107
|
+
"""Check whether the bug-audit family stays off for this run.
|
|
108
|
+
|
|
109
|
+
The bug-audit family is off by default. It runs only when
|
|
110
|
+
``CLAUDE_REVIEWS_ENABLED`` lists ``bugteam``, and a ``bugteam`` token in
|
|
111
|
+
``CLAUDE_REVIEWS_DISABLED`` forces it off even when the opt-in lists it.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
True when ``CLAUDE_REVIEWS_DISABLED`` lists ``bugteam`` or when
|
|
115
|
+
``CLAUDE_REVIEWS_ENABLED`` does not list ``bugteam``.
|
|
116
|
+
"""
|
|
117
|
+
return _is_off_by_default_reviewer_disabled(CLAUDE_REVIEWS_DISABLED_BUGTEAM_TOKEN)
|
|
87
118
|
|
|
88
119
|
|
|
89
120
|
def is_bugbot_disabled_via_env() -> bool:
|
|
@@ -97,13 +128,7 @@ def is_bugbot_disabled_via_env() -> bool:
|
|
|
97
128
|
True when ``CLAUDE_REVIEWS_DISABLED`` lists ``bugbot`` or when
|
|
98
129
|
``CLAUDE_REVIEWS_ENABLED`` does not list ``bugbot``.
|
|
99
130
|
"""
|
|
100
|
-
|
|
101
|
-
CLAUDE_REVIEWS_DISABLED_ENV_VAR_NAME, CLAUDE_REVIEWS_DISABLED_BUGBOT_TOKEN
|
|
102
|
-
)
|
|
103
|
-
is_opted_in = _is_reviewer_listed_in_env(
|
|
104
|
-
CLAUDE_REVIEWS_ENABLED_ENV_VAR_NAME, CLAUDE_REVIEWS_DISABLED_BUGBOT_TOKEN
|
|
105
|
-
)
|
|
106
|
-
return is_opted_out or not is_opted_in
|
|
131
|
+
return _is_off_by_default_reviewer_disabled(CLAUDE_REVIEWS_DISABLED_BUGBOT_TOKEN)
|
|
107
132
|
|
|
108
133
|
|
|
109
134
|
def is_bugbot_opted_out_via_env() -> bool:
|
|
@@ -134,14 +159,17 @@ def is_copilot_disabled_via_env() -> bool:
|
|
|
134
159
|
|
|
135
160
|
|
|
136
161
|
def is_codex_disabled_via_env() -> bool:
|
|
137
|
-
"""Check whether
|
|
162
|
+
"""Check whether the Codex reviewer stays off for this run.
|
|
163
|
+
|
|
164
|
+
Codex is off by default. It runs only when ``CLAUDE_REVIEWS_ENABLED``
|
|
165
|
+
lists ``codex``, and a ``codex`` token in ``CLAUDE_REVIEWS_DISABLED``
|
|
166
|
+
forces it off even when the opt-in lists it.
|
|
138
167
|
|
|
139
168
|
Returns:
|
|
140
|
-
True when
|
|
169
|
+
True when ``CLAUDE_REVIEWS_DISABLED`` lists ``codex`` or when
|
|
170
|
+
``CLAUDE_REVIEWS_ENABLED`` does not list ``codex``.
|
|
141
171
|
"""
|
|
142
|
-
return
|
|
143
|
-
CLAUDE_REVIEWS_DISABLED_ENV_VAR_NAME, CLAUDE_REVIEWS_DISABLED_CODEX_TOKEN
|
|
144
|
-
)
|
|
172
|
+
return _is_off_by_default_reviewer_disabled(CLAUDE_REVIEWS_DISABLED_CODEX_TOKEN)
|
|
145
173
|
|
|
146
174
|
|
|
147
175
|
def parse_arguments(all_argv: list[str]) -> argparse.Namespace:
|
|
@@ -1 +1,21 @@
|
|
|
1
1
|
"""Test fixtures for _shared/pr-loop/scripts/tests/."""
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from pr_loop_shared_constants.reviews_disabled_constants import (
|
|
5
|
+
CLAUDE_REVIEWS_DISABLED_BUGTEAM_TOKEN,
|
|
6
|
+
CLAUDE_REVIEWS_ENABLED_ENV_VAR_NAME,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@pytest.fixture(autouse=True)
|
|
11
|
+
def opt_bugteam_in(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
12
|
+
"""Opt bugteam in so each case exercises its own check, not the default off.
|
|
13
|
+
|
|
14
|
+
Bugteam is off by default, so a preflight case that never mentions the
|
|
15
|
+
reviewer lists halts on the opt-in check before reaching the behavior it
|
|
16
|
+
was written for. A case that tests those lists overrides this from its own
|
|
17
|
+
body, where monkeypatch runs after the fixture.
|
|
18
|
+
"""
|
|
19
|
+
monkeypatch.setenv(
|
|
20
|
+
CLAUDE_REVIEWS_ENABLED_ENV_VAR_NAME, CLAUDE_REVIEWS_DISABLED_BUGTEAM_TOKEN
|
|
21
|
+
)
|
|
@@ -200,9 +200,9 @@ def test_is_valid_project_root_uses_extracted_directory_marker_constants() -> No
|
|
|
200
200
|
|
|
201
201
|
def test_permission_rule_tool_name_extracts_tool_prefix() -> None:
|
|
202
202
|
assert common.permission_rule_tool_name("Edit(/repo/.claude/**)") == "Edit"
|
|
203
|
-
assert common.permission_rule_tool_name(
|
|
204
|
-
"Write"
|
|
205
|
-
)
|
|
203
|
+
assert common.permission_rule_tool_name(
|
|
204
|
+
"Write(c:/Users/example/.claude/worktrees/x/**)"
|
|
205
|
+
) == ("Write")
|
|
206
206
|
assert common.permission_rule_tool_name(None) is None
|
|
207
207
|
assert common.permission_rule_tool_name("not-a-rule") is None
|
|
208
208
|
|
|
@@ -217,13 +217,13 @@ def test_is_inert_file_permission_rule_for_write_glob_notebookedit() -> None:
|
|
|
217
217
|
|
|
218
218
|
def test_all_project_path_aliases_for_reap_adds_home_alias_when_project_is_home() -> None:
|
|
219
219
|
all_aliases = common.all_project_path_aliases_for_reap(
|
|
220
|
-
"C:/Users/
|
|
220
|
+
"C:/Users/example", home_directory_path="C:/Users/example"
|
|
221
221
|
)
|
|
222
|
-
assert all_aliases == ("C:/Users/
|
|
222
|
+
assert all_aliases == ("C:/Users/example", "$HOME")
|
|
223
223
|
|
|
224
224
|
|
|
225
225
|
def test_all_project_path_aliases_for_reap_skips_home_alias_for_other_projects() -> None:
|
|
226
226
|
all_aliases = common.all_project_path_aliases_for_reap(
|
|
227
|
-
"C:/dev/other", home_directory_path="C:/Users/
|
|
227
|
+
"C:/dev/other", home_directory_path="C:/Users/example"
|
|
228
228
|
)
|
|
229
229
|
assert all_aliases == ("C:/dev/other",)
|
|
@@ -29,13 +29,30 @@ def test_is_bugteam_disabled_via_env_returns_true_when_env_lists_bugteam(
|
|
|
29
29
|
assert reviews_disabled.is_bugteam_disabled_via_env() is True
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
def
|
|
32
|
+
def test_is_bugteam_disabled_via_env_returns_true_when_no_env_vars_set(
|
|
33
33
|
monkeypatch: pytest.MonkeyPatch,
|
|
34
34
|
) -> None:
|
|
35
35
|
monkeypatch.delenv("CLAUDE_REVIEWS_DISABLED", raising=False)
|
|
36
|
+
monkeypatch.delenv("CLAUDE_REVIEWS_ENABLED", raising=False)
|
|
37
|
+
assert reviews_disabled.is_bugteam_disabled_via_env() is True
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_is_bugteam_disabled_via_env_returns_false_when_enabled_lists_bugteam(
|
|
41
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
42
|
+
) -> None:
|
|
43
|
+
monkeypatch.delenv("CLAUDE_REVIEWS_DISABLED", raising=False)
|
|
44
|
+
monkeypatch.setenv("CLAUDE_REVIEWS_ENABLED", "bugteam")
|
|
36
45
|
assert reviews_disabled.is_bugteam_disabled_via_env() is False
|
|
37
46
|
|
|
38
47
|
|
|
48
|
+
def test_is_bugteam_disabled_via_env_true_when_disabled_overrides_enabled(
|
|
49
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
50
|
+
) -> None:
|
|
51
|
+
monkeypatch.setenv("CLAUDE_REVIEWS_DISABLED", "bugteam")
|
|
52
|
+
monkeypatch.setenv("CLAUDE_REVIEWS_ENABLED", "bugteam")
|
|
53
|
+
assert reviews_disabled.is_bugteam_disabled_via_env() is True
|
|
54
|
+
|
|
55
|
+
|
|
39
56
|
def test_is_bugbot_disabled_via_env_returns_true_when_env_lists_bugbot(
|
|
40
57
|
monkeypatch: pytest.MonkeyPatch,
|
|
41
58
|
) -> None:
|
|
@@ -150,20 +167,30 @@ def test_is_codex_disabled_via_env_returns_true_when_env_lists_codex(
|
|
|
150
167
|
assert reviews_disabled.is_codex_disabled_via_env() is True
|
|
151
168
|
|
|
152
169
|
|
|
153
|
-
def
|
|
170
|
+
def test_is_codex_disabled_via_env_returns_true_when_no_env_vars_set(
|
|
154
171
|
monkeypatch: pytest.MonkeyPatch,
|
|
155
172
|
) -> None:
|
|
156
173
|
monkeypatch.delenv("CLAUDE_REVIEWS_DISABLED", raising=False)
|
|
157
|
-
|
|
174
|
+
monkeypatch.delenv("CLAUDE_REVIEWS_ENABLED", raising=False)
|
|
175
|
+
assert reviews_disabled.is_codex_disabled_via_env() is True
|
|
158
176
|
|
|
159
177
|
|
|
160
|
-
def
|
|
178
|
+
def test_is_codex_disabled_via_env_returns_false_when_enabled_lists_codex(
|
|
161
179
|
monkeypatch: pytest.MonkeyPatch,
|
|
162
180
|
) -> None:
|
|
163
|
-
monkeypatch.
|
|
181
|
+
monkeypatch.delenv("CLAUDE_REVIEWS_DISABLED", raising=False)
|
|
182
|
+
monkeypatch.setenv("CLAUDE_REVIEWS_ENABLED", "codex")
|
|
164
183
|
assert reviews_disabled.is_codex_disabled_via_env() is False
|
|
165
184
|
|
|
166
185
|
|
|
186
|
+
def test_is_codex_disabled_via_env_true_when_only_bugbot_enabled(
|
|
187
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
188
|
+
) -> None:
|
|
189
|
+
monkeypatch.delenv("CLAUDE_REVIEWS_DISABLED", raising=False)
|
|
190
|
+
monkeypatch.setenv("CLAUDE_REVIEWS_ENABLED", "bugbot")
|
|
191
|
+
assert reviews_disabled.is_codex_disabled_via_env() is True
|
|
192
|
+
|
|
193
|
+
|
|
167
194
|
def test_is_codex_disabled_via_env_true_when_listed_among_other_tokens(
|
|
168
195
|
monkeypatch: pytest.MonkeyPatch,
|
|
169
196
|
) -> None:
|
|
@@ -223,8 +250,25 @@ def test_cli_main_supports_codex_reviewer(
|
|
|
223
250
|
assert reviews_disabled.main(["--reviewer", "codex"]) == 0
|
|
224
251
|
|
|
225
252
|
|
|
226
|
-
def
|
|
253
|
+
def test_cli_main_returns_one_for_codex_when_enabled_via_env(
|
|
227
254
|
monkeypatch: pytest.MonkeyPatch,
|
|
228
255
|
) -> None:
|
|
229
256
|
monkeypatch.setenv("CLAUDE_REVIEWS_DISABLED", "bugbot")
|
|
257
|
+
monkeypatch.setenv("CLAUDE_REVIEWS_ENABLED", "codex")
|
|
230
258
|
assert reviews_disabled.main(["--reviewer", "codex"]) == 1
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def test_cli_main_returns_one_for_bugteam_when_enabled_via_env(
|
|
262
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
263
|
+
) -> None:
|
|
264
|
+
monkeypatch.delenv("CLAUDE_REVIEWS_DISABLED", raising=False)
|
|
265
|
+
monkeypatch.setenv("CLAUDE_REVIEWS_ENABLED", "bugteam")
|
|
266
|
+
assert reviews_disabled.main(["--reviewer", "bugteam"]) == 1
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def test_cli_main_returns_zero_for_bugteam_when_no_env_vars_set(
|
|
270
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
271
|
+
) -> None:
|
|
272
|
+
monkeypatch.delenv("CLAUDE_REVIEWS_DISABLED", raising=False)
|
|
273
|
+
monkeypatch.delenv("CLAUDE_REVIEWS_ENABLED", raising=False)
|
|
274
|
+
assert reviews_disabled.main(["--reviewer", "bugteam"]) == 0
|
|
@@ -114,7 +114,7 @@ def test_revoke_strips_inert_write_glob_notebookedit_on_foreign_worktree_paths(
|
|
|
114
114
|
(project_directory / ".git").mkdir()
|
|
115
115
|
settings_path = tmp_path / "home" / ".claude" / "settings.json"
|
|
116
116
|
foreign_worktree = (
|
|
117
|
-
"c:/Users/
|
|
117
|
+
"c:/Users/example/.claude/worktrees/claude-dev-env-702a0c2055d2/other-wt"
|
|
118
118
|
)
|
|
119
119
|
live_other_project = "C:/dev/live-other-project"
|
|
120
120
|
settings_path.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -23,19 +23,13 @@ Adds:
|
|
|
23
23
|
- `pre_fix_sha` — `git rev-parse HEAD` immediately before each FIX
|
|
24
24
|
- `gate_round_count` — consecutive pre-audit gate failures (cap: 5 → exit `error`)
|
|
25
25
|
|
|
26
|
-
State lives inline in the lead session (orchestrator). Cleared on TeamDelete.
|
|
27
|
-
|
|
28
|
-
### qbug
|
|
29
|
-
|
|
30
|
-
Adds nothing beyond common. Single subagent loops internally and returns a final summary; orchestrator discards intermediate state. Subagent's loop counter and findings return in the exit payload (`{exit_reason, loop_count, final_commit_sha, audit_log, unresolved}`).
|
|
26
|
+
State lives inline in the lead session (orchestrator). Cleared on TeamDelete. A single-subagent cycle returns its loop counter and findings in the exit payload (`{exit_reason, loop_count, final_commit_sha, audit_log, unresolved}`); the orchestrator discards intermediate state.
|
|
31
27
|
|
|
32
28
|
### pr-converge
|
|
33
29
|
|
|
34
30
|
Normative field list, phase enum, dual persistence, and reset semantics: [`../../skills/pr-converge/reference/state-schema.md`](../../skills/pr-converge/reference/state-schema.md). File-backed multi-PR `status` enum: [`../../skills/pr-converge/reference/multi-pr-orchestration.md`](../../skills/pr-converge/reference/multi-pr-orchestration.md).
|
|
35
31
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
Adds per-PR JSON state file at `~/.claude/skills/monitor-many/state/<owner>-<repo>-<pr_number>.json`:
|
|
32
|
+
Multi-PR runs also keep a per-PR JSON state file at `~/.claude/skills/pr-converge/state/<owner>-<repo>-<pr_number>.json`:
|
|
39
33
|
|
|
40
34
|
| Field | Type | Description |
|
|
41
35
|
|---|---|---|
|
|
@@ -51,12 +45,9 @@ Adds per-PR JSON state file at `~/.claude/skills/monitor-many/state/<owner>-<rep
|
|
|
51
45
|
## Reset semantics
|
|
52
46
|
|
|
53
47
|
- bugteam: cleared on each new `/bugteam` invocation
|
|
54
|
-
-
|
|
55
|
-
- pr-converge: see [`../../skills/pr-converge/reference/state-schema.md`](../../skills/pr-converge/reference/state-schema.md)
|
|
56
|
-
- monitor-many: persists across orchestrator runs; only `last_seen_comment_id` advances monotonically
|
|
48
|
+
- pr-converge: see [`../../skills/pr-converge/reference/state-schema.md`](../../skills/pr-converge/reference/state-schema.md); multi-PR file state persists across orchestrator runs and only `last_seen_comment_id` advances monotonically
|
|
57
49
|
|
|
58
50
|
## Convergence checks
|
|
59
51
|
|
|
60
|
-
- bugteam
|
|
61
|
-
- pr-converge: see [`../../skills/pr-converge/reference/convergence-gates.md`](../../skills/pr-converge/reference/convergence-gates.md)
|
|
62
|
-
- monitor-many: no unresolved comments requiring code changes AND required checks green AND review policy satisfied → `gh pr ready`
|
|
52
|
+
- bugteam: `last_action == "audited"` AND `last_findings.total == 0` → `converged`
|
|
53
|
+
- pr-converge: see [`../../skills/pr-converge/reference/convergence-gates.md`](../../skills/pr-converge/reference/convergence-gates.md); multi-PR ready when no unresolved comments require code changes, required checks are green, and review policy is satisfied → `gh pr ready`
|