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,166 +0,0 @@
|
|
|
1
|
-
"""Behavioral tests for the code-review enforcement constants and comparator.
|
|
2
|
-
|
|
3
|
-
These exercise ``effort_meets_threshold`` against the ordered effort tokens and
|
|
4
|
-
assert the push and pull-request thresholds carry the push-based names the gate
|
|
5
|
-
family reads, so a rename that reintroduces commit terminology fails loudly.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import importlib.util
|
|
9
|
-
import pathlib
|
|
10
|
-
import re
|
|
11
|
-
|
|
12
|
-
import pytest
|
|
13
|
-
|
|
14
|
-
_CONFIG_DIR = pathlib.Path(__file__).parent
|
|
15
|
-
|
|
16
|
-
SAMPLE_ROOT_KEY_HEX_LENGTH = 16
|
|
17
|
-
|
|
18
|
-
_constants_spec = importlib.util.spec_from_file_location(
|
|
19
|
-
"code_review_enforcement_constants",
|
|
20
|
-
_CONFIG_DIR / "code_review_enforcement_constants.py",
|
|
21
|
-
)
|
|
22
|
-
assert _constants_spec is not None
|
|
23
|
-
assert _constants_spec.loader is not None
|
|
24
|
-
_constants_module = importlib.util.module_from_spec(_constants_spec)
|
|
25
|
-
_constants_spec.loader.exec_module(_constants_module)
|
|
26
|
-
|
|
27
|
-
effort_meets_threshold = _constants_module.effort_meets_threshold
|
|
28
|
-
CODE_REVIEW_ENFORCEMENT_ENV_VAR = _constants_module.CODE_REVIEW_ENFORCEMENT_ENV_VAR
|
|
29
|
-
code_review_enforcement_enabled_in_environment = (
|
|
30
|
-
_constants_module.code_review_enforcement_enabled_in_environment
|
|
31
|
-
)
|
|
32
|
-
PUSH_REQUIRED_EFFORT = _constants_module.PUSH_REQUIRED_EFFORT
|
|
33
|
-
PR_CREATE_REQUIRED_EFFORT = _constants_module.PR_CREATE_REQUIRED_EFFORT
|
|
34
|
-
GATED_PUSH_SUBCOMMANDS = _constants_module.GATED_PUSH_SUBCOMMANDS
|
|
35
|
-
ALL_EFFORT_TOKENS_IN_ASCENDING_ORDER = _constants_module.ALL_EFFORT_TOKENS_IN_ASCENDING_ORDER
|
|
36
|
-
PUSH_GATE_CORRECTIVE_MESSAGE = _constants_module.PUSH_GATE_CORRECTIVE_MESSAGE
|
|
37
|
-
SANCTIONED_STAMP_MINTER_FLAG = _constants_module.SANCTIONED_STAMP_MINTER_FLAG
|
|
38
|
-
STAMP_DIRECTORY_GUARD_MESSAGE = _constants_module.STAMP_DIRECTORY_GUARD_MESSAGE
|
|
39
|
-
STAMP_DIRECTORY_NAME = _constants_module.STAMP_DIRECTORY_NAME
|
|
40
|
-
GH_PR_CREATE_INVOCATION_PATTERN = _constants_module.GH_PR_CREATE_INVOCATION_PATTERN
|
|
41
|
-
STAMP_FILE_REFERENCE_BOUNDARY_PREFIX_PATTERN = (
|
|
42
|
-
_constants_module.STAMP_FILE_REFERENCE_BOUNDARY_PREFIX_PATTERN
|
|
43
|
-
)
|
|
44
|
-
STAMP_FILE_ROOT_KEY_JSON_SUFFIX_PATTERN = _constants_module.STAMP_FILE_ROOT_KEY_JSON_SUFFIX_PATTERN
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def test_gh_pr_create_pattern_matches_create_but_not_edit() -> None:
|
|
48
|
-
invocation_pattern = re.compile(GH_PR_CREATE_INVOCATION_PATTERN, re.IGNORECASE)
|
|
49
|
-
assert invocation_pattern.search("gh pr create --title T --body-file b.md") is not None
|
|
50
|
-
assert invocation_pattern.search("gh pr edit 1 --title T") is None
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def test_stamp_file_pattern_fragments_match_a_stamp_file_reference() -> None:
|
|
54
|
-
stamp_file_pattern = re.compile(
|
|
55
|
-
STAMP_FILE_REFERENCE_BOUNDARY_PREFIX_PATTERN
|
|
56
|
-
+ re.escape(STAMP_DIRECTORY_NAME)
|
|
57
|
-
+ STAMP_FILE_ROOT_KEY_JSON_SUFFIX_PATTERN % SAMPLE_ROOT_KEY_HEX_LENGTH,
|
|
58
|
-
re.IGNORECASE,
|
|
59
|
-
)
|
|
60
|
-
stamp_file_reference = f"cat {STAMP_DIRECTORY_NAME}/{'a' * SAMPLE_ROOT_KEY_HEX_LENGTH}.json"
|
|
61
|
-
assert stamp_file_pattern.search(stamp_file_reference) is not None
|
|
62
|
-
assert stamp_file_pattern.search("cat notes.json") is None
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def test_higher_effort_meets_a_lower_threshold() -> None:
|
|
66
|
-
assert effort_meets_threshold("xhigh", "low") is True
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def test_lower_effort_fails_a_higher_threshold() -> None:
|
|
70
|
-
assert effort_meets_threshold("low", "xhigh") is False
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def test_equal_effort_meets_the_threshold() -> None:
|
|
74
|
-
assert effort_meets_threshold("low", "low") is True
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def test_ultra_is_unranked_and_meets_nothing() -> None:
|
|
78
|
-
assert effort_meets_threshold("ultra", "low") is False
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def test_unknown_required_effort_meets_nothing() -> None:
|
|
82
|
-
assert effort_meets_threshold("low", "ultra") is False
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def test_push_requires_the_lowest_effort_token() -> None:
|
|
86
|
-
every_token_meets_push = all(
|
|
87
|
-
effort_meets_threshold(each_token, PUSH_REQUIRED_EFFORT)
|
|
88
|
-
for each_token in ALL_EFFORT_TOKENS_IN_ASCENDING_ORDER
|
|
89
|
-
)
|
|
90
|
-
assert every_token_meets_push
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def test_pr_create_threshold_admits_xhigh_but_rejects_high() -> None:
|
|
94
|
-
assert effort_meets_threshold("xhigh", PR_CREATE_REQUIRED_EFFORT) is True
|
|
95
|
-
assert effort_meets_threshold("high", PR_CREATE_REQUIRED_EFFORT) is False
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
def test_gated_push_subcommands_gates_push_not_commit() -> None:
|
|
99
|
-
assert "push" in GATED_PUSH_SUBCOMMANDS
|
|
100
|
-
assert "commit" not in GATED_PUSH_SUBCOMMANDS
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def test_ultra_absent_from_the_ordered_tokens() -> None:
|
|
104
|
-
assert "ultra" not in ALL_EFFORT_TOKENS_IN_ASCENDING_ORDER
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def test_push_gate_message_names_the_push_action_and_low_effort() -> None:
|
|
108
|
-
assert "git push" in PUSH_GATE_CORRECTIVE_MESSAGE
|
|
109
|
-
assert "CODE_REVIEW_PUSH_GATE" in PUSH_GATE_CORRECTIVE_MESSAGE
|
|
110
|
-
assert "'low'" in PUSH_GATE_CORRECTIVE_MESSAGE
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
def test_guard_message_directs_users_to_the_sanctioned_minter_flag() -> None:
|
|
114
|
-
assert SANCTIONED_STAMP_MINTER_FLAG in STAMP_DIRECTORY_GUARD_MESSAGE
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
def test_enforcement_defaults_to_off(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
118
|
-
monkeypatch.delenv(CODE_REVIEW_ENFORCEMENT_ENV_VAR, raising=False)
|
|
119
|
-
assert code_review_enforcement_enabled_in_environment() is False
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
@pytest.mark.parametrize("enabling_value", ["1", "true", "TRUE", " yes ", "on"])
|
|
123
|
-
def test_enforcement_turns_on_for_each_enabling_environment_value(
|
|
124
|
-
monkeypatch: pytest.MonkeyPatch, enabling_value: str
|
|
125
|
-
) -> None:
|
|
126
|
-
monkeypatch.setenv(CODE_REVIEW_ENFORCEMENT_ENV_VAR, enabling_value)
|
|
127
|
-
assert code_review_enforcement_enabled_in_environment() is True
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
@pytest.mark.parametrize("non_enabling_value", ["0", "false", "off", "", "maybe"])
|
|
131
|
-
def test_enforcement_stays_off_for_a_non_enabling_environment_value(
|
|
132
|
-
monkeypatch: pytest.MonkeyPatch, non_enabling_value: str
|
|
133
|
-
) -> None:
|
|
134
|
-
monkeypatch.setenv(CODE_REVIEW_ENFORCEMENT_ENV_VAR, non_enabling_value)
|
|
135
|
-
assert code_review_enforcement_enabled_in_environment() is False
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
def _module_flag_after_a_fresh_import(
|
|
139
|
-
monkeypatch: pytest.MonkeyPatch, environment_value: str | None
|
|
140
|
-
) -> bool:
|
|
141
|
-
if environment_value is None:
|
|
142
|
-
monkeypatch.delenv(CODE_REVIEW_ENFORCEMENT_ENV_VAR, raising=False)
|
|
143
|
-
else:
|
|
144
|
-
monkeypatch.setenv(CODE_REVIEW_ENFORCEMENT_ENV_VAR, environment_value)
|
|
145
|
-
fresh_spec = importlib.util.spec_from_file_location(
|
|
146
|
-
"code_review_enforcement_constants_fresh_import",
|
|
147
|
-
_CONFIG_DIR / "code_review_enforcement_constants.py",
|
|
148
|
-
)
|
|
149
|
-
assert fresh_spec is not None
|
|
150
|
-
assert fresh_spec.loader is not None
|
|
151
|
-
fresh_module = importlib.util.module_from_spec(fresh_spec)
|
|
152
|
-
fresh_spec.loader.exec_module(fresh_module)
|
|
153
|
-
flag_value: bool = fresh_module.CODE_REVIEW_ENFORCEMENT_ENABLED
|
|
154
|
-
return flag_value
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
def test_module_flag_turns_on_when_the_environment_asks_for_enforcement(
|
|
158
|
-
monkeypatch: pytest.MonkeyPatch,
|
|
159
|
-
) -> None:
|
|
160
|
-
assert _module_flag_after_a_fresh_import(monkeypatch, "true") is True
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
def test_module_flag_stays_off_when_the_environment_is_unset(
|
|
164
|
-
monkeypatch: pytest.MonkeyPatch,
|
|
165
|
-
) -> None:
|
|
166
|
-
assert _module_flag_after_a_fresh_import(monkeypatch, None) is False
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
"""Constants for the verified-commit gate hook family.
|
|
2
|
-
|
|
3
|
-
Shared by ``verification_verdict_store.py``, ``verified_commit_gate.py``,
|
|
4
|
-
and ``verifier_verdict_minter.py`` so every tunable lives in one place.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
GIT_TIMEOUT_SECONDS = 30
|
|
10
|
-
ROOT_KEY_HEX_LENGTH = 16
|
|
11
|
-
VERDICT_JSON_INDENT = 2
|
|
12
|
-
CLAUDE_HOME_DIRECTORY_NAME = ".claude"
|
|
13
|
-
VERDICT_DIRECTORY_NAME = "verification"
|
|
14
|
-
VERDICT_DIRECTORY_NAME_SEPARATOR_PATTERN = r"['\"\\/,\s]+"
|
|
15
|
-
VERDICT_DIRECTORY_PATH_BOUNDARY_PATTERN = r"(?=['\"]*[\\/,])"
|
|
16
|
-
RELATIVE_VERDICT_DIRECTORY_PATTERN = r"(?:^|(?<=[\s;&|(='\"]))verification[\\/]"
|
|
17
|
-
VERDICT_PATH_GLUE_PATTERN = r"['\"+\\/\s]*[\\/]['\"+\\/\s]*"
|
|
18
|
-
VERDICT_DIRECTORY_CHANGE_TARGET_PATTERN = r"[ \t]+['\"]?verification[\\/]?['\"]?(?=[\s;&|]|$)"
|
|
19
|
-
VERDICT_PATH_JOINED_VARIABLE_PATTERN = r"\$\{?(\w+)\}?[\\/]|[\\/]\$\{?(\w+)\}?"
|
|
20
|
-
VERDICT_PATH_VARIABLE_ASSIGNMENT_PATTERN = r"(?:^|(?<=[\s;&|(]))%s=(\S+)"
|
|
21
|
-
VERDICT_FILE_RELATIVE_REFERENCE_PATTERN = (
|
|
22
|
-
rf"(?:^|(?<=[\s;&|(='\"\\/]))verification[\\/][0-9a-f]{{{ROOT_KEY_HEX_LENGTH}}}\.json"
|
|
23
|
-
)
|
|
24
|
-
PATH_OBFUSCATION_PRIMITIVE_PATTERN = (
|
|
25
|
-
r"chr\s*\(|bytes\.fromhex\s*\(|b64decode\s*\(|codecs\.decode\s*\("
|
|
26
|
-
r"|(?:bytes|bytearray)\s*\(\s*\[|\[char\[?\]?\]"
|
|
27
|
-
)
|
|
28
|
-
ALL_VERDICT_PATH_SEGMENT_NAMES = (".claude", "verification")
|
|
29
|
-
ALL_VERDICT_PATH_SEGMENT_BODIES = ("claude", "verification")
|
|
30
|
-
HEX_TOKEN_PATTERN = r"(?<![0-9a-fx])([0-9a-f]{6,})(?![0-9a-f])"
|
|
31
|
-
BASE64_TOKEN_PATTERN = r"[A-Za-z0-9+/]{8,}={0,2}"
|
|
32
|
-
CHARACTER_CODE_SEQUENCE_PATTERN = r"\d{1,3}(?:\s*,\s*\d{1,3})+"
|
|
33
|
-
CHR_CALL_CHAIN_PATTERN = r"chr\(\s*\d{1,3}\s*\)(?:\s*\+\s*chr\(\s*\d{1,3}\s*\))+"
|
|
34
|
-
CHR_CALL_CODE_PATTERN = r"chr\(\s*(\d{1,3})\s*\)"
|
|
35
|
-
HEX_DIGITS_PER_BYTE = 2
|
|
36
|
-
FILE_WRITE_PRIMITIVE_PATTERN = (
|
|
37
|
-
r"\bopen\s*\(|\.write_text\s*\(|\.write_bytes\s*\("
|
|
38
|
-
r"|Out-File|Set-Content|Add-Content|\btee\b|>"
|
|
39
|
-
)
|
|
40
|
-
NON_REDIRECT_FILE_WRITE_PRIMITIVE_PATTERN = (
|
|
41
|
-
r"\bopen\s*\(|\.write_text\s*\(|\.write_bytes\s*\("
|
|
42
|
-
r"|Out-File|Set-Content|Add-Content|\btee\b"
|
|
43
|
-
)
|
|
44
|
-
WRITE_CALL_REGION_PATTERN = (
|
|
45
|
-
r"(?:\bopen\s*\(|\.write_text\s*\(|\.write_bytes\s*\("
|
|
46
|
-
r"|Out-File|Set-Content|Add-Content|\btee\b)[^;&|\n]*"
|
|
47
|
-
)
|
|
48
|
-
VERDICT_KEY_ALL_PASS = "all_pass"
|
|
49
|
-
VERDICT_KEY_MANIFEST_SHA256 = "manifest_sha256"
|
|
50
|
-
VERDICT_KEY_FINDINGS = "findings"
|
|
51
|
-
VERDICT_FINDING_CHECK_KEY = "check"
|
|
52
|
-
LOGS_DIRECTORY_NAME = "logs"
|
|
53
|
-
VERIFIER_VERDICTS_JSONL_FILENAME = "verifier-verdicts.jsonl"
|
|
54
|
-
LEDGER_KEY_TIMESTAMP = "timestamp"
|
|
55
|
-
LEDGER_KEY_REPO_ROOT = "repo_root"
|
|
56
|
-
LEDGER_KEY_BRANCH = "branch"
|
|
57
|
-
LEDGER_KEY_MANIFEST_HASH = "manifest_hash"
|
|
58
|
-
LEDGER_KEY_ALL_PASS = "all_pass"
|
|
59
|
-
LEDGER_KEY_FINDING_COUNT = "finding_count"
|
|
60
|
-
LEDGER_KEY_FINDING_CHECK_NAMES = "finding_check_names"
|
|
61
|
-
LEDGER_KEY_MINTED_FROM_AGENT_ID = "minted_from_agent_id"
|
|
62
|
-
VERDICT_FILE_GLOB = "*.json"
|
|
63
|
-
SUBAGENTS_DIRECTORY_NAME = "subagents"
|
|
64
|
-
AGENT_TRANSCRIPT_GLOB = "agent-*.jsonl"
|
|
65
|
-
AGENT_META_SIDECAR_SUFFIX = ".meta.json"
|
|
66
|
-
AGENT_META_TYPE_KEY = "agentType"
|
|
67
|
-
TRANSCRIPT_ENTRY_TYPE_KEY = "type"
|
|
68
|
-
TRANSCRIPT_ASSISTANT_ENTRY_TYPE = "assistant"
|
|
69
|
-
TRANSCRIPT_MESSAGE_KEY = "message"
|
|
70
|
-
TRANSCRIPT_CONTENT_KEY = "content"
|
|
71
|
-
TRANSCRIPT_CONTENT_TYPE_KEY = "type"
|
|
72
|
-
TRANSCRIPT_TEXT_CONTENT_TYPE = "text"
|
|
73
|
-
TRANSCRIPT_TEXT_KEY = "text"
|
|
74
|
-
VERDICT_FENCE_PATTERN = r"```verdict\s*\n(.*?)```"
|
|
75
|
-
MANIFEST_HASH_CLI_FLAG = "--manifest-hash"
|
|
76
|
-
MANIFEST_HASH_FOR_BRANCH_CLI_FLAG = "--manifest-hash-for-branch"
|
|
77
|
-
WORKTREE_LIST_PATH_PREFIX = "worktree "
|
|
78
|
-
WORKTREE_LIST_BRANCH_PREFIX = "branch "
|
|
79
|
-
BRANCH_REFERENCE_PREFIX = "refs/heads/"
|
|
80
|
-
EMPTY_SURFACE_GUARD_MESSAGE = (
|
|
81
|
-
"ERROR: The work tree at {repo_root} has no changed or untracked files "
|
|
82
|
-
"versus origin/main (empty change surface). This work tree holds nothing "
|
|
83
|
-
"to verify — you are pointed at the wrong work tree. Run `git worktree list` "
|
|
84
|
-
"to see all checked-out work trees and target the one on the branch under review."
|
|
85
|
-
)
|
|
86
|
-
BRANCH_WORKTREE_ABSENT_MESSAGE = (
|
|
87
|
-
"ERROR: No work tree has branch '{branch}' checked out. "
|
|
88
|
-
"Check it out in a work tree first: "
|
|
89
|
-
"`git worktree add <path> <branch>` or `git checkout <branch>`."
|
|
90
|
-
)
|
|
91
|
-
DOCS_ONLY_EXTENSIONS = frozenset(
|
|
92
|
-
{".md", ".txt", ".rst", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp", ".ico"}
|
|
93
|
-
)
|
|
94
|
-
PYTHON_EXTENSION = ".py"
|
|
95
|
-
TEST_FILE_PREFIX = "test_"
|
|
96
|
-
TEST_FILE_SUFFIX = "_test.py"
|
|
97
|
-
CONFTEST_FILE_NAME = "conftest.py"
|
|
98
|
-
MINIMUM_STATUS_FIELD_COUNT = 2
|
|
99
|
-
ALL_FALLBACK_BASE_REFERENCES = ("origin/main", "origin/master")
|
|
100
|
-
DETACHED_HEAD_LABEL = "HEAD"
|
|
101
|
-
BRANCH_REMOTE_CONFIG_KEY_TEMPLATE = "branch.{branch_name}.remote"
|
|
102
|
-
ALL_TOOLING_STATE_PREFIXES = (
|
|
103
|
-
".claude/verification/",
|
|
104
|
-
".claude/worktrees/",
|
|
105
|
-
".claude/daemon/",
|
|
106
|
-
".claude/teams/",
|
|
107
|
-
".claude/sessions/",
|
|
108
|
-
".cursor/worktrees/",
|
|
109
|
-
".claude-plugin-data/",
|
|
110
|
-
)
|
|
111
|
-
GATED_GIT_SUBCOMMANDS = frozenset({"commit", "push"})
|
|
112
|
-
ALL_GIT_BINARY_NAMES = frozenset({"git", "git.exe"})
|
|
113
|
-
VALUE_TAKING_GIT_OPTIONS = frozenset({"-C", "-c", "--git-dir", "--work-tree", "--namespace"})
|
|
114
|
-
REPO_DIRECTORY_OPTION = "-C"
|
|
115
|
-
WORK_TREE_OPTION = "--work-tree"
|
|
116
|
-
DIRECTORY_CHANGE_VERBS = frozenset({"cd", "pushd", "set-location", "sl"})
|
|
117
|
-
DIRECTORY_CHANGE_PATH_OPTIONS = frozenset({"-path", "-literalpath"})
|
|
118
|
-
DIRECTORY_CHANGE_OPTION_TERMINATOR = "--"
|
|
119
|
-
DIRECTORY_CHANGE_PATTERN_PREFIX = r"(?:^|(?<=[\s;&|(]))(?:"
|
|
120
|
-
DIRECTORY_CHANGE_PATTERN_SUFFIX = r")(?=\s|$)"
|
|
121
|
-
DIRECTORY_CHANGE_OPTION_PREFIX_PATTERN = r"(?:[ \t]+(?:%s)(?=\s|$))*"
|
|
122
|
-
DIRECTORY_CHANGE_TARGET_PATTERN = r"[ \t]+['\"]?\S*"
|
|
123
|
-
CLAUDE_HOME_TARGET_BOUNDARY_PATTERN = r"[\\/]?['\"]?(?=[\s;&|]|$)"
|
|
124
|
-
VERDICT_DIRECTORY_TARGET_BOUNDARY_PATTERN = r"[\\/]?['\"]?(?=[\s;&|]|$)"
|
|
125
|
-
COMMAND_AFTER_DIRECTORY_CHANGE_PATTERN = r"[;&|\n][\s]*\S"
|
|
126
|
-
OPTION_WITH_VALUE_STEP = 2
|
|
127
|
-
ALL_GATED_TOOL_NAMES = ("Bash", "PowerShell")
|
|
128
|
-
HASH_PREVIEW_LENGTH = 16
|
|
129
|
-
VERIFICATION_BYPASS_MARKER = "# verify-skip"
|
|
130
|
-
MINTING_AGENT_TYPE = "code-verifier"
|
|
131
|
-
VERDICT_DIRECTORY_GUARD_MESSAGE = (
|
|
132
|
-
"BLOCKED: [VERDICT_DIRECTORY_GUARD] Shell access to the verification "
|
|
133
|
-
"verdict directory (~/.claude/verification/) is denied. Only the "
|
|
134
|
-
"verifier_verdict_minter.py SubagentStop hook writes verdict files; a "
|
|
135
|
-
"shell write here would forge a passing verdict and defeat the "
|
|
136
|
-
"verified-commit gate. Spawn the code-verifier agent to earn a verdict "
|
|
137
|
-
"instead of writing one."
|
|
138
|
-
)
|
|
139
|
-
CORRECTIVE_MESSAGE = (
|
|
140
|
-
"BLOCKED: [VERIFIED_COMMIT_GATE] This branch surface has no passing "
|
|
141
|
-
"verification verdict. Clear commit-committability gates first "
|
|
142
|
-
"(CODE_RULES on changed lines and merge conflicts vs base — the "
|
|
143
|
-
"code_verifier_spawn_preflight_gate enforces these on the spawn). If a "
|
|
144
|
-
"prior commit failed on CODE_RULES or staging, fix those before "
|
|
145
|
-
"re-verifying. Then spawn the code-verifier agent (Agent or Task tool, "
|
|
146
|
-
"subagent_type 'code-verifier') with the task texts, the diff scope, "
|
|
147
|
-
"and recorded baselines; when it finishes with a clean verdict the "
|
|
148
|
-
"SubagentStop hook mints the verdict and this command will pass. Any "
|
|
149
|
-
"file change after verification invalidates the verdict, so verify "
|
|
150
|
-
"last only after commit gates are green. The verdict binds to the exact "
|
|
151
|
-
"surface content (every changed and untracked file's bytes), not to a "
|
|
152
|
-
"work-tree path, so a commit from a different work tree passes only "
|
|
153
|
-
"when its surface is byte-identical; a work tree carrying any extra or "
|
|
154
|
-
"later edit has a surface no verdict covers. To land this change, run "
|
|
155
|
-
"this command from the work tree that holds the verified surface, or "
|
|
156
|
-
"verify this surface here. Exempt automatically: docs/image files, "
|
|
157
|
-
"pytest test files, and "
|
|
158
|
-
"Python files whose docstring- and comment-stripped AST is unchanged "
|
|
159
|
-
"(comment-only edits in non-Python files are not exempt)."
|
|
160
|
-
)
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
"""The additionalContext text the verified-commit gate attaches to a deny.
|
|
2
|
-
|
|
3
|
-
The gate injects this next to the blocked tool result so the agent learns,
|
|
4
|
-
at the moment of the block, when the '# verify-skip' marker is legitimate
|
|
5
|
-
and when a fresh verification is required instead.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
VERIFY_SKIP_ADDITIONAL_CONTEXT = (
|
|
9
|
-
"The verified-commit gate honors a one-command escape hatch: appending the "
|
|
10
|
-
"marker '# verify-skip' as a trailing shell comment (outside every quoted "
|
|
11
|
-
"region) to the blocked command bypasses the gate for that command only. "
|
|
12
|
-
"It is allowed only when the branch surface is the "
|
|
13
|
-
"same code a code-verifier already passed clean and the gate is "
|
|
14
|
-
"blocking on a verdict that does not cover it (an unminted verdict, "
|
|
15
|
-
"staging churn, or a reverted concurrent write) — confirm the verified "
|
|
16
|
-
"suite still passes and the diff holds nothing beyond the clean verdict "
|
|
17
|
-
"before using it. Any real code change since that clean verdict, a "
|
|
18
|
-
"first verification, or unrepaired findings all require a fresh "
|
|
19
|
-
"verification by the code-verifier agent instead. Full rule: "
|
|
20
|
-
"~/.claude/rules/verified-commit-gate-skip.md."
|
|
21
|
-
)
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
"""Output-shape constants for the verified-commit gate's deny payload.
|
|
2
|
-
|
|
3
|
-
Shared by ``verified_commit_gate.py`` and its ``verified_commit_gate_parts``
|
|
4
|
-
package so the PreToolUse event name, the deny decision string, the hook's
|
|
5
|
-
own module name for block logging, and the regex-alternation join separator
|
|
6
|
-
live in one place.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from __future__ import annotations
|
|
10
|
-
|
|
11
|
-
PRE_TOOL_USE_HOOK_EVENT_NAME = "PreToolUse"
|
|
12
|
-
DENY_PERMISSION_DECISION = "deny"
|
|
13
|
-
GATE_HOOK_MODULE_NAME = "verified_commit_gate.py"
|
|
14
|
-
REGEX_ALTERNATION_SEPARATOR = "|"
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
"""Pytest fixture that reproduces foreign-``config`` shadowing for the gate family.
|
|
2
|
-
|
|
3
|
-
The verified-commit gate hooks import shared constants as
|
|
4
|
-
``from config.verified_commit_constants import ...``. This fixture mirrors the
|
|
5
|
-
installed layout that breaks that import -- a real ``hooks/blocking`` package
|
|
6
|
-
beside a decoy ``hooks/config`` regular package -- and runs a caller-supplied
|
|
7
|
-
driver as a subprocess whose ``sys.path`` places the decoy ahead of
|
|
8
|
-
``blocking``, the ordering under which the wrong ``config`` wins resolution.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
import shutil
|
|
12
|
-
import subprocess
|
|
13
|
-
import sys
|
|
14
|
-
import textwrap
|
|
15
|
-
from collections.abc import Callable
|
|
16
|
-
from pathlib import Path
|
|
17
|
-
|
|
18
|
-
import pytest
|
|
19
|
-
|
|
20
|
-
_BLOCKING_SOURCE_DIRECTORY = Path(__file__).resolve().parent
|
|
21
|
-
_HOOKS_CONSTANTS_SOURCE_DIRECTORY = _BLOCKING_SOURCE_DIRECTORY.parent / "hooks_constants"
|
|
22
|
-
_SUBPROCESS_TIMEOUT_SECONDS = 60
|
|
23
|
-
_MIRRORED_BLOCKING_FILE_NAMES = (
|
|
24
|
-
"verified_commit_gate.py",
|
|
25
|
-
"verification_verdict_store.py",
|
|
26
|
-
"verifier_verdict_minter.py",
|
|
27
|
-
"verdict_directory_write_blocker.py",
|
|
28
|
-
"verified_commit_config_bootstrap.py",
|
|
29
|
-
"code_review_enforcement_config_bootstrap.py",
|
|
30
|
-
"code_review_stamp_store.py",
|
|
31
|
-
)
|
|
32
|
-
_DECOY_CONFIG_INIT_SOURCE = '"""Foreign config package that must never win resolution."""\n'
|
|
33
|
-
_DECOY_CONFIG_CONSTANTS_SOURCE = (
|
|
34
|
-
'"""Stale stand-in carrying none of the real gate constants."""\n\nIS_DECOY_CONFIG = True\n'
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def _copy_mirrored_packages(mirrored_hooks_directory: Path, mirrored_blocking_directory: Path) -> None:
|
|
39
|
-
"""Copy the ``config``, gate-parts, and ``hooks_constants`` packages into the mirror."""
|
|
40
|
-
shutil.copytree(_BLOCKING_SOURCE_DIRECTORY / "config", mirrored_blocking_directory / "config")
|
|
41
|
-
shutil.copytree(
|
|
42
|
-
_BLOCKING_SOURCE_DIRECTORY / "verified_commit_gate_parts",
|
|
43
|
-
mirrored_blocking_directory / "verified_commit_gate_parts",
|
|
44
|
-
ignore=shutil.ignore_patterns("tests", "__pycache__"),
|
|
45
|
-
)
|
|
46
|
-
shutil.copytree(_HOOKS_CONSTANTS_SOURCE_DIRECTORY, mirrored_hooks_directory / "hooks_constants")
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def _write_decoy_config_package(mirrored_hooks_directory: Path) -> None:
|
|
50
|
-
"""Write the decoy ``config`` package that must never win resolution."""
|
|
51
|
-
decoy_config_directory = mirrored_hooks_directory / "config"
|
|
52
|
-
decoy_config_directory.mkdir()
|
|
53
|
-
(decoy_config_directory / "__init__.py").write_text(_DECOY_CONFIG_INIT_SOURCE, encoding="utf-8")
|
|
54
|
-
(decoy_config_directory / "verified_commit_constants.py").write_text(
|
|
55
|
-
_DECOY_CONFIG_CONSTANTS_SOURCE, encoding="utf-8"
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def _build_shadowed_hook_tree(tmp_path: Path) -> tuple[Path, Path]:
|
|
60
|
-
"""Mirror the hook tree with a decoy ``config`` package beside ``blocking``.
|
|
61
|
-
|
|
62
|
-
Args:
|
|
63
|
-
tmp_path: The directory the mirrored tree is built under.
|
|
64
|
-
|
|
65
|
-
Returns:
|
|
66
|
-
The mirrored ``hooks`` directory and its ``blocking`` subdirectory.
|
|
67
|
-
"""
|
|
68
|
-
mirrored_hooks_directory = tmp_path / "hooks"
|
|
69
|
-
mirrored_blocking_directory = mirrored_hooks_directory / "blocking"
|
|
70
|
-
mirrored_blocking_directory.mkdir(parents=True)
|
|
71
|
-
|
|
72
|
-
for each_file_name in _MIRRORED_BLOCKING_FILE_NAMES:
|
|
73
|
-
source_file = _BLOCKING_SOURCE_DIRECTORY / each_file_name
|
|
74
|
-
if source_file.exists():
|
|
75
|
-
shutil.copy2(source_file, mirrored_blocking_directory / each_file_name)
|
|
76
|
-
|
|
77
|
-
_copy_mirrored_packages(mirrored_hooks_directory, mirrored_blocking_directory)
|
|
78
|
-
_write_decoy_config_package(mirrored_hooks_directory)
|
|
79
|
-
return mirrored_hooks_directory, mirrored_blocking_directory
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def _probe_command(mirrored_hooks_directory: Path, mirrored_blocking_directory: Path) -> str:
|
|
83
|
-
"""Build the ``sys.path`` preamble that shadows ``blocking`` with the decoy config."""
|
|
84
|
-
return textwrap.dedent(
|
|
85
|
-
f"""\
|
|
86
|
-
import sys
|
|
87
|
-
sys.path.insert(0, {str(mirrored_blocking_directory)!r})
|
|
88
|
-
sys.path.insert(0, {str(mirrored_hooks_directory)!r})
|
|
89
|
-
"""
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
@pytest.fixture
|
|
94
|
-
def run_under_config_shadow(
|
|
95
|
-
tmp_path: Path,
|
|
96
|
-
) -> Callable[[str], subprocess.CompletedProcess[str]]:
|
|
97
|
-
"""Return a runner that executes a driver under a foreign-``config`` sys.path.
|
|
98
|
-
|
|
99
|
-
``run_under_config_shadow("import verified_commit_gate")`` returns 0 once
|
|
100
|
-
the bootstrap seeds the real module, nonzero while the decoy config wins.
|
|
101
|
-
|
|
102
|
-
Args:
|
|
103
|
-
tmp_path: Pytest's per-test temporary directory, fixture-injected.
|
|
104
|
-
|
|
105
|
-
Returns:
|
|
106
|
-
A function taking driver source text and returning the finished
|
|
107
|
-
subprocess result.
|
|
108
|
-
"""
|
|
109
|
-
mirrored_hooks_directory, mirrored_blocking_directory = _build_shadowed_hook_tree(tmp_path)
|
|
110
|
-
sys_path_preamble = _probe_command(mirrored_hooks_directory, mirrored_blocking_directory)
|
|
111
|
-
|
|
112
|
-
def run_driver(driver_body: str) -> subprocess.CompletedProcess[str]:
|
|
113
|
-
probe_script = tmp_path / "probe.py"
|
|
114
|
-
probe_script.write_text(sys_path_preamble + textwrap.dedent(driver_body), encoding="utf-8")
|
|
115
|
-
return subprocess.run(
|
|
116
|
-
[sys.executable, str(probe_script)],
|
|
117
|
-
check=False,
|
|
118
|
-
capture_output=True,
|
|
119
|
-
text=True,
|
|
120
|
-
timeout=_SUBPROCESS_TIMEOUT_SECONDS,
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
return run_driver
|