claude-dev-env 1.38.0 → 1.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +10 -36
- package/_shared/pr-loop/audit-reply-template.md +147 -0
- package/_shared/pr-loop/fix-protocol.md +25 -4
- package/_shared/pr-loop/gh-payloads.md +37 -50
- package/_shared/pr-loop/scripts/code_rules_gate.py +0 -60
- package/_shared/pr-loop/scripts/config/post_audit_thread_constants.py +189 -0
- package/_shared/pr-loop/scripts/post_audit_thread.py +947 -0
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +0 -19
- package/_shared/pr-loop/scripts/tests/test_post_audit_thread.py +923 -0
- package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +127 -0
- package/_shared/pr-loop/state-schema.md +1 -1
- package/agents/clean-coder.md +2 -2
- package/bin/install.mjs +6 -7
- package/bin/install.test.mjs +8 -0
- package/commands/doc-gist.md +16 -0
- package/commands/plan.md +0 -2
- package/commands/review-plan.md +1 -1
- package/docs/CODE_RULES.md +122 -2
- package/hooks/blocking/bot_mention_comment_blocker.py +75 -0
- package/hooks/blocking/code_rules_enforcer.py +1236 -161
- package/hooks/blocking/convergence_gate_blocker.py +130 -0
- package/hooks/blocking/destructive_command_blocker.py +74 -0
- package/hooks/blocking/gh_body_arg_blocker.py +30 -0
- package/hooks/blocking/md_to_html_blocker.py +119 -0
- package/hooks/blocking/test_bot_mention_comment_blocker.py +131 -0
- package/hooks/blocking/test_code_rules_enforcer.py +21 -0
- package/hooks/blocking/test_code_rules_enforcer_any_exempt_files.py +70 -0
- package/hooks/blocking/test_code_rules_enforcer_any_imports_and_cast.py +92 -0
- package/hooks/blocking/test_code_rules_enforcer_banned_import_alias.py +143 -0
- package/hooks/blocking/test_code_rules_enforcer_banned_prefixes.py +152 -0
- package/hooks/blocking/test_code_rules_enforcer_bare_except.py +120 -0
- package/hooks/blocking/test_code_rules_enforcer_boundary_types.py +175 -0
- package/hooks/blocking/test_code_rules_enforcer_cap_meta.py +0 -1
- package/hooks/blocking/test_code_rules_enforcer_collection_prefix.py +50 -0
- package/hooks/blocking/test_code_rules_enforcer_docstring_format.py +255 -0
- package/hooks/blocking/test_code_rules_enforcer_inline_tuple_string_magic.py +130 -0
- package/hooks/blocking/test_code_rules_enforcer_stub_implementations.py +141 -0
- package/hooks/blocking/test_code_rules_enforcer_test_branching.py +143 -0
- package/hooks/blocking/test_code_rules_enforcer_thin_wrapper_files.py +169 -0
- package/hooks/blocking/test_code_rules_enforcer_todo_markers.py +99 -0
- package/hooks/blocking/test_code_rules_enforcer_typed_dict_pairs.py +141 -0
- package/hooks/blocking/test_code_rules_enforcer_unused_imports.py +158 -0
- package/hooks/blocking/test_convergence_gate_blocker.py +63 -0
- package/hooks/blocking/test_destructive_command_blocker.py +146 -0
- package/hooks/blocking/test_destructive_command_blocker_no_verify.py +102 -0
- package/hooks/blocking/test_gh_body_arg_blocker.py +45 -0
- package/hooks/blocking/test_md_to_html_blocker.py +317 -0
- package/hooks/config/any_type_config.py +7 -0
- package/hooks/config/banned_identifiers_constants.py +11 -0
- package/hooks/config/blocking_check_limits.py +38 -0
- package/hooks/config/bot_mention_comment_blocker_constants.py +20 -0
- package/hooks/config/code_rules_enforcer_constants.py +53 -0
- package/hooks/config/convergence_branch_constants.py +9 -0
- package/hooks/config/doc_gist_auto_publish_constants.py +18 -0
- package/hooks/config/html_companion_constants.py +20 -0
- package/hooks/config/inline_tuple_string_magic_constants.py +22 -0
- package/hooks/config/test_banned_identifiers_constants.py +17 -0
- package/hooks/hooks.json +28 -20
- package/hooks/pyproject.toml +69 -0
- package/hooks/validators/mypy_integration.py +47 -1
- package/hooks/validators/run_all_validators.py +3 -3
- package/hooks/validators/test_mypy_integration.py +50 -1
- package/hooks/workflow/doc_gist_auto_publish.py +144 -0
- package/hooks/workflow/md_to_html_companion.py +365 -0
- package/hooks/workflow/test_doc_gist_auto_publish.py +117 -0
- package/hooks/workflow/test_md_to_html_companion.py +452 -0
- package/package.json +1 -1
- package/rules/gh-body-file.md +2 -0
- package/scripts/Install-SweepEmptyDirs.ps1 +111 -0
- package/scripts/check.ps1 +106 -0
- package/scripts/config/timing.py +11 -0
- package/scripts/sweep_empty_dirs.py +138 -0
- package/scripts/sync_to_cursor/rules.py +1 -1
- package/scripts/test_sweep_empty_dirs.py +183 -0
- package/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml +323 -0
- package/skills/_shared/pr-loop/scripts/_cli_utils.py +22 -0
- package/skills/_shared/pr-loop/scripts/_path_resolver.py +165 -0
- package/skills/_shared/pr-loop/scripts/_xml_utils.py +20 -0
- package/skills/_shared/pr-loop/scripts/build_audit_prompt.py +182 -0
- package/skills/_shared/pr-loop/scripts/build_fix_prompt.py +185 -0
- package/skills/_shared/pr-loop/scripts/config/__init__.py +0 -0
- package/skills/_shared/pr-loop/scripts/config/path_resolver_constants.py +78 -0
- package/skills/_shared/pr-loop/scripts/init_loop_state.py +135 -0
- package/skills/_shared/pr-loop/scripts/teardown_worktrees.py +175 -0
- package/skills/_shared/pr-loop/scripts/write_audit_outcomes.py +182 -0
- package/skills/_shared/pr-loop/scripts/write_fix_outcomes.py +206 -0
- package/skills/bugteam/CONSTRAINTS.md +21 -22
- package/skills/bugteam/EXAMPLES.md +3 -3
- package/skills/bugteam/PROMPTS.md +227 -67
- package/skills/bugteam/SKILL.md +114 -455
- package/skills/bugteam/reference/README.md +1 -1
- package/skills/bugteam/reference/audit-and-teammates.md +112 -39
- package/skills/bugteam/reference/audit-contract.md +4 -22
- package/skills/bugteam/reference/copilot-gap-analysis.md +8 -5
- package/skills/bugteam/reference/design-rationale.md +2 -2
- package/skills/bugteam/reference/github-pr-reviews.md +50 -57
- package/skills/bugteam/reference/obstacles/audit-assign-ids.md +13 -0
- package/skills/bugteam/reference/obstacles/audit-capture-excerpts.md +13 -0
- package/skills/bugteam/reference/obstacles/audit-walk-categories.md +13 -0
- package/skills/bugteam/reference/obstacles/audit-write-xml.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-append-summary.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-apply-fixes.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-git-add-commit.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-git-push.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-post-reply.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-publish-summary.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-py-compile.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-read-files.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-resolve-thread.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-test-suite.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-violation-count.md +13 -0
- package/skills/bugteam/reference/obstacles/fix-write-xml.md +13 -0
- package/skills/bugteam/reference/team-setup.md +106 -9
- package/skills/bugteam/reference/teardown-publish-permissions.md +39 -8
- package/skills/bugteam/scripts/README.md +60 -0
- package/skills/bugteam/scripts/_claude_permissions_common.py +358 -0
- package/skills/bugteam/scripts/bugteam_code_rules_gate.py +976 -0
- package/skills/bugteam/scripts/bugteam_fix_hookspath.py +375 -0
- package/skills/bugteam/scripts/bugteam_preflight.py +294 -0
- package/skills/bugteam/scripts/config/bugteam_code_rules_gate_constants.py +25 -0
- package/skills/bugteam/scripts/config/bugteam_fix_hookspath_constants.py +26 -0
- package/skills/bugteam/scripts/config/bugteam_preflight_constants.py +35 -0
- package/skills/bugteam/scripts/config/claude_permissions_common_constants.py +20 -0
- package/skills/bugteam/scripts/config/probe_code_rules_enforcer_check_constants.py +12 -0
- package/skills/bugteam/scripts/config/windows_safe_rmtree_constants.py +7 -0
- package/skills/bugteam/scripts/grant_project_claude_permissions.py +175 -0
- package/skills/bugteam/scripts/probe_code_rules_enforcer_check.py +107 -0
- package/skills/bugteam/scripts/revoke_project_claude_permissions.py +220 -0
- package/skills/bugteam/scripts/test__claude_permissions_common.py +112 -0
- package/skills/bugteam/scripts/test_bugteam_code_rules_gate.py +400 -0
- package/skills/bugteam/scripts/test_bugteam_fix_hookspath.py +384 -0
- package/skills/bugteam/scripts/test_bugteam_preflight.py +268 -0
- package/skills/bugteam/scripts/test_claude_permissions_common.py +195 -0
- package/skills/bugteam/scripts/test_grant_project_claude_permissions.py +55 -0
- package/skills/bugteam/scripts/test_probe_code_rules_enforcer_check.py +76 -0
- package/skills/bugteam/scripts/test_revoke_project_claude_permissions.py +55 -0
- package/skills/bugteam/scripts/test_windows_safe_rmtree.py +108 -0
- package/skills/bugteam/scripts/windows_safe_rmtree.py +100 -0
- package/skills/bugteam/test_skill_additions.py +1 -11
- package/skills/code/SKILL.md +176 -0
- package/skills/doc-gist/SKILL.md +99 -0
- package/skills/doc-gist/references/examples/01-exploration-code-approaches.html +453 -0
- package/skills/doc-gist/references/examples/02-exploration-visual-designs.html +515 -0
- package/skills/doc-gist/references/examples/03-code-review-pr.html +638 -0
- package/skills/doc-gist/references/examples/04-code-understanding.html +491 -0
- package/skills/doc-gist/references/examples/05-design-system.html +629 -0
- package/skills/doc-gist/references/examples/06-component-variants.html +605 -0
- package/skills/doc-gist/references/examples/07-prototype-animation.html +455 -0
- package/skills/doc-gist/references/examples/08-prototype-interaction.html +396 -0
- package/skills/doc-gist/references/examples/09-slide-deck.html +592 -0
- package/skills/doc-gist/references/examples/10-svg-illustrations.html +492 -0
- package/skills/doc-gist/references/examples/11-status-report.html +528 -0
- package/skills/doc-gist/references/examples/12-incident-report.html +596 -0
- package/skills/doc-gist/references/examples/13-flowchart-diagram.html +395 -0
- package/skills/doc-gist/references/examples/14-research-feature-explainer.html +381 -0
- package/skills/doc-gist/references/examples/15-research-concept-explainer.html +368 -0
- package/skills/doc-gist/references/examples/16-implementation-plan.html +702 -0
- package/skills/doc-gist/references/examples/17-pr-writeup.html +595 -0
- package/skills/doc-gist/references/examples/18-editor-triage-board.html +573 -0
- package/skills/doc-gist/references/examples/19-editor-feature-flags.html +663 -0
- package/skills/doc-gist/references/examples/20-editor-prompt-tuner.html +722 -0
- package/skills/doc-gist/references/examples/README.md +5 -0
- package/skills/doc-gist/scripts/config/__init__.py +0 -0
- package/skills/doc-gist/scripts/config/gist_upload_constants.py +16 -0
- package/skills/doc-gist/scripts/gist_upload.py +177 -0
- package/skills/doc-gist/scripts/test_gist_upload.py +51 -0
- package/skills/findbugs/SKILL.md +68 -2
- package/skills/monitor-open-prs/SKILL.md +13 -32
- package/skills/monitor-open-prs/test_skill_contract.py +0 -11
- package/skills/pr-consistency-audit/SKILL.md +112 -0
- package/skills/pr-consistency-audit/reference/detection-rules.md +96 -0
- package/skills/pr-consistency-audit/reference/illustrations.md +78 -0
- package/skills/pr-converge/SKILL.md +227 -23
- package/skills/pr-converge/config/__init__.py +0 -0
- package/skills/pr-converge/config/constants.py +62 -0
- package/skills/pr-converge/reference/convergence-gates.md +138 -44
- package/skills/pr-converge/reference/examples.md +43 -11
- package/skills/pr-converge/reference/fix-protocol.md +6 -5
- package/skills/pr-converge/reference/ground-rules.md +5 -3
- package/skills/pr-converge/reference/multi-pr-orchestration.md +44 -19
- package/skills/pr-converge/reference/obstacles/fix-post-replies.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-publish-summary.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-push.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-read-filelines.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-reset-state.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-resolve-threads.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-spawn-clean-coder.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-stage-commit.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-trigger-bugbot.md +13 -0
- package/skills/pr-converge/reference/obstacles/fix-write-test.md +13 -0
- package/skills/pr-converge/reference/per-tick.md +90 -31
- package/skills/pr-converge/reference/state-schema.md +22 -1
- package/skills/pr-converge/reference/stop-conditions.md +9 -7
- package/skills/pr-converge/scripts/README.md +34 -46
- package/skills/pr-converge/scripts/check_bugbot_ci.py +174 -0
- package/skills/pr-converge/scripts/check_convergence.py +497 -0
- package/skills/pr-converge/scripts/check_pending_reviews.py +154 -0
- package/skills/pr-converge/scripts/config/pr_converge_constants.py +118 -0
- package/skills/pr-converge/scripts/fetch_copilot_reviews.py +134 -0
- package/skills/pr-converge/scripts/post_fix_reply.py +168 -0
- package/skills/pr-converge/workflows/schedule-wakeup-loop.md +5 -12
- package/skills/qbug/SKILL.md +132 -27
- package/skills/session-log/SKILL.md +216 -114
- package/skills/session-tidy/SKILL.md +1 -1
- package/skills/skill-builder/SKILL.md +138 -56
- package/skills/skill-builder/references/delegation-map.md +72 -113
- package/skills/skill-builder/references/progressive-disclosure.md +122 -0
- package/skills/skill-builder/references/self-audit-checklist.md +92 -0
- package/skills/skill-builder/references/skill-types.md +228 -0
- package/skills/skill-builder/references/thariq-x-post-skills.json +33 -0
- package/skills/skill-builder/templates/gap-analysis.md +15 -8
- package/skills/skill-builder/workflows/improve-skill.md +86 -57
- package/skills/skill-builder/workflows/new-skill.md +80 -168
- package/skills/skill-builder/workflows/polish-skill.md +78 -54
- package/skills/structure-prompt/SKILL.md +50 -0
- package/skills/structure-prompt/reference/adversarial-tuning.md +62 -0
- package/skills/structure-prompt/reference/block-classification.md +27 -0
- package/skills/structure-prompt/reference/canonical-case.md +48 -0
- package/skills/structure-prompt/reference/citation-depth.md +70 -0
- package/skills/structure-prompt/reference/cleanup.md +33 -0
- package/skills/structure-prompt/reference/constraints.md +33 -0
- package/skills/structure-prompt/reference/directives.md +37 -0
- package/skills/structure-prompt/reference/examples.md +72 -0
- package/skills/structure-prompt/reference/instantiation.md +51 -0
- package/skills/structure-prompt/reference/output-contract.md +72 -0
- package/skills/structure-prompt/reference/per-category.md +23 -0
- package/skills/structure-prompt/reference/persona.md +38 -0
- package/skills/structure-prompt/reference/research.md +33 -0
- package/skills/structure-prompt/reference/structure.md +28 -0
- package/agents/code-standards-agent.md +0 -93
- package/agents/groq-coder.md +0 -113
- package/agents/plan-executor.md +0 -226
- package/agents/project-docs-analyzer.md +0 -53
- package/agents/project-structure-organizer-agent.md +0 -72
- package/agents/skill-to-agent-converter.md +0 -370
- package/agents/skill-writer-agent.md +0 -470
- package/agents/user-docs-writer.md +0 -67
- package/agents/workflow-visual-documenter.md +0 -82
- package/commands/readability-review.md +0 -20
- package/hooks/mypy.ini +0 -2
- package/hooks/notification/attention_needed_notify.py +0 -71
- package/hooks/notification/claude_notification_handler.py +0 -67
- package/hooks/notification/notification_utils.py +0 -267
- package/hooks/notification/subagent_complete_notify.py +0 -381
- package/hooks/notification/test_attention_needed_notify.py +0 -47
- package/hooks/notification/test_claude_notification_handler.py +0 -54
- package/hooks/notification/test_notification_utils.py +0 -91
- package/hooks/notification/test_subagent_complete_notify.py +0 -79
- package/scripts/config/groq_bugteam_config.py +0 -230
- package/scripts/config/test_groq_bugteam_config.py +0 -83
- package/scripts/config/test_spec_implementer_prompt.py +0 -32
- package/scripts/groq_bugteam.README.md +0 -131
- package/scripts/groq_bugteam.py +0 -647
- package/scripts/groq_bugteam_dotenv.py +0 -40
- package/scripts/groq_bugteam_spec.py +0 -226
- package/scripts/test_groq_bugteam.py +0 -529
- package/scripts/test_groq_bugteam_apply_fix_from_spec.py +0 -426
- package/scripts/test_groq_bugteam_dotenv.py +0 -66
- package/scripts/test_groq_bugteam_spec.py +0 -338
- package/skills/bugteam/SKILL_EVALS.md +0 -309
- package/skills/dream/SKILL.md +0 -118
- package/skills/ingest/SKILL.md +0 -40
- package/skills/npm-creator/SKILL.md +0 -187
- package/skills/readability-review/SKILL.md +0 -127
- package/skills/resume-review/SKILL.md +0 -261
- package/skills/rule-audit/SKILL.md +0 -307
- package/skills/rule-creator/SKILL.md +0 -150
- package/skills/searching-obsidian-vault/SKILL.md +0 -131
- package/skills/skill-writer/REFERENCE.md +0 -284
- package/skills/skill-writer/SKILL.md +0 -222
- package/skills/tdd-team/SKILL.md +0 -128
package/CLAUDE.md
CHANGED
|
@@ -1,54 +1,28 @@
|
|
|
1
1
|
# Claude Development Assistant
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The user delegates execution to you and expects zero manual steps unless strictly necessary. Execute every command you can directly. Only instruct the user to do something manually when you are technically unable to do it yourself. When a task involves credentials or other sensitive input, display a minimal secure UI (e.g., a password dialog) to collect it rather than asking the user to paste it into chat or run the command themselves. When direction is ambiguous, use AskUserQuestion to clarify before acting.
|
|
4
4
|
|
|
5
5
|
## Code Rules
|
|
6
6
|
@~/.claude/docs/CODE_RULES.md
|
|
7
7
|
|
|
8
|
+
When a UNC path is mapped to a drive letter, ALWAYS prefer the drive letter and NEVER use UNC.
|
|
9
|
+
|
|
10
|
+
## GOTCHAS
|
|
11
|
+
When making code changes, make sure you are working in the proper worktree path for the task at hand.
|
|
12
|
+
When writing to an existing file, you must either EDIT the file, or remove it and THEN re-write it if it's truly a full re-write.
|
|
13
|
+
|
|
8
14
|
## File-Global Constants
|
|
9
15
|
|
|
10
16
|
**file_global_constants_use_count:** Every module-level constant in production code outside `config/` must be referenced by at least two methods, functions, or classes in the same file. One reference → move to `config/` and import as a local alias. Zero references → delete (dead code). Test files are exempt.
|
|
11
17
|
|
|
12
18
|
Full rule including the decision table, examples, and exemption details: [`packages/claude-dev-env/rules/file-global-constants.md`](rules/file-global-constants.md).
|
|
13
19
|
|
|
14
|
-
##
|
|
15
|
-
|
|
16
|
-
**SRP (Single Responsibility)** always applies: one reason to change per function, class, or module — regardless of paradigm.
|
|
17
|
-
|
|
18
|
-
**OCP, LSP, ISP, DIP** apply where two or more concrete implementations already share a contract. With a single concretion, Right-Sized Engineering takes precedence: use concrete classes, functions when no state, and direct imports. Refactor toward OCP/DIP at the commit that introduces the second concrete implementation.
|
|
19
|
-
|
|
20
|
-
Full rule including the reconciliation with Right-Sized Engineering, misapplication signals, and when-it-adds-value criteria: [`packages/claude-dev-env/docs/CODE_RULES.md`](docs/CODE_RULES.md) §7.5.
|
|
21
|
-
|
|
22
|
-
## Core Philosophy
|
|
20
|
+
## Test Philosophy
|
|
23
21
|
|
|
24
|
-
|
|
22
|
+
When writing tests, always write tests that actually test the behavior of the function against actual, real data and environments.
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
1. **ALWAYS FOLLOW TDD** - No production code without failing test
|
|
29
|
-
2. **MANDATORY SELF-CHECK before proposing** - See protocol below
|
|
30
|
-
3. Assess refactoring after every green
|
|
31
|
-
|
|
32
|
-
**BEFORE proposing plans/implementation:**
|
|
33
|
-
|
|
34
|
-
☐ "Is this KISS?" (simplest? unnecessary complexity?)
|
|
35
|
-
☐ "Over-engineering?" (multiple files? premature abstractions?)
|
|
36
|
-
☐ Test infrastructure? (ONE file, functions, YAGNI)
|
|
37
|
-
☐ Tests add value? (no existence checks, no constant tests)
|
|
38
|
-
☐ Files (proper modules, correct dirs, no empty __init__.py)
|
|
39
|
-
☐ Quality (DRY, types complete, no Any/any)
|
|
24
|
+
When writing tests, always ensure you utilize the production code paths instead of duplicating explicitly for the test.
|
|
40
25
|
|
|
41
26
|
## Additional Non-overlapping Rules
|
|
42
27
|
|
|
43
28
|
- **task_scope:** Match every action to what was explicitly requested. When intent is ambiguous, research official docs and present options via AskUserQuestion before making any changes. Proceed with edits only on explicit instruction.
|
|
44
|
-
|
|
45
|
-
## Tool Policies
|
|
46
|
-
- **context7:** Before writing code using any library/framework/SDK/API, call `resolve-library-id` then `query-docs` via Context7 MCP. Use the fetched docs to write code. Applies to all libs including React, Next.js, Django, Express, Prisma.
|
|
47
|
-
- **gh MCP:** Always use `mcp__plugin_github_github__*` tools for any GitHub operations (branches, PRs, file operations). Do not use the `Bash` tool to invoke `gh` or `git` CLI for GitHub operations.
|
|
48
|
-
|
|
49
|
-
## Compaction
|
|
50
|
-
When compacting, always preserve:
|
|
51
|
-
- Active task and current goal
|
|
52
|
-
- Full list of modified files
|
|
53
|
-
- Any failing test names or error messages
|
|
54
|
-
- Current git branch and PR state
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Audit reply template
|
|
2
|
+
|
|
3
|
+
Canonical reply shape for every orchestrator-to-thread reply posted by the PR-loop suite (`pr-converge`, `bugteam`, `qbug`, and the `clean-coder` agent). Every reply Claude posts to an unresolved review thread on a draft PR uses this template.
|
|
4
|
+
|
|
5
|
+
Read this doc before authoring any code that posts a reply. The template is the contract emitted by every `clean-coder` reply path; the audit-skill wiring (`bugteam`, `qbug`, `pr-converge`) reads it before authoring a reply.
|
|
6
|
+
|
|
7
|
+
This doc has two surfaces, called out separately so consumers do not conflate them: the **reply template** (this section and below) shapes the body Claude posts back to a single review thread; the **audit body skeleton** in [Relationship to the audit review body](#relationship-to-the-audit-review-body) shapes the parent review `post_audit_thread.py` posts at audit time. The reply-template consumers are the four skills/agents listed above (read-only `findbugs` is excluded — it posts an audit review via `post_audit_thread.py` but never authors thread replies). The audit-body-skeleton consumers include `findbugs` alongside `bugteam` and `qbug` because all three skills post audit reviews via the same script.
|
|
8
|
+
|
|
9
|
+
## Provenance
|
|
10
|
+
|
|
11
|
+
The template mirrors Anthropic's `claude[bot]` reply structure observed on `anthropics/claude-code`. Reference example: PR `anthropics/claude-code#10826`, inline comment `2483980211`. Reading that thread shows the structural anchors this template captures: a status header line, a horizontal-rule separator, an `<action_heading> ✅` section, a plain-language explanation, anchored `**`<file>:<line>`:**` bullets, and a closing paragraph.
|
|
12
|
+
|
|
13
|
+
## When the template applies
|
|
14
|
+
|
|
15
|
+
Every reply path uses the same skeleton. Two paths exist; both produce a reply with the structure below.
|
|
16
|
+
|
|
17
|
+
| Path | When the orchestrator picks it | Code-side action |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| Fix | Thread classified `still_applies`. Code change addresses the finding. | `clean-coder` commits the fix, pushes, then replies. |
|
|
20
|
+
| No-longer-applies | Thread classified `no_longer_applies`. Concern is moot under the current code (file removed, intent satisfied differently, refactor obviated the concern). | No code change. Orchestrator posts the reply directly. |
|
|
21
|
+
|
|
22
|
+
## Template skeleton
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
**Claude finished @<reviewer>'s task** —— <status_line>
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
### <action_heading> ✅
|
|
29
|
+
|
|
30
|
+
<1–2 paragraph plain-language explanation>
|
|
31
|
+
|
|
32
|
+
**`<file>:<line>`:**
|
|
33
|
+
- <bullet describing change or rationale>
|
|
34
|
+
- <bullet describing change or rationale>
|
|
35
|
+
|
|
36
|
+
<closing paragraph>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Placeholder reference
|
|
40
|
+
|
|
41
|
+
| Placeholder | Required value |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `<reviewer>` | GitHub login of the reviewer whose thread the reply addresses (e.g., `cursor[bot]`, `copilot-pull-request-reviewer[bot]`, `claude[bot]`, the bugteam-account login, a human reviewer's login). |
|
|
44
|
+
| `<status_line>` | One of two fixed strings, see [Per-path variation](#per-path-variation). |
|
|
45
|
+
| `<action_heading>` | Per-path content, see [Per-path variation](#per-path-variation). |
|
|
46
|
+
| `<file>:<line>` | Path relative to repo root and the line number the reviewer anchored to. Multiple `**`<file>:<line>`:**` blocks are allowed when the reply spans more than one anchor in the same thread. |
|
|
47
|
+
| Bullets | Two or more bullets per anchor block. Each bullet is one sentence. |
|
|
48
|
+
| Closing paragraph | One paragraph that ties the bullets back to the reviewer's concern. Affirmative phrasing only. |
|
|
49
|
+
|
|
50
|
+
The separator between the header and `<action_heading>` is a Markdown horizontal rule (`---`) on its own line. The em-dash separator inside the header line is `——` (two em-dashes, U+2014 ×2). Both render correctly on GitHub.
|
|
51
|
+
|
|
52
|
+
## Per-path variation
|
|
53
|
+
|
|
54
|
+
| Path | `<status_line>` | `<action_heading>` |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| Fix | `Fixed in <SHA>` (short SHA, 7 characters) | Finding-specific action verb. Example: `Replaced Any with concrete type`, `Renamed handle_request to dispatch_webhook`, `Added missing Raises: section`. |
|
|
57
|
+
| No longer applies | `This concern no longer applies` | Reason-specific. Example: `File removed in commit <SHA>`, `Intent satisfied via refactor in commit <SHA>`, `Concern superseded by upstream change`. |
|
|
58
|
+
|
|
59
|
+
## Structural identity rule
|
|
60
|
+
|
|
61
|
+
The skeleton is identical across both paths. The only per-path differences are `<status_line>` and `<action_heading>`. Every other element is present in both paths:
|
|
62
|
+
|
|
63
|
+
- The header line with `**Claude finished @<reviewer>'s task** —— <status_line>` is present in both paths.
|
|
64
|
+
- The horizontal rule separator is present in both paths.
|
|
65
|
+
- The `### <action_heading> ✅` line is present in both paths.
|
|
66
|
+
- The plain-language explanation is present in both paths.
|
|
67
|
+
- The `**`<file>:<line>`:**` bullet blocks are present in both paths. On the fix path, bullets describe what changed. On the no-longer-applies path, bullets describe why the concern is moot at that anchor.
|
|
68
|
+
- The closing paragraph is present in both paths.
|
|
69
|
+
|
|
70
|
+
A reply that omits any of these elements does not satisfy the template.
|
|
71
|
+
|
|
72
|
+
## Worked example — fix path
|
|
73
|
+
|
|
74
|
+
Reviewer thread (synthesized for this doc):
|
|
75
|
+
|
|
76
|
+
> `cursor[bot]` on `src/foo.py:42`:
|
|
77
|
+
> The `handle_request` function returns `Any`. Name the concrete return type so callers do not lose type information.
|
|
78
|
+
|
|
79
|
+
Reply posted by `clean-coder` after committing the fix at SHA `a3f9c12`:
|
|
80
|
+
|
|
81
|
+
```markdown
|
|
82
|
+
**Claude finished @cursor[bot]'s task** —— Fixed in a3f9c12
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
### Replaced Any with concrete return type ✅
|
|
86
|
+
|
|
87
|
+
The reviewer's concern is correct: returning `Any` from a public function erases type information for every caller and defeats `mypy`'s ability to catch shape mismatches downstream. The fix names the concrete return type the function already produces.
|
|
88
|
+
|
|
89
|
+
**`src/foo.py:42`:**
|
|
90
|
+
- Changed the return annotation from `Any` to `RequestOutcome`.
|
|
91
|
+
- Renamed the function from `handle_request` to `dispatch_webhook` to comply with the banned-prefix rule (`handle_` is one of the banned function prefixes per `CODE_RULES.md`).
|
|
92
|
+
- Added a Google-style `Returns:` section to the docstring naming the new return type.
|
|
93
|
+
|
|
94
|
+
The function signature now matches its actual behavior, and `mypy --strict` reports zero errors on the touched file.
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Worked example — no-longer-applies path
|
|
98
|
+
|
|
99
|
+
Reviewer thread (synthesized for this doc):
|
|
100
|
+
|
|
101
|
+
> `copilot-pull-request-reviewer[bot]` on `src/legacy_adapter.py:88`:
|
|
102
|
+
> This compatibility shim should be removed once the upstream migration completes. Add a TODO with the planned removal date.
|
|
103
|
+
|
|
104
|
+
Reply posted by the orchestrator directly (no code change) after the upstream migration lands and removes the shim file entirely:
|
|
105
|
+
|
|
106
|
+
```markdown
|
|
107
|
+
**Claude finished @copilot-pull-request-reviewer[bot]'s task** —— This concern no longer applies
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
### File removed in commit b8e2d4f ✅
|
|
111
|
+
|
|
112
|
+
The compatibility shim the reviewer flagged is no longer present in the tree. The upstream migration completed in commit `b8e2d4f`, and the same commit deleted `src/legacy_adapter.py` outright. There is no longer any shim to add a TODO to, and there is no longer any caller that imports from the removed module.
|
|
113
|
+
|
|
114
|
+
**`src/legacy_adapter.py:88`:**
|
|
115
|
+
- The anchored line lives in a file deleted by commit `b8e2d4f`.
|
|
116
|
+
- A repo-wide grep for `legacy_adapter` returns zero matches.
|
|
117
|
+
- The two former call sites (`src/api/router.py`, `src/api/middleware.py`) import from the consolidated module instead.
|
|
118
|
+
|
|
119
|
+
The thread can be resolved without further action; the reviewer's underlying concern is satisfied by the deletion rather than by the originally requested TODO.
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Relationship to the audit review body
|
|
123
|
+
|
|
124
|
+
The audit review body posted by `post_audit_thread.py` (consumers: `bugteam`, `findbugs`, `qbug`) shares the same header anchor pattern:
|
|
125
|
+
|
|
126
|
+
<!-- audit-body-skeleton:start -->
|
|
127
|
+
```
|
|
128
|
+
**<Skill> audit completed** —— <state_label>
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
### <heading>
|
|
132
|
+
|
|
133
|
+
<summary paragraph>
|
|
134
|
+
|
|
135
|
+
**Findings:** <N> | **Severity:** <P0 count>P0 / <P1 count>P1 / <P2 count>P2
|
|
136
|
+
|
|
137
|
+
<optional collapsed details section per finding>
|
|
138
|
+
```
|
|
139
|
+
<!-- audit-body-skeleton:end -->
|
|
140
|
+
|
|
141
|
+
The audit review body announces a complete audit pass; the reply template addresses one specific thread. They use the same `**Title** —— <status>` header convention so a reader scanning a PR sees consistent visual anchoring across both surfaces.
|
|
142
|
+
|
|
143
|
+
## Cross-references
|
|
144
|
+
|
|
145
|
+
- [`audit-contract.md`](audit-contract.md) — finding schema (Shape A / Shape B), adversarial second pass, post-fix self-audit, persistence layout. The fields in a Shape A finding (`file`, `line`, `failure_mode`) feed the placeholders in this template. Replies cite the same `<file>:<line>` anchors that the originating audit recorded.
|
|
146
|
+
- [`fix-protocol.md`](fix-protocol.md) — step 12 of the fix protocol describes the reply step and renders this template's full structure.
|
|
147
|
+
- [`gh-payloads.md`](gh-payloads.md) — MCP and REST endpoints used to post replies (`add_reply_to_pull_request_comment` and `post_fix_reply.py`). The transport is independent of the template; both transports accept the body string this template defines.
|
|
@@ -16,10 +16,31 @@
|
|
|
16
16
|
9. **Stage by explicit path:** `git add <path>` for each modified file. Avoid `git add -A` and `git add .`.
|
|
17
17
|
10. **Create one commit** summarizing the fixed findings. Let every git hook run. When a hook blocks the commit, capture stderr, mark every finding in this loop `status=hook_blocked`, and move to the next iteration without retrying this loop.
|
|
18
18
|
11. **Push fast-forward:** `git push origin <branch>`. Verify `git fetch origin <branch> && git rev-parse origin/<branch>` matches `HEAD`.
|
|
19
|
-
12. **Reply
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
12. **Reply + resolve, atomic per thread.** For each finding, post the reply and call `resolve_thread` as one logical action — no yield to the orchestrator between them, no batching all replies before any resolves.
|
|
20
|
+
|
|
21
|
+
The reply body uses the unified template from [`audit-reply-template.md`](audit-reply-template.md). Skeleton (identical across all paths):
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
**Claude finished @<reviewer>'s task** —— <status_line>
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
### <action_heading> ✅
|
|
28
|
+
|
|
29
|
+
<1–2 paragraph plain-language explanation>
|
|
30
|
+
|
|
31
|
+
**`<file>:<line>`:**
|
|
32
|
+
- <bullet describing change or rationale>
|
|
33
|
+
- <bullet describing change or rationale>
|
|
34
|
+
|
|
35
|
+
<closing paragraph>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Per-path `<status_line>` / `<action_heading>`:
|
|
39
|
+
- `status=fixed`: `Fixed in <short_sha>` (7-char SHA) / finding-specific action verb (e.g., `Replaced Any with concrete type`).
|
|
40
|
+
- `status=could_not_address`: `Could not address this loop` / one-line reason text.
|
|
41
|
+
- `status=hook_blocked`: `Hook blocked the fix commit` / one-line hook summary.
|
|
42
|
+
|
|
43
|
+
Transport: post the reply via [`gh-payloads.md`](gh-payloads.md), then call `pull_request_review_write(method="resolve_thread", threadId=<thread_node_id>, ...)` for the same thread before moving to the next finding (this is the PR review thread node ID — `PRRT_kwDOxxx` — distinct from the numeric comment ID; harvest it at audit time when calling `get_review_comments`, see [`skills/bugteam/reference/obstacles/fix-resolve-thread.md`](../../skills/bugteam/reference/obstacles/fix-resolve-thread.md)).
|
|
23
44
|
13. **Re-trigger reviewer** when the calling workflow specifies. Workflow-specific:
|
|
24
45
|
- `pr-converge`: post `bugbot run` issue comment after every push (Cursor Bugbot)
|
|
25
46
|
- `monitor-many`: post `bugbot run` issue comment AND call `requested_reviewers` API for Copilot
|
|
@@ -8,42 +8,29 @@ Build payloads as structured arguments to MCP tools. Body content passes as a st
|
|
|
8
8
|
|
|
9
9
|
## One review per loop
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
Single-line anchors: `{path, line, side: "RIGHT", body}`. Multi-line anchors add `start_line` and `start_side: "RIGHT"`.
|
|
29
|
-
|
|
30
|
-
Zero findings still post one review. Body line: `## /<workflow> loop <N> audit: 0P0 / 0P1 / 0P2 → clean`. `comments: []`.
|
|
31
|
-
|
|
32
|
-
## Review body template
|
|
33
|
-
|
|
34
|
-
```
|
|
35
|
-
## /<workflow> loop <N> audit: <P0>P0 / <P1>P1 / <P2>P2
|
|
36
|
-
|
|
37
|
-
### Findings without a diff anchor
|
|
38
|
-
(only when needed)
|
|
39
|
-
- **[severity] title** — <file>:<line> — <one-line description>
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
`<workflow>` is the calling skill name (`bugteam`, `qbug`, `pr-converge`).
|
|
11
|
+
Posting the per-loop audit review is handled by
|
|
12
|
+
[`_shared/pr-loop/scripts/post_audit_thread.py`](scripts/post_audit_thread.py).
|
|
13
|
+
The script owns the review-create/POST/retry flow internally; callers no longer
|
|
14
|
+
build the GitHub reviews-API payload themselves. See
|
|
15
|
+
[`skills/bugteam/SKILL.md` § Audit posting](../../skills/bugteam/SKILL.md#audit-posting)
|
|
16
|
+
for the contract and [`skills/bugteam/PROMPTS.md`](../../skills/bugteam/PROMPTS.md)
|
|
17
|
+
for the AUDIT-step invocation shape.
|
|
18
|
+
|
|
19
|
+
## Review body skeleton
|
|
20
|
+
|
|
21
|
+
The review body skeleton lives in
|
|
22
|
+
[`audit-reply-template.md`](audit-reply-template.md) between the
|
|
23
|
+
`<!-- audit-body-skeleton:start -->` and `<!-- audit-body-skeleton:end -->`
|
|
24
|
+
markers. `post_audit_thread.py` reads that skeleton at runtime and substitutes
|
|
25
|
+
its placeholders (`<Skill>`, `<state_label>`, `<heading>`, severity counts,
|
|
26
|
+
collapsed `<details>` block). Callers pass the skill name, state, commit SHA,
|
|
27
|
+
and findings JSON; the body shape is owned by the template.
|
|
43
28
|
|
|
44
29
|
## Reply to a finding
|
|
45
30
|
|
|
46
|
-
Call `add_reply_to_pull_request_comment` with the finding comment ID and
|
|
31
|
+
Call `add_reply_to_pull_request_comment` with the finding comment ID and a
|
|
32
|
+
reply body rendered from
|
|
33
|
+
[`audit-reply-template.md`](audit-reply-template.md):
|
|
47
34
|
|
|
48
35
|
```
|
|
49
36
|
add_reply_to_pull_request_comment(
|
|
@@ -55,30 +42,30 @@ add_reply_to_pull_request_comment(
|
|
|
55
42
|
)
|
|
56
43
|
```
|
|
57
44
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
Lines not in the PR diff cannot anchor an inline comment. Omit them from `comments[]` and list under the review body's `### Findings without a diff anchor` section. Outcome record per finding: `used_fallback="true"`, empty `finding_comment_id`, `finding_comment_url` = parent review URL.
|
|
45
|
+
The `body` follows the unified reply skeleton documented in
|
|
46
|
+
[`audit-reply-template.md` § Template skeleton](audit-reply-template.md#template-skeleton).
|
|
61
47
|
|
|
62
|
-
##
|
|
48
|
+
## Anchor fallback (line not in diff)
|
|
63
49
|
|
|
64
|
-
|
|
50
|
+
Lines not in the PR diff cannot anchor an inline comment. The AUDIT teammate
|
|
51
|
+
keeps such findings out of the findings JSON handed to
|
|
52
|
+
`post_audit_thread.py`, lists them in the audit outcome XML under `<finding>`
|
|
53
|
+
with an empty `finding_comment_id`, and surfaces them in the calling skill's
|
|
54
|
+
user-facing output (chat reply to the user) rather than in the PR review body.
|
|
65
55
|
|
|
66
|
-
|
|
67
|
-
add_issue_comment(
|
|
68
|
-
owner=owner,
|
|
69
|
-
repo=repo,
|
|
70
|
-
issueNumber=pull_number,
|
|
71
|
-
body=fallback_body
|
|
72
|
-
)
|
|
73
|
-
```
|
|
56
|
+
## Review POST failure
|
|
74
57
|
|
|
75
|
-
|
|
58
|
+
There is no fallback path. `post_audit_thread.py` exits `2` on retry
|
|
59
|
+
exhaustion (four non-2xx responses across the built-in `1s / 4s / 16s` backoff)
|
|
60
|
+
and the orchestrator halts with `error: post_audit_thread retry exhausted`.
|
|
61
|
+
A hard blocker on the audit-posting path is a halt condition, not a degraded
|
|
62
|
+
flat-issue-comment fall-through.
|
|
76
63
|
|
|
77
64
|
## Endpoints
|
|
78
65
|
|
|
79
|
-
- Review: `
|
|
80
|
-
|
|
81
|
-
-
|
|
66
|
+
- Review: handled by `post_audit_thread.py` (POSTs to
|
|
67
|
+
`/repos/{owner}/{repo}/pulls/{N}/reviews` internally).
|
|
68
|
+
- Reply: `add_reply_to_pull_request_comment(...)`.
|
|
82
69
|
|
|
83
70
|
## SHA capture timing
|
|
84
71
|
|
|
@@ -15,18 +15,13 @@ from config.code_rules_gate_constants import (
|
|
|
15
15
|
ALL_CODE_FILE_EXTENSIONS,
|
|
16
16
|
ALL_GIT_DIFF_CACHED_NAME_ONLY_NULL_TERMINATED_COMMAND,
|
|
17
17
|
ALL_GIT_DIFF_NAME_ONLY_NULL_TERMINATED_COMMAND_PREFIX,
|
|
18
|
-
ALL_LITERAL_KEYWORD_EXEMPTIONS,
|
|
19
18
|
ALL_TEST_FILENAME_GLOB_SUFFIXES,
|
|
20
19
|
ALL_TEST_FILENAME_SUFFIXES,
|
|
21
|
-
COLUMN_KEY_PATTERN_TEMPLATE,
|
|
22
|
-
CONFIG_PATH_SEGMENT,
|
|
23
20
|
EXPECTED_NON_RENAME_COLUMN_COUNT,
|
|
24
21
|
EXPECTED_RENAME_COLUMN_COUNT,
|
|
25
|
-
EXPECTED_TUPLE_PAIR_LENGTH,
|
|
26
22
|
GIT_NAME_STATUS_ADDED_PREFIX,
|
|
27
23
|
GIT_NAME_STATUS_RENAMED_PREFIX,
|
|
28
24
|
MAX_VIOLATIONS_PER_CHECK,
|
|
29
|
-
MINIMUM_COLUMN_NAME_LENGTH_AFTER_FIRST_CHAR,
|
|
30
25
|
PYTHON_FILE_EXTENSION,
|
|
31
26
|
TEST_CONFTEST_FILENAME,
|
|
32
27
|
TEST_FILENAME_PREFIX,
|
|
@@ -365,58 +360,6 @@ def is_test_path(file_path: str) -> bool:
|
|
|
365
360
|
return False
|
|
366
361
|
|
|
367
362
|
|
|
368
|
-
def check_database_column_string_magic(content: str, file_path: str) -> list[str]:
|
|
369
|
-
"""Flag string literals that look like database/HTTP column or key names inside function bodies.
|
|
370
|
-
|
|
371
|
-
Triggers when a snake_case string literal appears as the first element of a
|
|
372
|
-
two-element tuple inside a function body (the characteristic column-name/value
|
|
373
|
-
pair pattern). Files under ``config/`` and test files are exempt.
|
|
374
|
-
"""
|
|
375
|
-
normalized_path = file_path.replace("\\", "/")
|
|
376
|
-
if CONFIG_PATH_SEGMENT in normalized_path:
|
|
377
|
-
return []
|
|
378
|
-
if is_test_path(normalized_path):
|
|
379
|
-
return []
|
|
380
|
-
try:
|
|
381
|
-
tree = ast.parse(content)
|
|
382
|
-
except SyntaxError:
|
|
383
|
-
return []
|
|
384
|
-
issues: list[str] = []
|
|
385
|
-
column_key_pattern = re.compile(
|
|
386
|
-
COLUMN_KEY_PATTERN_TEMPLATE.format(
|
|
387
|
-
minimum_length=MINIMUM_COLUMN_NAME_LENGTH_AFTER_FIRST_CHAR
|
|
388
|
-
)
|
|
389
|
-
)
|
|
390
|
-
seen_tuple_node_ids: set[int] = set()
|
|
391
|
-
for each_node in ast.walk(tree):
|
|
392
|
-
if not isinstance(each_node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
393
|
-
continue
|
|
394
|
-
for each_child in ast.walk(each_node):
|
|
395
|
-
if not isinstance(each_child, ast.Tuple):
|
|
396
|
-
continue
|
|
397
|
-
if id(each_child) in seen_tuple_node_ids:
|
|
398
|
-
continue
|
|
399
|
-
seen_tuple_node_ids.add(id(each_child))
|
|
400
|
-
if len(each_child.elts) != EXPECTED_TUPLE_PAIR_LENGTH:
|
|
401
|
-
continue
|
|
402
|
-
first_element = each_child.elts[0]
|
|
403
|
-
if not isinstance(first_element, ast.Constant):
|
|
404
|
-
continue
|
|
405
|
-
if not isinstance(first_element.value, str):
|
|
406
|
-
continue
|
|
407
|
-
literal_text = first_element.value
|
|
408
|
-
if not column_key_pattern.match(literal_text):
|
|
409
|
-
continue
|
|
410
|
-
if literal_text in ALL_LITERAL_KEYWORD_EXEMPTIONS:
|
|
411
|
-
continue
|
|
412
|
-
issues.append(
|
|
413
|
-
f"Line {first_element.lineno}: Column-name string magic {literal_text!r} - extract to config"
|
|
414
|
-
)
|
|
415
|
-
if len(issues) >= MAX_VIOLATIONS_PER_CHECK:
|
|
416
|
-
return issues
|
|
417
|
-
return issues
|
|
418
|
-
|
|
419
|
-
|
|
420
363
|
def _iter_calls_excluding_nested_functions(node: ast.AST) -> Iterator[ast.Call]:
|
|
421
364
|
for each_child in ast.iter_child_nodes(node):
|
|
422
365
|
if isinstance(each_child, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
@@ -826,9 +769,6 @@ def run_gate(
|
|
|
826
769
|
repository_root.resolve(), relative_posix
|
|
827
770
|
)
|
|
828
771
|
issues = validate_content(content, relative_posix, prior_content)
|
|
829
|
-
issues.extend(
|
|
830
|
-
check_database_column_string_magic(content, relative_posix)
|
|
831
|
-
)
|
|
832
772
|
issues.extend(check_wrapper_plumb_through(content, relative_posix))
|
|
833
773
|
if not issues:
|
|
834
774
|
continue
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"""Constants for post_audit_thread.py.
|
|
2
|
+
|
|
3
|
+
Centralizes every literal the script and its tests need so the script body
|
|
4
|
+
contains no magic values beyond the integer literals exempt from
|
|
5
|
+
``check_magic_values`` (``0``, ``1``, ``-1``). Constants live here per
|
|
6
|
+
CODE_RULES.md §4 (Config Locations) and §3 (Reuse Constants).
|
|
7
|
+
|
|
8
|
+
All scalar constants stay narrowly typed so the consuming script and tests
|
|
9
|
+
can rely on ``int`` / ``str`` / ``tuple`` semantics without runtime checks.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
SKILL_BUGTEAM: str = "bugteam"
|
|
17
|
+
SKILL_FINDBUGS: str = "findbugs"
|
|
18
|
+
SKILL_QBUG: str = "qbug"
|
|
19
|
+
ALL_SUPPORTED_SKILLS: tuple[str, ...] = (SKILL_BUGTEAM, SKILL_FINDBUGS, SKILL_QBUG)
|
|
20
|
+
|
|
21
|
+
STATE_CLEAN: str = "CLEAN"
|
|
22
|
+
STATE_DIRTY: str = "DIRTY"
|
|
23
|
+
ALL_SUPPORTED_STATES: tuple[str, ...] = (STATE_CLEAN, STATE_DIRTY)
|
|
24
|
+
|
|
25
|
+
SEVERITY_TAG_P0: str = "P0"
|
|
26
|
+
SEVERITY_TAG_P1: str = "P1"
|
|
27
|
+
SEVERITY_TAG_P2: str = "P2"
|
|
28
|
+
ALL_SUPPORTED_SEVERITY_TAGS: tuple[str, ...] = (
|
|
29
|
+
SEVERITY_TAG_P0,
|
|
30
|
+
SEVERITY_TAG_P1,
|
|
31
|
+
SEVERITY_TAG_P2,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
INLINE_COMMENT_SIDE_RIGHT: str = "RIGHT"
|
|
35
|
+
INLINE_COMMENT_SIDE_LEFT: str = "LEFT"
|
|
36
|
+
ALL_SUPPORTED_INLINE_COMMENT_SIDES: tuple[str, ...] = (
|
|
37
|
+
INLINE_COMMENT_SIDE_RIGHT,
|
|
38
|
+
INLINE_COMMENT_SIDE_LEFT,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
GITHUB_API_BASE_URL: str = "https://api.github.com"
|
|
42
|
+
GITHUB_API_USER_AGENT: str = "post_audit_thread.py/1"
|
|
43
|
+
GITHUB_API_ACCEPT_HEADER: str = "application/vnd.github+json"
|
|
44
|
+
GITHUB_API_VERSION_HEADER: str = "2022-11-28"
|
|
45
|
+
|
|
46
|
+
GITHUB_REVIEW_EVENT_APPROVE: str = "APPROVE"
|
|
47
|
+
GITHUB_REVIEW_EVENT_REQUEST_CHANGES: str = "REQUEST_CHANGES"
|
|
48
|
+
|
|
49
|
+
HTTP_STATUS_SUCCESS_RANGE_LOW: int = 200
|
|
50
|
+
HTTP_STATUS_SUCCESS_RANGE_HIGH: int = 300
|
|
51
|
+
|
|
52
|
+
HTTP_AUTHORIZATION_BEARER_PREFIX: str = "Bearer "
|
|
53
|
+
HTTP_HEADER_AUTHORIZATION: str = "Authorization"
|
|
54
|
+
HTTP_HEADER_ACCEPT: str = "Accept"
|
|
55
|
+
HTTP_HEADER_CONTENT_TYPE: str = "Content-Type"
|
|
56
|
+
HTTP_HEADER_GITHUB_API_VERSION: str = "X-GitHub-Api-Version"
|
|
57
|
+
HTTP_HEADER_USER_AGENT: str = "User-Agent"
|
|
58
|
+
HTTP_METHOD_POST: str = "POST"
|
|
59
|
+
HTTP_REQUEST_CONTENT_TYPE: str = "application/json"
|
|
60
|
+
HTTP_REQUEST_TIMEOUT_SECONDS: int = 30
|
|
61
|
+
ERROR_RESPONSE_PREVIEW_CHARS: int = 200
|
|
62
|
+
|
|
63
|
+
MAX_RETRY_ATTEMPTS: int = 3
|
|
64
|
+
ALL_RETRY_BACKOFF_SECONDS: tuple[int, ...] = (1, 4, 16)
|
|
65
|
+
|
|
66
|
+
EXIT_CODE_USER_ERROR: int = 1
|
|
67
|
+
EXIT_CODE_RETRY_EXHAUSTED: int = 2
|
|
68
|
+
|
|
69
|
+
SHORT_SHA_LENGTH: int = 7
|
|
70
|
+
|
|
71
|
+
ALL_GH_AUTH_TOKEN_COMMAND_PARTS: tuple[str, ...] = ("gh", "auth", "token")
|
|
72
|
+
|
|
73
|
+
GH_TOKEN_ENV_VAR_NAME: str = "GH_TOKEN"
|
|
74
|
+
GITHUB_TOKEN_ENV_VAR_NAME: str = "GITHUB_TOKEN"
|
|
75
|
+
ALL_GH_TOKEN_ENV_VAR_NAMES: tuple[str, ...] = (
|
|
76
|
+
GH_TOKEN_ENV_VAR_NAME,
|
|
77
|
+
GITHUB_TOKEN_ENV_VAR_NAME,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
JSON_FIELD_PATH: str = "path"
|
|
81
|
+
JSON_FIELD_LINE: str = "line"
|
|
82
|
+
JSON_FIELD_SIDE: str = "side"
|
|
83
|
+
JSON_FIELD_SEVERITY: str = "severity"
|
|
84
|
+
JSON_FIELD_DESCRIPTION: str = "description"
|
|
85
|
+
JSON_FIELD_FIX_SUMMARY: str = "fix_summary"
|
|
86
|
+
ALL_REQUIRED_FINDING_FIELDS: tuple[str, ...] = (
|
|
87
|
+
JSON_FIELD_PATH,
|
|
88
|
+
JSON_FIELD_LINE,
|
|
89
|
+
JSON_FIELD_SIDE,
|
|
90
|
+
JSON_FIELD_SEVERITY,
|
|
91
|
+
JSON_FIELD_DESCRIPTION,
|
|
92
|
+
JSON_FIELD_FIX_SUMMARY,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
REVIEW_REQUEST_FIELD_COMMIT_ID: str = "commit_id"
|
|
96
|
+
REVIEW_REQUEST_FIELD_BODY: str = "body"
|
|
97
|
+
REVIEW_REQUEST_FIELD_EVENT: str = "event"
|
|
98
|
+
REVIEW_REQUEST_FIELD_COMMENTS: str = "comments"
|
|
99
|
+
|
|
100
|
+
REVIEW_RESPONSE_FIELD_HTML_URL: str = "html_url"
|
|
101
|
+
|
|
102
|
+
INLINE_COMMENT_FIELD_PATH: str = "path"
|
|
103
|
+
INLINE_COMMENT_FIELD_LINE: str = "line"
|
|
104
|
+
INLINE_COMMENT_FIELD_SIDE: str = "side"
|
|
105
|
+
INLINE_COMMENT_FIELD_BODY: str = "body"
|
|
106
|
+
|
|
107
|
+
AUDIT_REPLY_TEMPLATE_FILENAME: str = "audit-reply-template.md"
|
|
108
|
+
TEMPLATE_FENCE_TOKEN: str = "```"
|
|
109
|
+
|
|
110
|
+
PLACEHOLDER_SKILL: str = "<Skill>"
|
|
111
|
+
PLACEHOLDER_STATE_LABEL: str = "<state_label>"
|
|
112
|
+
PLACEHOLDER_HEADING: str = "<heading>"
|
|
113
|
+
PLACEHOLDER_SUMMARY_PARAGRAPH: str = "<summary paragraph>"
|
|
114
|
+
PLACEHOLDER_FINDINGS_COUNT: str = "<N>"
|
|
115
|
+
PLACEHOLDER_P0_COUNT: str = "<P0 count>"
|
|
116
|
+
PLACEHOLDER_P1_COUNT: str = "<P1 count>"
|
|
117
|
+
PLACEHOLDER_P2_COUNT: str = "<P2 count>"
|
|
118
|
+
PLACEHOLDER_DETAILS_BLOCK: str = "<optional collapsed details section per finding>"
|
|
119
|
+
|
|
120
|
+
STATE_LABEL_FOR_CLEAN: str = "Clean — no findings"
|
|
121
|
+
STATE_LABEL_FOR_DIRTY: str = "Findings requested"
|
|
122
|
+
HEADING_FOR_CLEAN: str = "Audit pass clean"
|
|
123
|
+
HEADING_FOR_DIRTY: str = "Findings recorded as inline review comments"
|
|
124
|
+
|
|
125
|
+
SUMMARY_PARAGRAPH_CLEAN_TEMPLATE: str = (
|
|
126
|
+
"The {skill_display} audit pass against commit `{short_commit}` found no "
|
|
127
|
+
"findings. No inline review comments were posted; the PR carries zero "
|
|
128
|
+
"unresolved threads originating from this audit pass."
|
|
129
|
+
)
|
|
130
|
+
SUMMARY_PARAGRAPH_DIRTY_TEMPLATE: str = (
|
|
131
|
+
"The {skill_display} audit pass against commit `{short_commit}` surfaced "
|
|
132
|
+
"{findings_count} finding(s). Each finding is posted below as an inline "
|
|
133
|
+
"review comment so it becomes its own resolvable thread; the unresolved-"
|
|
134
|
+
"thread gate picks them up at the next pr-converge step boundary."
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
DETAILS_BLOCK_HEADER: str = "<details>\n<summary>Finding details</summary>\n"
|
|
138
|
+
DETAILS_BLOCK_BULLET_TEMPLATE: str = (
|
|
139
|
+
"- **[{severity}]** `{path}:{line}` — {description}"
|
|
140
|
+
)
|
|
141
|
+
DETAILS_BLOCK_FOOTER: str = "\n</details>"
|
|
142
|
+
|
|
143
|
+
INLINE_COMMENT_BODY_TEMPLATE: str = (
|
|
144
|
+
"**[{severity}] {skill_display} audit finding**\n\n"
|
|
145
|
+
"{description}\n\n"
|
|
146
|
+
"**Suggested fix:** {fix_summary}"
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
CLI_FLAG_SKILL: str = "--skill"
|
|
150
|
+
CLI_FLAG_OWNER: str = "--owner"
|
|
151
|
+
CLI_FLAG_REPO: str = "--repo"
|
|
152
|
+
CLI_FLAG_PR_NUMBER: str = "--pr-number"
|
|
153
|
+
CLI_FLAG_COMMIT: str = "--commit"
|
|
154
|
+
CLI_FLAG_STATE: str = "--state"
|
|
155
|
+
CLI_FLAG_FINDINGS_JSON: str = "--findings-json"
|
|
156
|
+
|
|
157
|
+
REVIEWS_API_PATH_TEMPLATE: str = "/repos/{owner}/{repo}/pulls/{pr_number}/reviews"
|
|
158
|
+
SINGLE_REVIEW_API_PATH_TEMPLATE: str = (
|
|
159
|
+
"/repos/{owner}/{repo}/pulls/{pr_number}/reviews/{review_id}"
|
|
160
|
+
)
|
|
161
|
+
SINGLE_REVIEW_COMMENTS_API_PATH_TEMPLATE: str = (
|
|
162
|
+
"/repos/{owner}/{repo}/pulls/{pr_number}/reviews/{review_id}/comments"
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
AUDIT_BODY_SKELETON_OPEN_MARKER: str = "<!-- audit-body-skeleton:start -->"
|
|
166
|
+
AUDIT_BODY_SKELETON_CLOSE_MARKER: str = "<!-- audit-body-skeleton:end -->"
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def script_directory() -> Path:
|
|
170
|
+
"""Return the absolute path of the parent directory holding the consuming script.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
Path to ``_shared/pr-loop/scripts/`` resolved through this constants
|
|
174
|
+
module's location. Callers may walk up one further level
|
|
175
|
+
(``script_directory().parent``) to reach the
|
|
176
|
+
``_shared/pr-loop/`` directory where ``audit-reply-template.md`` lives.
|
|
177
|
+
"""
|
|
178
|
+
return Path(__file__).resolve().parent.parent
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def template_path() -> Path:
|
|
182
|
+
"""Return the absolute path to ``audit-reply-template.md``.
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
Path object pointing to ``_shared/pr-loop/audit-reply-template.md``
|
|
186
|
+
relative to this constants module. Callers read this file at runtime
|
|
187
|
+
so the markdown doc remains the source of truth for the body skeleton.
|
|
188
|
+
"""
|
|
189
|
+
return script_directory().parent / AUDIT_REPLY_TEMPLATE_FILENAME
|