claude-dev-env 2.12.0 → 2.14.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/AGENTS.md +61 -0
- package/CLAUDE.md +1 -57
- package/_shared/AGENTS.md +15 -0
- package/_shared/CLAUDE.md +1 -15
- package/_shared/advisor/AGENTS.md +22 -0
- package/_shared/advisor/CLAUDE.md +1 -22
- package/_shared/pr-loop/AGENTS.md +27 -0
- package/_shared/pr-loop/CLAUDE.md +1 -27
- package/_shared/pr-loop/scripts/AGENTS.md +35 -0
- package/_shared/pr-loop/scripts/CLAUDE.md +1 -35
- package/_shared/pr-loop/scripts/code_rules_gate.py +2 -3
- package/_shared/pr-loop/scripts/code_rules_gate_parts/AGENTS.md +42 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +1 -42
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/AGENTS.md +26 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/CLAUDE.md +1 -26
- package/_shared/pr-loop/scripts/test_code_rules_gate.py +0 -26
- package/_shared/pr-loop/scripts/tests/AGENTS.md +44 -0
- package/_shared/pr-loop/scripts/tests/CLAUDE.md +1 -44
- package/_shared/process-tree/AGENTS.md +41 -0
- package/_shared/process-tree/CLAUDE.md +1 -41
- package/agents/AGENTS.md +31 -0
- package/agents/CLAUDE.md +1 -32
- package/agents/clean-coder.md +6 -6
- package/agents/pr-description-writer.md +11 -81
- package/agents/test_agent_frontmatter.py +4 -4
- package/audit-rubrics/AGENTS.md +43 -0
- package/audit-rubrics/CLAUDE.md +1 -43
- package/audit-rubrics/category_rubrics/AGENTS.md +37 -0
- package/audit-rubrics/category_rubrics/CLAUDE.md +1 -37
- package/audit-rubrics/prompts/AGENTS.md +37 -0
- package/audit-rubrics/prompts/CLAUDE.md +1 -37
- package/bin/AGENTS.md +112 -0
- package/bin/CLAUDE.md +1 -112
- package/bin/ever-shipped-skills.mjs +1 -0
- package/bin/install-constants.mjs +6 -7
- package/bin/install.mjs +71 -13
- package/bin/install.prune.test.mjs +26 -0
- package/bin/install.settings-defaults.test.mjs +60 -33
- package/bin/install.test.mjs +36 -4
- package/commands/AGENTS.md +23 -0
- package/commands/CLAUDE.md +1 -23
- package/commands/hook-log-extract.md +3 -3
- package/commands/sr-loop.md +9 -5
- package/docs/AGENTS.md +32 -0
- package/docs/CLAUDE.md +1 -33
- package/docs/CODE_RULES.md +1 -1
- package/docs/imagegen.md +22 -0
- package/docs/references/AGENTS.md +17 -0
- package/docs/references/CLAUDE.md +1 -18
- package/hooks/AGENTS.md +31 -0
- package/hooks/CLAUDE.md +1 -31
- package/hooks/_gh_pr_author_swap_utils.py +14 -0
- package/hooks/advisory/AGENTS.md +16 -0
- package/hooks/advisory/CLAUDE.md +1 -16
- package/hooks/blocking/AGENTS.md +123 -0
- package/hooks/blocking/CLAUDE.md +1 -148
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/AGENTS.md +28 -0
- package/hooks/blocking/claude_md_orphan_file_blocker_parts/CLAUDE.md +1 -28
- package/hooks/blocking/code_rules_banned_identifiers.py +1 -1
- package/hooks/blocking/code_rules_dead_module_constant.py +149 -37
- package/hooks/blocking/code_rules_probe_chains.py +6 -2
- package/hooks/blocking/config/AGENTS.md +10 -0
- package/hooks/blocking/config/CLAUDE.md +1 -22
- package/hooks/blocking/conventional_pr_title_gate.py +1 -2
- package/hooks/blocking/gh_pr_author_restore.py +7 -2
- package/hooks/blocking/intent_only_ending_blocker.py +11 -16
- package/hooks/blocking/inventory_intent_records/AGENTS.md +26 -0
- package/hooks/blocking/inventory_intent_records/CLAUDE.md +1 -26
- package/hooks/blocking/package_inventory_stale_blocker_parts/AGENTS.md +26 -0
- package/hooks/blocking/package_inventory_stale_blocker_parts/CLAUDE.md +1 -26
- package/hooks/blocking/pii_prevention_blocker_parts/AGENTS.md +24 -0
- package/hooks/blocking/pii_prevention_blocker_parts/CLAUDE.md +1 -24
- package/hooks/blocking/send_user_file_open_locally_blocker.py +1 -1
- package/hooks/blocking/stop_dispatcher.py +4 -4
- package/hooks/blocking/tdd_enforcer_parts/AGENTS.md +30 -0
- package/hooks/blocking/tdd_enforcer_parts/CLAUDE.md +1 -30
- package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +0 -3
- package/hooks/blocking/test_code_rules_enforcer_banned_prefixes.py +1 -1
- package/hooks/blocking/test_code_rules_enforcer_dead_module_constant.py +171 -0
- package/hooks/blocking/test_code_rules_enforcer_magic_allowlist.py +1 -1
- package/hooks/blocking/test_gh_pr_author_restore.py +2 -1
- package/hooks/blocking/test_intent_only_ending_blocker.py +4 -0
- package/hooks/blocking/test_pre_tool_use_dispatcher.py +6 -7
- package/hooks/blocking/test_send_user_file_open_locally_blocker.py +4 -3
- package/hooks/blocking/test_shared_stdin_adoption.py +0 -2
- package/hooks/diagnostic/AGENTS.md +43 -0
- package/hooks/diagnostic/CLAUDE.md +1 -43
- package/hooks/diagnostic/hook_log_extractor.py +4 -38
- package/hooks/diagnostic/hook_log_stop_wrapper.py +6 -155
- package/hooks/diagnostic/migrations/AGENTS.md +16 -0
- package/hooks/diagnostic/migrations/CLAUDE.md +1 -16
- package/hooks/diagnostic/queries/AGENTS.md +19 -0
- package/hooks/diagnostic/queries/CLAUDE.md +1 -19
- package/hooks/diagnostic/test_hook_log_extractor.py +10 -23
- package/hooks/diagnostic/test_hook_log_stop_wrapper.py +3 -331
- package/hooks/git-hooks/AGENTS.md +31 -0
- package/hooks/git-hooks/CLAUDE.md +1 -31
- package/hooks/git-hooks/git_hooks_constants/AGENTS.md +21 -0
- package/hooks/git-hooks/git_hooks_constants/CLAUDE.md +1 -21
- package/hooks/git-hooks/git_hooks_constants/__init__.py +4 -12
- package/hooks/git-hooks/pre_push.py +49 -118
- package/hooks/git-hooks/test_pre_push.py +111 -137
- package/hooks/hooks.json +0 -35
- package/hooks/hooks_constants/AGENTS.md +104 -0
- package/hooks/hooks_constants/CLAUDE.md +1 -113
- package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +0 -11
- package/hooks/hooks_constants/convergence_branch_constants.py +0 -1
- package/hooks/hooks_constants/fable_spawn_gate_constants.py +3 -4
- package/hooks/hooks_constants/hook_log_extractor_constants.py +1 -2
- package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +0 -8
- package/hooks/hooks_constants/send_user_file_open_locally_blocker_constants.py +1 -6
- package/hooks/hooks_constants/stop_dispatcher_constants.py +0 -1
- package/hooks/hooks_constants/task_list_loop_starter_constants.py +4 -3
- package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +1 -26
- package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +0 -5
- package/hooks/hooks_constants/test_stop_dispatcher_constants.py +0 -1
- package/hooks/hooks_constants/working_style_prompt_constants.py +29 -20
- package/hooks/lifecycle/AGENTS.md +18 -0
- package/hooks/lifecycle/CLAUDE.md +1 -20
- package/hooks/observability/AGENTS.md +20 -0
- package/hooks/observability/CLAUDE.md +1 -20
- package/hooks/session/AGENTS.md +33 -0
- package/hooks/session/CLAUDE.md +1 -33
- package/hooks/session/gh_pr_author_session_cleanup.py +7 -2
- package/hooks/session/task_list_loop_starter.py +3 -3
- package/hooks/session/test_gh_pr_author_session_cleanup.py +2 -1
- package/hooks/session/test_task_list_loop_starter.py +10 -2
- package/hooks/session/test_working_style_prompt.py +9 -4
- package/hooks/validation/AGENTS.md +20 -0
- package/hooks/validation/CLAUDE.md +1 -20
- package/hooks/validators/AGENTS.md +51 -0
- package/hooks/validators/CLAUDE.md +1 -51
- package/hooks/validators/health_check.py +52 -19
- package/hooks/validators/python_style_checks.py +1 -1
- package/hooks/validators/test_health_check.py +112 -27
- package/hooks/workflow/AGENTS.md +16 -0
- package/hooks/workflow/CLAUDE.md +1 -16
- package/installable-surfaces.manifest.json +1 -0
- package/output-styles/AGENTS.md +15 -0
- package/output-styles/CLAUDE.md +1 -15
- package/package.json +2 -1
- package/rules/AGENTS.md +61 -0
- package/rules/CLAUDE.md +1 -63
- package/rules/code-standards.md +5 -9
- package/rules/doc-prose-cuts.md +1 -1
- package/rules/gh-cli-conventions.md +0 -1
- package/rules/git-workflow.md +1 -3
- package/scripts/AGENTS.md +62 -0
- package/scripts/CLAUDE.md +1 -63
- package/scripts/_code_review_test_support.py +0 -95
- package/scripts/codex_compat_materializer.py +4 -0
- package/scripts/dev_env_scripts_constants/AGENTS.md +21 -0
- package/scripts/dev_env_scripts_constants/CLAUDE.md +1 -21
- package/scripts/dev_env_scripts_constants/code_review_constants.py +9 -98
- package/scripts/dev_env_scripts_constants/test_code_review_constants.py +1 -44
- package/scripts/invoke_code_review.py +8 -451
- package/scripts/sync_to_cursor/AGENTS.md +23 -0
- package/scripts/sync_to_cursor/CLAUDE.md +1 -23
- package/scripts/test_invoke_code_review.py +5 -61
- package/scripts/test_invoke_code_review_cli.py +1 -45
- package/scripts/test_invoke_code_review_contract.py +1 -118
- package/scripts/test_validate_instruction_pairs.py +90 -0
- package/scripts/test_verify_installable_package.py +5 -1
- package/scripts/tests/AGENTS.md +33 -0
- package/scripts/tests/CLAUDE.md +1 -33
- package/scripts/tests/test_codex_compat_materializer.py +36 -1
- package/scripts/validate_instruction_pairs.py +183 -0
- package/settings.json +1 -10
- package/skills/AGENTS.md +72 -0
- package/skills/CLAUDE.md +1 -64
- package/skills/_shared/AGENTS.md +44 -0
- package/skills/_shared/CLAUDE.md +1 -44
- package/skills/_shared/advisor/AGENTS.md +9 -0
- package/skills/_shared/advisor/CLAUDE.md +1 -9
- package/skills/_shared/pr-loop/AGENTS.md +50 -0
- package/skills/_shared/pr-loop/CLAUDE.md +1 -50
- package/skills/_shared/pr-loop/prompts/AGENTS.md +9 -0
- package/skills/_shared/pr-loop/prompts/CLAUDE.md +1 -9
- package/skills/_shared/pr-loop/scripts/AGENTS.md +35 -0
- package/skills/_shared/pr-loop/scripts/CLAUDE.md +1 -35
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +24 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +1 -24
- package/skills/anthropic-plan/AGENTS.md +34 -0
- package/skills/anthropic-plan/CLAUDE.md +1 -34
- package/skills/anthropic-plan/scripts/AGENTS.md +11 -0
- package/skills/anthropic-plan/scripts/CLAUDE.md +1 -11
- package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/AGENTS.md +16 -0
- package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/CLAUDE.md +1 -16
- package/skills/anthropic-plan/templates/AGENTS.md +13 -0
- package/skills/anthropic-plan/templates/CLAUDE.md +1 -13
- package/skills/anthropic-plan/workflow/AGENTS.md +14 -0
- package/skills/anthropic-plan/workflow/CLAUDE.md +1 -14
- package/skills/auditing-claude-config/AGENTS.md +21 -0
- package/skills/auditing-claude-config/CLAUDE.md +1 -21
- package/skills/autoconverge/AGENTS.md +36 -0
- package/skills/autoconverge/CLAUDE.md +1 -36
- package/skills/autoconverge/reference/AGENTS.md +16 -0
- package/skills/autoconverge/reference/CLAUDE.md +1 -16
- package/skills/autoconverge/reference/convergence.md +7 -7
- package/skills/autoconverge/reference/gotchas.md +3 -10
- package/skills/autoconverge/workflow/AGENTS.md +26 -0
- package/skills/autoconverge/workflow/CLAUDE.md +1 -26
- package/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +16 -0
- package/skills/autoconverge/workflow/autoconverge_report_constants/CLAUDE.md +1 -16
- package/skills/autoconverge/workflow/converge.contract.test.mjs +53 -1388
- package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +4 -3
- package/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +33 -493
- package/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +15 -97
- package/skills/autoconverge/workflow/converge.mjs +201 -238
- package/skills/autoconverge/workflow/converge.precatch.test.mjs +1 -1
- package/skills/bugteam/AGENTS.md +30 -0
- package/skills/bugteam/CLAUDE.md +1 -30
- package/skills/bugteam/CONSTRAINTS.md +1 -1
- package/skills/bugteam/SKILL.md +9 -0
- package/skills/bugteam/reference/AGENTS.md +20 -0
- package/skills/bugteam/reference/CLAUDE.md +1 -20
- package/skills/bugteam/reference/audit-and-teammates.md +10 -6
- package/skills/bugteam/reference/obstacles/AGENTS.md +24 -0
- package/skills/bugteam/reference/obstacles/CLAUDE.md +1 -24
- package/skills/bugteam/scripts/AGENTS.md +30 -0
- package/skills/bugteam/scripts/CLAUDE.md +1 -30
- package/skills/bugteam/scripts/bugteam_scripts_constants/AGENTS.md +18 -0
- package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +1 -18
- package/skills/bugteam/test_skill_additions.py +9 -0
- package/skills/closeout/reference/handoff-prompt-template.md +1 -1
- package/skills/codex-review/AGENTS.md +46 -0
- package/skills/codex-review/CLAUDE.md +1 -46
- package/skills/codex-review/reference/AGENTS.md +15 -0
- package/skills/codex-review/reference/CLAUDE.md +1 -15
- package/skills/codex-review/scripts/codex_review_scripts_constants/AGENTS.md +18 -0
- package/skills/codex-review/scripts/codex_review_scripts_constants/CLAUDE.md +1 -18
- package/skills/codex-review/test_skill_scaffold.py +3 -3
- package/skills/comments/SKILL.md +65 -0
- package/skills/copilot-review/AGENTS.md +18 -0
- package/skills/copilot-review/CLAUDE.md +1 -18
- package/skills/descriptions/SKILL.md +51 -0
- package/skills/emergencies/SKILL.md +42 -0
- package/skills/everything-search/AGENTS.md +17 -0
- package/skills/everything-search/CLAUDE.md +1 -17
- package/skills/fresh-branch/AGENTS.md +14 -0
- package/skills/fresh-branch/CLAUDE.md +1 -14
- package/skills/grok-spawn/AGENTS.md +28 -0
- package/skills/grok-spawn/CLAUDE.md +1 -28
- package/skills/orchestrator/SKILL.md +2 -4
- package/skills/plan-to-pr/SKILL.md +6 -7
- package/skills/plan-to-pr/reference/final-validation-tasks.md +1 -1
- package/skills/plan-to-pr/reference/process-inventory.md +2 -2
- package/skills/plan-to-pr/reference/review-loop.md +2 -2
- package/skills/plan-to-pr/reference/run-record.schema.json +1 -1
- package/skills/plan-to-pr/reference/task-seeds.md +1 -1
- package/skills/plan-to-pr/reference/task-ticket.md +3 -4
- package/skills/plan-to-pr/scripts/config/constants.py +1 -2
- package/skills/plan-to-pr/scripts/test_validate_protocol.py +1 -1
- package/skills/plan-to-pr/test_skill_contract.py +2 -2
- package/skills/pr-converge/AGENTS.md +32 -0
- package/skills/pr-converge/CLAUDE.md +1 -32
- package/skills/pr-converge/SKILL.md +13 -16
- package/skills/pr-converge/pr_converge_skill_constants/AGENTS.md +26 -0
- package/skills/pr-converge/pr_converge_skill_constants/CLAUDE.md +1 -26
- package/skills/pr-converge/reference/AGENTS.md +28 -0
- package/skills/pr-converge/reference/CLAUDE.md +1 -28
- package/skills/pr-converge/reference/obstacles/AGENTS.md +23 -0
- package/skills/pr-converge/reference/obstacles/CLAUDE.md +1 -23
- package/skills/pr-converge/reference/progress-checklist.md +6 -5
- package/skills/pr-converge/reference/state-schema.md +1 -27
- package/skills/pr-converge/scripts/AGENTS.md +46 -0
- package/skills/pr-converge/scripts/CLAUDE.md +1 -46
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/AGENTS.md +18 -0
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/CLAUDE.md +1 -18
- package/skills/pr-converge/workflows/AGENTS.md +16 -0
- package/skills/pr-converge/workflows/CLAUDE.md +1 -16
- package/skills/pr-loop-cloud-transport/SKILL.md +1 -1
- package/skills/pr-loop-cloud-transport/reference/identity-and-hooks.md +3 -3
- package/skills/pr-loop-lifecycle/SKILL.md +1 -1
- package/skills/pr-loop-lifecycle/reference/teardown-publish-permissions.md +1 -1
- package/skills/prototype/SKILL.md +4 -4
- package/skills/prototype/reference/honest-limitations.md +5 -5
- package/skills/prototype/reference/promotion-tasks.md +2 -2
- package/skills/prototype/workflows/promotion.md +4 -6
- package/skills/rebase/AGENTS.md +32 -0
- package/skills/rebase/CLAUDE.md +1 -32
- package/skills/recall/AGENTS.md +30 -0
- package/skills/recall/CLAUDE.md +1 -30
- package/skills/remember/AGENTS.md +31 -0
- package/skills/remember/CLAUDE.md +1 -31
- package/skills/reviews/SKILL.md +85 -0
- package/skills/session-log/AGENTS.md +32 -0
- package/skills/session-log/CLAUDE.md +1 -32
- package/skills/session-tidy/AGENTS.md +36 -0
- package/skills/session-tidy/CLAUDE.md +1 -36
- package/skills/skill-builder/AGENTS.md +49 -0
- package/skills/skill-builder/CLAUDE.md +1 -49
- package/skills/skill-builder/references/AGENTS.md +25 -0
- package/skills/skill-builder/references/CLAUDE.md +1 -25
- package/skills/skill-builder/references/deterministic-elements.md +1 -1
- package/skills/skill-builder/templates/AGENTS.md +14 -0
- package/skills/skill-builder/templates/CLAUDE.md +1 -14
- package/skills/skill-builder/workflows/AGENTS.md +19 -0
- package/skills/skill-builder/workflows/CLAUDE.md +1 -19
- package/skills/small-cl/SKILL.md +52 -0
- package/skills/task-build/AGENTS.md +29 -0
- package/skills/task-build/CLAUDE.md +1 -29
- package/skills/update/AGENTS.md +38 -0
- package/skills/update/CLAUDE.md +1 -38
- package/system-prompts/AGENTS.md +17 -0
- package/system-prompts/CLAUDE.md +1 -17
- package/system-prompts/software-engineer.xml +3 -3
- package/agents/code-verifier.md +0 -74
- package/docs/PR_DESCRIPTION_GUIDE.md +0 -157
- package/docs/references/code-review-enforcement.md +0 -132
- package/hooks/blocking/code_review_enforcement_config_bootstrap.py +0 -53
- package/hooks/blocking/code_review_gate_deny.py +0 -74
- package/hooks/blocking/code_review_pr_create_gate.py +0 -198
- package/hooks/blocking/code_review_push_gate.py +0 -145
- package/hooks/blocking/code_review_stamp_directory_write_blocker.py +0 -348
- package/hooks/blocking/code_review_stamp_store.py +0 -233
- package/hooks/blocking/code_review_stamp_write_blocker_parts/__init__.py +0 -7
- package/hooks/blocking/code_review_stamp_write_blocker_parts/conftest.py +0 -15
- package/hooks/blocking/code_review_stamp_write_blocker_parts/obfuscated_stamp_path_reference.py +0 -212
- package/hooks/blocking/code_review_stamp_write_blocker_parts/split_directory_change_into_stamp.py +0 -138
- package/hooks/blocking/code_review_stamp_write_blocker_parts/test_obfuscated_stamp_path_reference.py +0 -49
- package/hooks/blocking/code_review_stamp_write_blocker_parts/test_split_directory_change_into_stamp.py +0 -38
- package/hooks/blocking/code_verifier_spawn_preflight_gate.py +0 -483
- package/hooks/blocking/config/code_review_enforcement_constants.py +0 -143
- package/hooks/blocking/config/test_code_review_enforcement_constants.py +0 -166
- package/hooks/blocking/config/verified_commit_constants.py +0 -160
- package/hooks/blocking/config/verified_commit_context_constants.py +0 -21
- package/hooks/blocking/config/verified_commit_gate_output_constants.py +0 -14
- package/hooks/blocking/conftest.py +0 -123
- package/hooks/blocking/convergence_gate_blocker.py +0 -310
- package/hooks/blocking/pr_converge_bugteam_enforcer.py +0 -170
- package/hooks/blocking/pr_description_body_audit.py +0 -148
- package/hooks/blocking/pr_description_command_parser.py +0 -237
- package/hooks/blocking/pr_description_enforcer.py +0 -227
- package/hooks/blocking/pr_description_pr_number.py +0 -155
- package/hooks/blocking/pr_description_proof_of_work.py +0 -385
- package/hooks/blocking/pr_description_readability.py +0 -364
- package/hooks/blocking/reviewer_spawn_gate.py +0 -182
- package/hooks/blocking/test_code_review_enforcement_config_bootstrap.py +0 -62
- package/hooks/blocking/test_code_review_gate_deny.py +0 -54
- package/hooks/blocking/test_code_review_pr_create_gate.py +0 -199
- package/hooks/blocking/test_code_review_push_gate.py +0 -205
- package/hooks/blocking/test_code_review_stamp_directory_write_blocker.py +0 -199
- package/hooks/blocking/test_code_review_stamp_store.py +0 -205
- package/hooks/blocking/test_code_verifier_spawn_preflight_gate.py +0 -710
- package/hooks/blocking/test_code_verifier_tools_contract.py +0 -28
- package/hooks/blocking/test_convergence_gate_blocker.py +0 -428
- package/hooks/blocking/test_pr_converge_bugteam_enforcer.py +0 -311
- package/hooks/blocking/test_pr_converge_bugteam_enforcer_state_tolerance.py +0 -184
- package/hooks/blocking/test_pr_description_enforcer.py +0 -221
- package/hooks/blocking/test_pr_description_enforcer_body_audit.py +0 -247
- package/hooks/blocking/test_pr_description_enforcer_body_rules.py +0 -493
- package/hooks/blocking/test_pr_description_enforcer_command_parser.py +0 -366
- package/hooks/blocking/test_pr_description_enforcer_pr_number.py +0 -159
- package/hooks/blocking/test_pr_description_enforcer_proof_gate.py +0 -175
- package/hooks/blocking/test_pr_description_enforcer_readability.py +0 -443
- package/hooks/blocking/test_pr_description_proof_of_work.py +0 -313
- package/hooks/blocking/test_reviewer_spawn_gate.py +0 -230
- package/hooks/blocking/test_verdict_directory_write_blocker.py +0 -804
- package/hooks/blocking/test_verification_verdict_store.py +0 -974
- package/hooks/blocking/test_verified_commit_config_bootstrap.py +0 -67
- package/hooks/blocking/test_verified_commit_docs_delta.py +0 -176
- package/hooks/blocking/test_verified_commit_gate.py +0 -581
- package/hooks/blocking/test_verified_commit_gate_additional_context.py +0 -134
- package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +0 -131
- package/hooks/blocking/test_verifier_verdict_minter.py +0 -299
- package/hooks/blocking/tests/test_verified_commit_gate.py +0 -41
- package/hooks/blocking/verdict_directory_write_blocker.py +0 -687
- package/hooks/blocking/verification_verdict_store.py +0 -1039
- package/hooks/blocking/verified_commit_config_bootstrap.py +0 -63
- package/hooks/blocking/verified_commit_gate.py +0 -113
- package/hooks/blocking/verified_commit_gate_parts/CLAUDE.md +0 -28
- package/hooks/blocking/verified_commit_gate_parts/__init__.py +0 -1
- package/hooks/blocking/verified_commit_gate_parts/command_tokenization.py +0 -174
- package/hooks/blocking/verified_commit_gate_parts/deny_payload.py +0 -53
- package/hooks/blocking/verified_commit_gate_parts/deny_reason.py +0 -80
- package/hooks/blocking/verified_commit_gate_parts/directory_resolution.py +0 -170
- package/hooks/blocking/verified_commit_gate_parts/gated_invocations.py +0 -217
- package/hooks/blocking/verified_commit_gate_parts/tests/conftest.py +0 -10
- package/hooks/blocking/verified_commit_gate_parts/tests/test_command_tokenization.py +0 -94
- package/hooks/blocking/verified_commit_gate_parts/tests/test_deny_payload.py +0 -17
- package/hooks/blocking/verified_commit_gate_parts/tests/test_deny_reason.py +0 -38
- package/hooks/blocking/verified_commit_gate_parts/tests/test_directory_resolution.py +0 -71
- package/hooks/blocking/verified_commit_gate_parts/tests/test_gated_invocations.py +0 -96
- package/hooks/blocking/verified_commit_message_accuracy_blocker.py +0 -167
- package/hooks/blocking/verifier_verdict_minter.py +0 -280
- package/hooks/hooks_constants/code_verifier_spawn_preflight_gate_constants.py +0 -64
- package/hooks/hooks_constants/convergence_gate_blocker_constants.py +0 -53
- package/hooks/hooks_constants/pr_converge_bugteam_enforcer_constants.py +0 -55
- package/hooks/hooks_constants/pr_converge_bugteam_enforcer_state.py +0 -67
- package/hooks/hooks_constants/pr_description_enforcer_constants.py +0 -167
- package/hooks/hooks_constants/pr_description_proof_of_work_constants.py +0 -107
- package/hooks/hooks_constants/reviewer_spawn_gate_constants.py +0 -41
- package/hooks/hooks_constants/test_pr_description_enforcer_constants.py +0 -292
- package/hooks/lifecycle/pr_converge_bugteam_skill_tracker.py +0 -198
- package/hooks/lifecycle/test_pr_converge_bugteam_skill_tracker.py +0 -283
- package/rules/proof-of-work-pr-comments.md +0 -22
- package/rules/verified-commit-gate-skip.md +0 -4
- package/scripts/Show-Asset.ps1 +0 -106
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
"""Configuration constants for the pr_description_enforcer PreToolUse hook."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import os
|
|
6
|
-
import re
|
|
7
|
-
from dataclasses import dataclass
|
|
8
|
-
from pathlib import Path
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
_PLUGIN_ROOT: str = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
12
|
-
PR_GUIDE_PATH: str = os.path.join(_PLUGIN_ROOT, "docs", "PR_DESCRIPTION_GUIDE.md")
|
|
13
|
-
|
|
14
|
-
MINIMUM_SUBSTANTIVE_PROSE_CHARS: int = 40
|
|
15
|
-
|
|
16
|
-
FENCED_CODE_BLOCK_PATTERN: re.Pattern[str] = re.compile(r"```.*?```", re.DOTALL)
|
|
17
|
-
INLINE_CODE_PATTERN: re.Pattern[str] = re.compile(r"`[^`]*`")
|
|
18
|
-
HEADING_LINE_PATTERN: re.Pattern[str] = re.compile(r"^#+[ \t].*$", re.MULTILINE)
|
|
19
|
-
BOLD_PAIR_PATTERN: re.Pattern[str] = re.compile(r"\*\*([^*]+?)\*\*")
|
|
20
|
-
BULLET_MARKER_PATTERN: re.Pattern[str] = re.compile(r"^\s*[-*+]\s+", re.MULTILINE)
|
|
21
|
-
BLOCKQUOTE_MARKER_PATTERN: re.Pattern[str] = re.compile(r"^\s*>\s+", re.MULTILINE)
|
|
22
|
-
BLOCKQUOTE_LINE_PATTERN: re.Pattern[str] = re.compile(r"^\s*>.*$", re.MULTILINE)
|
|
23
|
-
TABLE_ROW_LINE_PATTERN: re.Pattern[str] = re.compile(r"^\s*\|.*\|.*$", re.MULTILINE)
|
|
24
|
-
LINK_TEXT_PATTERN: re.Pattern[str] = re.compile(r"\[([^\]]+)\]\([^)]+\)")
|
|
25
|
-
WHITESPACE_RUN_PATTERN: re.Pattern[str] = re.compile(r"\s+")
|
|
26
|
-
VAGUE_LANGUAGE_PATTERN: re.Pattern[str] = re.compile(
|
|
27
|
-
r"\b(fix(?:ed)? (?:bug|issue|it)|update(?:d)? code|minor changes|various (?:fixes|updates|improvements))\b",
|
|
28
|
-
re.IGNORECASE,
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
SUMMARY_HEADER: str = "## Summary"
|
|
32
|
-
PROBLEM_HEADER: str = "## Problem"
|
|
33
|
-
TEST_PLAN_HEADER: str = "## Test plan"
|
|
34
|
-
TESTS_HEADER: str = "## Tests"
|
|
35
|
-
TESTING_HEADER: str = "## Testing"
|
|
36
|
-
VERIFICATION_HEADER: str = "## Verification"
|
|
37
|
-
VALIDATION_HEADER: str = "## Validation"
|
|
38
|
-
|
|
39
|
-
ALL_HEAVY_OPENING_HEADERS: frozenset[str] = frozenset({PROBLEM_HEADER, SUMMARY_HEADER})
|
|
40
|
-
ALL_HEAVY_TESTING_HEADERS: frozenset[str] = frozenset(
|
|
41
|
-
{TEST_PLAN_HEADER, TESTING_HEADER, TESTS_HEADER, VERIFICATION_HEADER, VALIDATION_HEADER}
|
|
42
|
-
)
|
|
43
|
-
GH_PR_COMMAND_MIN_TOKEN_COUNT: int = 3
|
|
44
|
-
ALL_PR_NUMBER_BEARING_GH_PR_SUBCOMMANDS: frozenset[str] = frozenset({"edit", "comment", "ready"})
|
|
45
|
-
BODY_FILE_STDIN_SENTINEL: str = "-"
|
|
46
|
-
ATOMIC_WRITE_TEMP_SUFFIX: str = ".tmp"
|
|
47
|
-
SELF_CLOSING_REFERENCE_MESSAGE_PREFIX: str = "PR body references its own PR number #"
|
|
48
|
-
SELF_CLOSING_REFERENCE_MESSAGE_SUFFIX: str = (
|
|
49
|
-
" as a self-closing keyword (Fixes/Closes/Resolves) -- remove the self-reference"
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
SELF_REFERENCE_PATTERN_TEMPLATE: str = (
|
|
53
|
-
r"\b(?:Close|Closes|Closed|Fix|Fixes|Fixed|Resolve|Resolves|Resolved)"
|
|
54
|
-
r"\s+#{pr_number}\b"
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
THIS_PR_OPENING_PATTERN: re.Pattern[str] = re.compile(
|
|
58
|
-
r"^\s*(?:#[^\n]*\n\s*)*This PR\b",
|
|
59
|
-
re.IGNORECASE,
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
TRIVIAL_SHAPE: str = "trivial"
|
|
63
|
-
STANDARD_SHAPE: str = "standard"
|
|
64
|
-
HEAVY_SHAPE: str = "heavy"
|
|
65
|
-
|
|
66
|
-
TRIVIAL_BODY_CHAR_THRESHOLD: int = 200
|
|
67
|
-
HEAVY_MIN_BODY_CHARS_FOR_CLASSIFICATION: int = 500
|
|
68
|
-
|
|
69
|
-
READABILITY_MAX_SENTENCE_WORDS: int = 28
|
|
70
|
-
READABILITY_AVG_SENTENCE_WORDS: int = 18
|
|
71
|
-
READABILITY_MIN_FLESCH: int = 50
|
|
72
|
-
READABILITY_STRIKE_THRESHOLD: int = 3
|
|
73
|
-
|
|
74
|
-
READABILITY_LOOSEN_CAP: int = 3
|
|
75
|
-
READABILITY_MIN_FLESCH_FLOOR: int = 30
|
|
76
|
-
READABILITY_MAX_SENTENCE_WORDS_CEILING: int = 60
|
|
77
|
-
READABILITY_AVG_SENTENCE_WORDS_CEILING: int = 40
|
|
78
|
-
|
|
79
|
-
READABILITY_FLESCH_LOOSEN_FACTOR: float = 0.9
|
|
80
|
-
READABILITY_SENTENCE_WORDS_LOOSEN_FACTOR: float = 10 / 9
|
|
81
|
-
|
|
82
|
-
ALL_READABILITY_CLI_FLAG_TOKENS: frozenset[str] = frozenset(
|
|
83
|
-
{
|
|
84
|
-
"--readability-loosen",
|
|
85
|
-
"--readability-reset",
|
|
86
|
-
"--readability-disable",
|
|
87
|
-
"--readability-enable",
|
|
88
|
-
}
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
FLESCH_BASE_SCORE: float = 206.835
|
|
92
|
-
FLESCH_WORDS_PER_SENTENCE_COEFFICIENT: float = 1.015
|
|
93
|
-
FLESCH_SYLLABLES_PER_WORD_COEFFICIENT: float = 84.6
|
|
94
|
-
FLESCH_PERFECT_SCORE: float = 100.0
|
|
95
|
-
|
|
96
|
-
READABILITY_STATE_FILE: Path = Path.home() / ".claude" / "state" / "pr_description_readability_strikes.json"
|
|
97
|
-
READABILITY_THRESHOLD_OVERRIDE_FILE: Path = (
|
|
98
|
-
Path.home() / ".claude" / "state" / "pr_description_readability_overrides.json"
|
|
99
|
-
)
|
|
100
|
-
READABILITY_ENABLED_STATE_FILE: Path = (
|
|
101
|
-
Path.home() / ".claude" / "state" / "pr_description_readability_enabled.json"
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
@dataclass(frozen=True)
|
|
106
|
-
class ReadabilityThresholds:
|
|
107
|
-
"""Three readability thresholds carried as a single typed structure."""
|
|
108
|
-
|
|
109
|
-
flesch_min: int
|
|
110
|
-
max_sentence_words: int
|
|
111
|
-
avg_sentence_words: int
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
DEFAULT_READABILITY_THRESHOLDS: ReadabilityThresholds = ReadabilityThresholds(
|
|
115
|
-
flesch_min=READABILITY_MIN_FLESCH,
|
|
116
|
-
max_sentence_words=READABILITY_MAX_SENTENCE_WORDS,
|
|
117
|
-
avg_sentence_words=READABILITY_AVG_SENTENCE_WORDS,
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
__all__ = [
|
|
122
|
-
"ALL_HEAVY_OPENING_HEADERS",
|
|
123
|
-
"ALL_HEAVY_TESTING_HEADERS",
|
|
124
|
-
"ALL_PR_NUMBER_BEARING_GH_PR_SUBCOMMANDS",
|
|
125
|
-
"ALL_READABILITY_CLI_FLAG_TOKENS",
|
|
126
|
-
"ATOMIC_WRITE_TEMP_SUFFIX",
|
|
127
|
-
"BLOCKQUOTE_LINE_PATTERN",
|
|
128
|
-
"BLOCKQUOTE_MARKER_PATTERN",
|
|
129
|
-
"BODY_FILE_STDIN_SENTINEL",
|
|
130
|
-
"BOLD_PAIR_PATTERN",
|
|
131
|
-
"BULLET_MARKER_PATTERN",
|
|
132
|
-
"DEFAULT_READABILITY_THRESHOLDS",
|
|
133
|
-
"FENCED_CODE_BLOCK_PATTERN",
|
|
134
|
-
"FLESCH_BASE_SCORE",
|
|
135
|
-
"FLESCH_PERFECT_SCORE",
|
|
136
|
-
"FLESCH_SYLLABLES_PER_WORD_COEFFICIENT",
|
|
137
|
-
"FLESCH_WORDS_PER_SENTENCE_COEFFICIENT",
|
|
138
|
-
"GH_PR_COMMAND_MIN_TOKEN_COUNT",
|
|
139
|
-
"HEADING_LINE_PATTERN",
|
|
140
|
-
"HEAVY_MIN_BODY_CHARS_FOR_CLASSIFICATION",
|
|
141
|
-
"HEAVY_SHAPE",
|
|
142
|
-
"INLINE_CODE_PATTERN",
|
|
143
|
-
"LINK_TEXT_PATTERN",
|
|
144
|
-
"MINIMUM_SUBSTANTIVE_PROSE_CHARS",
|
|
145
|
-
"PR_GUIDE_PATH",
|
|
146
|
-
"READABILITY_AVG_SENTENCE_WORDS_CEILING",
|
|
147
|
-
"READABILITY_ENABLED_STATE_FILE",
|
|
148
|
-
"READABILITY_FLESCH_LOOSEN_FACTOR",
|
|
149
|
-
"READABILITY_LOOSEN_CAP",
|
|
150
|
-
"READABILITY_MAX_SENTENCE_WORDS_CEILING",
|
|
151
|
-
"READABILITY_MIN_FLESCH_FLOOR",
|
|
152
|
-
"READABILITY_SENTENCE_WORDS_LOOSEN_FACTOR",
|
|
153
|
-
"READABILITY_STATE_FILE",
|
|
154
|
-
"READABILITY_STRIKE_THRESHOLD",
|
|
155
|
-
"READABILITY_THRESHOLD_OVERRIDE_FILE",
|
|
156
|
-
"ReadabilityThresholds",
|
|
157
|
-
"SELF_CLOSING_REFERENCE_MESSAGE_PREFIX",
|
|
158
|
-
"SELF_CLOSING_REFERENCE_MESSAGE_SUFFIX",
|
|
159
|
-
"SELF_REFERENCE_PATTERN_TEMPLATE",
|
|
160
|
-
"STANDARD_SHAPE",
|
|
161
|
-
"TABLE_ROW_LINE_PATTERN",
|
|
162
|
-
"THIS_PR_OPENING_PATTERN",
|
|
163
|
-
"TRIVIAL_BODY_CHAR_THRESHOLD",
|
|
164
|
-
"TRIVIAL_SHAPE",
|
|
165
|
-
"VAGUE_LANGUAGE_PATTERN",
|
|
166
|
-
"WHITESPACE_RUN_PATTERN",
|
|
167
|
-
]
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
"""Configuration constants for the proof-of-work PR-comment audit.
|
|
2
|
-
|
|
3
|
-
Holds the proof-part detection patterns, the gap and linkage word lists,
|
|
4
|
-
the gh command tokens the audit runs to read a PR's comments and diff, and
|
|
5
|
-
the corrective messages returned when a proof part is missing or when
|
|
6
|
-
``gh pr ready`` runs with no passing proof comment on the PR.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from __future__ import annotations
|
|
10
|
-
|
|
11
|
-
import re
|
|
12
|
-
|
|
13
|
-
ALL_PROOF_HEADING_KEYWORDS: tuple[str, ...] = ("proof", "verification")
|
|
14
|
-
|
|
15
|
-
PR_READY_INVOCATION_PATTERN: re.Pattern[str] = re.compile(r"(?:^|[;&|])\s*gh\s+pr\s+ready\b")
|
|
16
|
-
PR_READY_UNDO_FLAG: str = "--undo"
|
|
17
|
-
|
|
18
|
-
GH_EXECUTABLE: str = "gh"
|
|
19
|
-
GH_API_SUBCOMMAND: str = "api"
|
|
20
|
-
GH_PAGINATE_FLAG: str = "--paginate"
|
|
21
|
-
GH_SLURP_FLAG: str = "--slurp"
|
|
22
|
-
PR_COMMENTS_API_PATH_TEMPLATE: str = "repos/{{owner}}/{{repo}}/issues/{pr_number}/comments"
|
|
23
|
-
ALL_PR_DIFF_SUBCOMMANDS: tuple[str, ...] = ("pr", "diff")
|
|
24
|
-
PR_DIFF_NAME_ONLY_FLAG: str = "--name-only"
|
|
25
|
-
COMMENT_BODY_JSON_FIELD: str = "body"
|
|
26
|
-
GH_COMMAND_TIMEOUT_SECONDS: int = 6
|
|
27
|
-
MAX_DIFF_SCAN_CHARS: int = 200000
|
|
28
|
-
|
|
29
|
-
ALL_VISUAL_FILE_SUFFIXES: frozenset[str] = frozenset(
|
|
30
|
-
{".png", ".jpg", ".jpeg", ".gif", ".webp", ".avif", ".svg", ".ico", ".html", ".css"}
|
|
31
|
-
)
|
|
32
|
-
HEX_COLOR_ADDED_LINE_PATTERN: re.Pattern[str] = re.compile(r"^\+.*#[0-9A-Fa-f]{6}\b", re.MULTILINE)
|
|
33
|
-
IMAGE_EMBED_PATTERN: re.Pattern[str] = re.compile(r"!\[[^\]]*\]\([^)\s]+\)")
|
|
34
|
-
ISSUE_REFERENCE_PATTERN: re.Pattern[str] = re.compile(r"#\d+")
|
|
35
|
-
PLAN_LINKAGE_KEYWORD_PATTERN: re.Pattern[str] = re.compile(
|
|
36
|
-
r"\b(?:issue|phase|plan|parent|advanc\w*|milestone|part of)\b", re.IGNORECASE
|
|
37
|
-
)
|
|
38
|
-
DIGIT_PATTERN: re.Pattern[str] = re.compile(r"\d")
|
|
39
|
-
ALL_HONEST_GAP_PHRASES: tuple[str, ...] = (
|
|
40
|
-
"gap",
|
|
41
|
-
"limitation",
|
|
42
|
-
"cannot",
|
|
43
|
-
"does not show",
|
|
44
|
-
"not shown",
|
|
45
|
-
"unverified",
|
|
46
|
-
"not covered",
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
PROOF_PART_COMMAND_MESSAGE: str = (
|
|
50
|
-
"proof comment missing a fenced command block showing the exact command(s) run on real data"
|
|
51
|
-
)
|
|
52
|
-
PROOF_PART_MEASURED_MESSAGE: str = (
|
|
53
|
-
"proof comment missing a measured-value element -- add a table row or bullet fact carrying "
|
|
54
|
-
"the numbers read from the produced artifact"
|
|
55
|
-
)
|
|
56
|
-
PROOF_PART_PLAN_LINKAGE_MESSAGE: str = (
|
|
57
|
-
"proof comment missing a plan-linkage sentence -- add one line naming the parent issue or "
|
|
58
|
-
"phase this PR advances, with its #number"
|
|
59
|
-
)
|
|
60
|
-
PROOF_PART_VISUAL_MESSAGE: str = (
|
|
61
|
-
"proof comment missing a visual element on a visual change -- embed an image (color "
|
|
62
|
-
"swatches, before/after screenshots) for values a human cannot read at a glance"
|
|
63
|
-
)
|
|
64
|
-
PROOF_PART_HONEST_GAPS_MESSAGE: str = (
|
|
65
|
-
"proof comment missing an honest-gaps statement -- say plainly what this offline proof "
|
|
66
|
-
"cannot show and what covers that gap"
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
PR_READY_GATE_MESSAGE_TEMPLATE: str = (
|
|
70
|
-
"BLOCKED: [PROOF_OF_WORK] PR #{pr_number} carries no passing proof-of-work comment. "
|
|
71
|
-
"Post one comment with a proof or verification heading carrying: "
|
|
72
|
-
"(1) the exact command(s) run on real data in a fenced code block, "
|
|
73
|
-
"(2) measured outcomes from the produced artifact as a table row or bullet facts, "
|
|
74
|
-
"(3) one sentence naming the parent issue or phase this PR advances, with its #number, "
|
|
75
|
-
"(4) an image embed when the diff touches images, HTML, CSS, or hex color values, and "
|
|
76
|
-
"(5) an honest statement of what the offline proof cannot show. "
|
|
77
|
-
"Then re-run gh pr ready."
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
__all__ = [
|
|
81
|
-
"ALL_HONEST_GAP_PHRASES",
|
|
82
|
-
"ALL_PROOF_HEADING_KEYWORDS",
|
|
83
|
-
"ALL_PR_DIFF_SUBCOMMANDS",
|
|
84
|
-
"ALL_VISUAL_FILE_SUFFIXES",
|
|
85
|
-
"COMMENT_BODY_JSON_FIELD",
|
|
86
|
-
"DIGIT_PATTERN",
|
|
87
|
-
"GH_API_SUBCOMMAND",
|
|
88
|
-
"GH_COMMAND_TIMEOUT_SECONDS",
|
|
89
|
-
"GH_EXECUTABLE",
|
|
90
|
-
"GH_PAGINATE_FLAG",
|
|
91
|
-
"GH_SLURP_FLAG",
|
|
92
|
-
"HEX_COLOR_ADDED_LINE_PATTERN",
|
|
93
|
-
"IMAGE_EMBED_PATTERN",
|
|
94
|
-
"ISSUE_REFERENCE_PATTERN",
|
|
95
|
-
"MAX_DIFF_SCAN_CHARS",
|
|
96
|
-
"PLAN_LINKAGE_KEYWORD_PATTERN",
|
|
97
|
-
"PROOF_PART_COMMAND_MESSAGE",
|
|
98
|
-
"PROOF_PART_HONEST_GAPS_MESSAGE",
|
|
99
|
-
"PROOF_PART_MEASURED_MESSAGE",
|
|
100
|
-
"PROOF_PART_PLAN_LINKAGE_MESSAGE",
|
|
101
|
-
"PROOF_PART_VISUAL_MESSAGE",
|
|
102
|
-
"PR_COMMENTS_API_PATH_TEMPLATE",
|
|
103
|
-
"PR_DIFF_NAME_ONLY_FLAG",
|
|
104
|
-
"PR_READY_GATE_MESSAGE_TEMPLATE",
|
|
105
|
-
"PR_READY_INVOCATION_PATTERN",
|
|
106
|
-
"PR_READY_UNDO_FLAG",
|
|
107
|
-
]
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
"""Configuration constants for the reviewer_spawn_gate PreToolUse hook."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import re
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
|
|
8
|
-
BASH_TOOL_NAME: str = "Bash"
|
|
9
|
-
|
|
10
|
-
GATE_SENTINEL_MARKER: str = "CLAUDE_REVIEWER_GATE=autoconverge"
|
|
11
|
-
|
|
12
|
-
COPILOT_REVIEWER_TOKEN: str = "copilot"
|
|
13
|
-
BUGBOT_REVIEWER_TOKEN: str = "bugbot"
|
|
14
|
-
|
|
15
|
-
COPILOT_REVIEWER_LABEL: str = "GitHub Copilot"
|
|
16
|
-
BUGBOT_REVIEWER_LABEL: str = "Cursor Bugbot"
|
|
17
|
-
|
|
18
|
-
ALL_COPILOT_TRIGGER_MARKERS: tuple[str, ...] = (
|
|
19
|
-
"requested_reviewers",
|
|
20
|
-
"copilot-pull-request-reviewer[bot]",
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
BUGBOT_TRIGGER_SCRIPT_MARKER: str = "post_fix_reply.py"
|
|
24
|
-
BUGBOT_RUN_BODY_PATTERN: re.Pattern[str] = re.compile(
|
|
25
|
-
r'--body\s+["\']bugbot run["\']', re.IGNORECASE
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
AVAILABILITY_SCRIPT_RELATIVE_PATH: Path = (
|
|
29
|
-
Path("_shared") / "pr-loop" / "scripts" / "reviewer_availability.py"
|
|
30
|
-
)
|
|
31
|
-
AVAILABILITY_SCRIPT_PATH_ENV_VAR_NAME: str = "REVIEWER_SPAWN_GATE_AVAILABILITY_SCRIPT_PATH"
|
|
32
|
-
AVAILABILITY_SCRIPT_TIMEOUT_SECONDS: int = 15
|
|
33
|
-
AVAILABILITY_REVIEWER_FLAG: str = "--reviewer"
|
|
34
|
-
AVAILABILITY_DOWN_EXIT_CODE: int = 3
|
|
35
|
-
|
|
36
|
-
DENY_REASON_TEMPLATE: str = (
|
|
37
|
-
"BLOCKED [reviewer-spawn-gate]: {reviewer_label} is down or out of quota "
|
|
38
|
-
"this run. Skip requesting {reviewer_label} on this trigger — "
|
|
39
|
-
"autoconverge requests it again once the availability check reports it "
|
|
40
|
-
"back.\n\nAvailability check output: {availability_detail}"
|
|
41
|
-
)
|
|
@@ -1,292 +0,0 @@
|
|
|
1
|
-
"""Behavior tests for pr_description_enforcer_constants module."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import os
|
|
6
|
-
import sys
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
|
|
9
|
-
import pytest
|
|
10
|
-
|
|
11
|
-
_HOOKS_ROOT = Path(__file__).resolve().parent.parent
|
|
12
|
-
if str(_HOOKS_ROOT) not in sys.path:
|
|
13
|
-
sys.path.insert(0, str(_HOOKS_ROOT))
|
|
14
|
-
|
|
15
|
-
from hooks_constants import pr_description_enforcer_constants as constants_module
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def test_plugin_root_is_private_module_attribute() -> None:
|
|
19
|
-
assert hasattr(constants_module, "_PLUGIN_ROOT")
|
|
20
|
-
assert isinstance(constants_module._PLUGIN_ROOT, str)
|
|
21
|
-
assert os.path.isabs(constants_module._PLUGIN_ROOT)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def test_plugin_root_public_name_is_not_exported() -> None:
|
|
25
|
-
assert not hasattr(constants_module, "PLUGIN_ROOT")
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def test_pr_guide_path_resolves_under_plugin_root_docs() -> None:
|
|
29
|
-
expected_pr_guide_path = os.path.join(
|
|
30
|
-
constants_module._PLUGIN_ROOT, "docs", "PR_DESCRIPTION_GUIDE.md"
|
|
31
|
-
)
|
|
32
|
-
assert constants_module.PR_GUIDE_PATH == expected_pr_guide_path
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def test_fenced_code_block_pattern_matches_triple_backtick_block() -> None:
|
|
36
|
-
sample_markdown = "before ```python\ncode\n``` after"
|
|
37
|
-
match = constants_module.FENCED_CODE_BLOCK_PATTERN.search(sample_markdown)
|
|
38
|
-
assert match is not None
|
|
39
|
-
assert match.group(0).startswith("```")
|
|
40
|
-
assert match.group(0).endswith("```")
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def test_inline_code_pattern_matches_single_backtick_span() -> None:
|
|
44
|
-
match = constants_module.INLINE_CODE_PATTERN.search("see `value` here")
|
|
45
|
-
assert match is not None
|
|
46
|
-
assert match.group(0) == "`value`"
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def test_heading_line_pattern_matches_atx_heading() -> None:
|
|
50
|
-
match = constants_module.HEADING_LINE_PATTERN.search("## Description\n")
|
|
51
|
-
assert match is not None
|
|
52
|
-
assert match.group(0).strip() == "## Description"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def test_bold_pair_pattern_captures_inner_text() -> None:
|
|
56
|
-
match = constants_module.BOLD_PAIR_PATTERN.search("this is **bold** text")
|
|
57
|
-
assert match is not None
|
|
58
|
-
assert match.group(1) == "bold"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def test_bullet_marker_pattern_strips_dash_bullet_from_line() -> None:
|
|
62
|
-
stripped_line = constants_module.BULLET_MARKER_PATTERN.sub("", "- first item")
|
|
63
|
-
assert stripped_line == "first item"
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def test_blockquote_marker_pattern_strips_quote_marker_from_line() -> None:
|
|
67
|
-
stripped_line = constants_module.BLOCKQUOTE_MARKER_PATTERN.sub("", "> quoted line")
|
|
68
|
-
assert stripped_line == "quoted line"
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def test_link_text_pattern_captures_anchor_text() -> None:
|
|
72
|
-
match = constants_module.LINK_TEXT_PATTERN.search("See [the docs](https://example.com) now")
|
|
73
|
-
assert match is not None
|
|
74
|
-
assert match.group(1) == "the docs"
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def test_whitespace_run_pattern_collapses_multiple_spaces() -> None:
|
|
78
|
-
collapsed_text = constants_module.WHITESPACE_RUN_PATTERN.sub(" ", "a b\t\tc\n\nd")
|
|
79
|
-
assert collapsed_text == "a b c d"
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def test_this_pr_opening_pattern_matches_any_verb() -> None:
|
|
83
|
-
"""The guide says any `This PR ...` opening is a hard block. The pattern
|
|
84
|
-
must match regardless of the verb that follows, not a short allowlist."""
|
|
85
|
-
test_inputs = [
|
|
86
|
-
"This PR introduces a new feature.",
|
|
87
|
-
"This PR improves the algorithm.",
|
|
88
|
-
"This PR enables the cache.",
|
|
89
|
-
"This PR documents the contract.",
|
|
90
|
-
"This PR adds a check.",
|
|
91
|
-
"This PR fixes the bug.",
|
|
92
|
-
]
|
|
93
|
-
for each_input in test_inputs:
|
|
94
|
-
assert constants_module.THIS_PR_OPENING_PATTERN.match(each_input), (
|
|
95
|
-
f"`{each_input}` must match THIS_PR_OPENING_PATTERN regardless of verb"
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
def test_this_pr_opening_pattern_does_not_match_within_prose() -> None:
|
|
100
|
-
"""The block applies to body openings, not mid-paragraph mentions."""
|
|
101
|
-
text_with_mid_mention = "Adds caching. This PR follows the playbook."
|
|
102
|
-
assert constants_module.THIS_PR_OPENING_PATTERN.match(text_with_mid_mention) is None
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
def test_all_list_is_alphabetically_sorted() -> None:
|
|
106
|
-
"""`__all__` is the export surface; alphabetical order makes it easy to
|
|
107
|
-
verify completeness, spot duplicates, and bisect missing entries. Pin
|
|
108
|
-
sorted order so drift cannot reintroduce the H-before-G / appended-at-end
|
|
109
|
-
inconsistencies Bugbot flagged."""
|
|
110
|
-
actual_all_list = constants_module.__all__
|
|
111
|
-
expected_sorted = sorted(actual_all_list)
|
|
112
|
-
if actual_all_list != expected_sorted:
|
|
113
|
-
first_divergence_index = next(
|
|
114
|
-
each_index
|
|
115
|
-
for each_index, (each_actual_value, each_expected_value) in enumerate(zip(actual_all_list, expected_sorted))
|
|
116
|
-
if each_actual_value != each_expected_value
|
|
117
|
-
)
|
|
118
|
-
raise AssertionError(
|
|
119
|
-
"constants_module.__all__ must be alphabetically sorted; "
|
|
120
|
-
f"the first divergence is at index {first_divergence_index}: "
|
|
121
|
-
f"got {actual_all_list[first_divergence_index]!r}, "
|
|
122
|
-
f"expected {expected_sorted[first_divergence_index]!r}"
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
def test_dead_heavy_detection_constants_are_removed() -> None:
|
|
127
|
-
"""`ALL_HEAVY_DETECTION_HEADERS` and `HEAVY_DETECTION_HEADER_COUNT_MIN`
|
|
128
|
-
were remnants of the prior two-condition shape classifier (length AND
|
|
129
|
-
detection-header count). e137dee9 simplified the classifier to use length
|
|
130
|
-
alone, leaving both names as dead exports. Pin their removal so they
|
|
131
|
-
cannot drift back as misleading vestigial constants."""
|
|
132
|
-
for each_name in ("ALL_HEAVY_DETECTION_HEADERS", "HEAVY_DETECTION_HEADER_COUNT_MIN"):
|
|
133
|
-
assert not hasattr(constants_module, each_name), (
|
|
134
|
-
f"{each_name} must be deleted; the classifier now uses "
|
|
135
|
-
"HEAVY_MIN_BODY_CHARS_FOR_CLASSIFICATION alone."
|
|
136
|
-
)
|
|
137
|
-
assert each_name not in constants_module.__all__
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
def test_self_closing_reference_message_prefix_and_suffix_compose_full_message() -> None:
|
|
141
|
-
pr_number = 42
|
|
142
|
-
composed_message = (
|
|
143
|
-
f"{constants_module.SELF_CLOSING_REFERENCE_MESSAGE_PREFIX}"
|
|
144
|
-
f"{pr_number}"
|
|
145
|
-
f"{constants_module.SELF_CLOSING_REFERENCE_MESSAGE_SUFFIX}"
|
|
146
|
-
)
|
|
147
|
-
assert "#42" in composed_message
|
|
148
|
-
assert "Fixes/Closes/Resolves" in composed_message
|
|
149
|
-
assert "self-reference" in composed_message
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
def test_loosen_factors_are_inverse_paired() -> None:
|
|
153
|
-
flesch_factor = constants_module.READABILITY_FLESCH_LOOSEN_FACTOR
|
|
154
|
-
sentence_factor = constants_module.READABILITY_SENTENCE_WORDS_LOOSEN_FACTOR
|
|
155
|
-
assert flesch_factor * sentence_factor == pytest.approx(1.0)
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
def test_unused_header_constants_are_removed_from_module() -> None:
|
|
159
|
-
"""The four header constants FIX_HEADER, CHANGES_HEADER, APPROACH_HEADER,
|
|
160
|
-
and ROOT_CAUSE_HEADER were dead exports with no call sites and must not be
|
|
161
|
-
re-introduced as either module attributes or __all__ entries."""
|
|
162
|
-
for each_dead_name in ("FIX_HEADER", "CHANGES_HEADER", "APPROACH_HEADER", "ROOT_CAUSE_HEADER"):
|
|
163
|
-
assert not hasattr(constants_module, each_dead_name), (
|
|
164
|
-
f"{each_dead_name} was re-introduced; the four header constants "
|
|
165
|
-
"had zero call sites and were deleted."
|
|
166
|
-
)
|
|
167
|
-
assert each_dead_name not in constants_module.__all__, (
|
|
168
|
-
f"{each_dead_name} re-appeared in __all__ even though it has no consumers."
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
def test_module_internal_header_constants_are_not_publicly_exported() -> None:
|
|
173
|
-
"""The seven header-name constants and three default-readability-threshold scalars
|
|
174
|
-
are consumed only inside this same module (used to build ALL_HEAVY_* frozensets
|
|
175
|
-
and DEFAULT_READABILITY_THRESHOLDS). They must remain module attributes for the
|
|
176
|
-
builder expressions, but they must NOT appear in __all__ -- callers should import
|
|
177
|
-
the public aggregates (ALL_HEAVY_OPENING_HEADERS / ALL_HEAVY_TESTING_HEADERS /
|
|
178
|
-
DEFAULT_READABILITY_THRESHOLDS) instead of the individual scalars."""
|
|
179
|
-
all_internal_only_names = (
|
|
180
|
-
"SUMMARY_HEADER",
|
|
181
|
-
"PROBLEM_HEADER",
|
|
182
|
-
"TEST_PLAN_HEADER",
|
|
183
|
-
"TESTS_HEADER",
|
|
184
|
-
"TESTING_HEADER",
|
|
185
|
-
"VERIFICATION_HEADER",
|
|
186
|
-
"VALIDATION_HEADER",
|
|
187
|
-
"READABILITY_MAX_SENTENCE_WORDS",
|
|
188
|
-
"READABILITY_AVG_SENTENCE_WORDS",
|
|
189
|
-
"READABILITY_MIN_FLESCH",
|
|
190
|
-
)
|
|
191
|
-
for each_internal_name in all_internal_only_names:
|
|
192
|
-
assert hasattr(constants_module, each_internal_name), (
|
|
193
|
-
f"{each_internal_name} must remain as a module attribute -- "
|
|
194
|
-
"the aggregate builders reference it."
|
|
195
|
-
)
|
|
196
|
-
assert each_internal_name not in constants_module.__all__, (
|
|
197
|
-
f"{each_internal_name} is consumed only inside the module and "
|
|
198
|
-
"must not be advertised in __all__."
|
|
199
|
-
)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
def test_self_reference_pattern_covers_all_nine_github_closing_keywords() -> None:
|
|
203
|
-
"""GitHub recognizes nine closing keywords: close/closes/closed,
|
|
204
|
-
fix/fixes/fixed, resolve/resolves/resolved. The self-reference template
|
|
205
|
-
must enumerate all nine so no variant bypasses the self-closing block."""
|
|
206
|
-
pattern_source = constants_module.SELF_REFERENCE_PATTERN_TEMPLATE
|
|
207
|
-
for each_keyword in (
|
|
208
|
-
"Close", "Closes", "Closed",
|
|
209
|
-
"Fix", "Fixes", "Fixed",
|
|
210
|
-
"Resolve", "Resolves", "Resolved",
|
|
211
|
-
):
|
|
212
|
-
assert each_keyword in pattern_source, (
|
|
213
|
-
f"SELF_REFERENCE_PATTERN_TEMPLATE must enumerate `{each_keyword}` "
|
|
214
|
-
f"to catch every GitHub closing-keyword variant; got: {pattern_source!r}"
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
def test_body_shape_string_literals_are_named_constants() -> None:
|
|
219
|
-
"""The three PR-body shape names (`trivial`, `standard`, `heavy`) are used
|
|
220
|
-
by both `_compute_pr_body_shape` (return values) and `validate_pr_body`
|
|
221
|
-
(string comparisons). Bugbot flagged the inline literals as cross-function
|
|
222
|
-
magic strings. Pin the canonical names in `hooks_constants/` so a typo in
|
|
223
|
-
either site cannot silently misclassify shape."""
|
|
224
|
-
assert constants_module.TRIVIAL_SHAPE == "trivial"
|
|
225
|
-
assert constants_module.STANDARD_SHAPE == "standard"
|
|
226
|
-
assert constants_module.HEAVY_SHAPE == "heavy"
|
|
227
|
-
for each_name in ("TRIVIAL_SHAPE", "STANDARD_SHAPE", "HEAVY_SHAPE"):
|
|
228
|
-
assert each_name in constants_module.__all__
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
def test_readability_cli_flag_tokens_exposes_four_flags() -> None:
|
|
232
|
-
"""ALL_READABILITY_CLI_FLAG_TOKENS centralises the four CLI flags the
|
|
233
|
-
dispatcher recognises (loosen/reset/disable/enable). Pinning the set keeps
|
|
234
|
-
main()'s dispatcher loop and the dispatcher itself in sync; adding a flag
|
|
235
|
-
requires updating both the constant and the dispatcher in the same commit."""
|
|
236
|
-
expected_tokens = frozenset(
|
|
237
|
-
{
|
|
238
|
-
"--readability-loosen",
|
|
239
|
-
"--readability-reset",
|
|
240
|
-
"--readability-disable",
|
|
241
|
-
"--readability-enable",
|
|
242
|
-
}
|
|
243
|
-
)
|
|
244
|
-
assert constants_module.ALL_READABILITY_CLI_FLAG_TOKENS == expected_tokens
|
|
245
|
-
assert "ALL_READABILITY_CLI_FLAG_TOKENS" in constants_module.__all__
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
def test_ceremony_header_pattern_is_removed() -> None:
|
|
249
|
-
"""`CEREMONY_HEADER_PATTERN` is replaced by the broader `HEADING_LINE_PATTERN`
|
|
250
|
-
check in the Trivial-ceremony violation; the constant must not linger as a
|
|
251
|
-
dead export to drift back into use."""
|
|
252
|
-
assert not hasattr(constants_module, "CEREMONY_HEADER_PATTERN"), (
|
|
253
|
-
"CEREMONY_HEADER_PATTERN must be deleted; the ceremony-on-Trivial check "
|
|
254
|
-
"now uses HEADING_LINE_PATTERN to cover every heading level."
|
|
255
|
-
)
|
|
256
|
-
assert "CEREMONY_HEADER_PATTERN" not in constants_module.__all__
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
def test_flesch_formula_coefficients_are_named_constants() -> None:
|
|
260
|
-
"""The Flesch Reading Ease formula coefficients (206.835, 1.015, 84.6) and
|
|
261
|
-
the perfect-score default (100.0) must live as named UPPER_SNAKE constants
|
|
262
|
-
in `hooks_constants/pr_description_enforcer_constants.py` so the production
|
|
263
|
-
function body has zero magic numeric literals."""
|
|
264
|
-
assert constants_module.FLESCH_BASE_SCORE == 206.835
|
|
265
|
-
assert constants_module.FLESCH_WORDS_PER_SENTENCE_COEFFICIENT == 1.015
|
|
266
|
-
assert constants_module.FLESCH_SYLLABLES_PER_WORD_COEFFICIENT == 84.6
|
|
267
|
-
assert constants_module.FLESCH_PERFECT_SCORE == 100.0
|
|
268
|
-
for each_name in (
|
|
269
|
-
"FLESCH_BASE_SCORE",
|
|
270
|
-
"FLESCH_WORDS_PER_SENTENCE_COEFFICIENT",
|
|
271
|
-
"FLESCH_SYLLABLES_PER_WORD_COEFFICIENT",
|
|
272
|
-
"FLESCH_PERFECT_SCORE",
|
|
273
|
-
):
|
|
274
|
-
assert each_name in constants_module.__all__, (
|
|
275
|
-
f"{each_name} must appear in __all__ so the enforcer can import it."
|
|
276
|
-
)
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
def test_all_heavy_testing_headers_enumerates_five_canonical_forms() -> None:
|
|
280
|
-
"""The frozenset ALL_HEAVY_TESTING_HEADERS drives the violation message that
|
|
281
|
-
tells the writer which headers satisfy the heavy-shape testing-category
|
|
282
|
-
requirement. The set must include all five canonical forms (Test plan,
|
|
283
|
-
Testing, Tests, Verification, Validation) so the writer's documented
|
|
284
|
-
vocabulary matches the message it receives on a violation."""
|
|
285
|
-
expected_canonical_headers = [
|
|
286
|
-
"## Test plan",
|
|
287
|
-
"## Testing",
|
|
288
|
-
"## Tests",
|
|
289
|
-
"## Validation",
|
|
290
|
-
"## Verification",
|
|
291
|
-
]
|
|
292
|
-
assert sorted(constants_module.ALL_HEAVY_TESTING_HEADERS) == expected_canonical_headers
|