claude-dev-env 1.38.1 → 1.40.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 +199 -0
- package/_shared/pr-loop/scripts/config/reviews_disabled_constants.py +8 -0
- package/_shared/pr-loop/scripts/post_audit_thread.py +1242 -0
- package/_shared/pr-loop/scripts/preflight.py +129 -2
- package/_shared/pr-loop/scripts/reviews_disabled.py +59 -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 +1116 -0
- package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +127 -0
- package/_shared/pr-loop/scripts/tests/test_preflight.py +41 -0
- package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +36 -0
- package/_shared/pr-loop/state-schema.md +1 -1
- package/agents/clean-coder.md +2 -2
- package/agents/pr-description-writer.md +150 -52
- 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/docs/PR_DESCRIPTION_GUIDE.md +127 -64
- package/hooks/blocking/bot_mention_comment_blocker.py +75 -0
- package/hooks/blocking/code_rules_enforcer.py +1143 -129
- 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/pr_description_enforcer.py +57 -22
- 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_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/blocking/test_pr_description_enforcer.py +69 -8
- 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/pr_description_enforcer_constants.py +14 -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 +132 -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 +111 -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 +328 -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 +309 -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/copilot-review/SKILL.md +16 -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 +96 -2
- package/skills/monitor-open-prs/SKILL.md +14 -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 +229 -23
- package/skills/pr-converge/config/__init__.py +0 -0
- package/skills/pr-converge/config/constants.py +63 -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 +107 -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 +279 -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/scripts/test_check_bugbot_ci.py +312 -0
- package/skills/pr-converge/workflows/schedule-wakeup-loop.md +5 -12
- package/skills/qbug/SKILL.md +157 -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
|
@@ -1,5 +1,82 @@
|
|
|
1
1
|
# Gate, cycle, AUDIT, and FIX
|
|
2
2
|
|
|
3
|
+
## Pre-cycle: walk prior bugteam reviews end-first
|
|
4
|
+
|
|
5
|
+
**Pre-cycle: walk prior bugteam reviews end-first** (once per PR, after Step 2
|
|
6
|
+
and before iteration begins, when `last_action == "fresh"`). A re-invocation of
|
|
7
|
+
`/bugteam` on a PR with prior loops detects whether the most recent loop already
|
|
8
|
+
cleaned this HEAD (short-circuit) and otherwise records that prior loops were
|
|
9
|
+
dirty so the AUDIT runs against the latest diff with that signal in mind:
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
dirty_review_count = 0
|
|
13
|
+
all_reviews = pull_request_read(
|
|
14
|
+
method="get_reviews", pullNumber=N, owner=O, repo=R
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
NEW_BUGTEAM_HEADER_PREFIX = "**Bugteam audit completed**"
|
|
18
|
+
LEGACY_BUGTEAM_HEADER_PREFIX = "## /bugteam loop "
|
|
19
|
+
NEW_CLEAN_STATE_LABEL = "Clean — no findings"
|
|
20
|
+
LEGACY_CLEAN_TOKEN = "→ clean"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def is_bugteam_review(review_body: str) -> bool:
|
|
24
|
+
return (
|
|
25
|
+
review_body.startswith(NEW_BUGTEAM_HEADER_PREFIX)
|
|
26
|
+
or review_body.startswith(LEGACY_BUGTEAM_HEADER_PREFIX)
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def is_clean_bugteam_review(review_body: str) -> bool:
|
|
31
|
+
if review_body.startswith(NEW_BUGTEAM_HEADER_PREFIX):
|
|
32
|
+
return NEW_CLEAN_STATE_LABEL in review_body.splitlines()[0]
|
|
33
|
+
return review_body.rstrip().endswith(LEGACY_CLEAN_TOKEN)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
prior_reviews = [
|
|
37
|
+
rev for rev in all_reviews
|
|
38
|
+
if is_bugteam_review(rev.get("body", ""))
|
|
39
|
+
]
|
|
40
|
+
prior_reviews.sort(key=lambda rev: rev["submitted_at"], reverse=True)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The classifier handles both shapes. The new shape — emitted by
|
|
44
|
+
`_shared/pr-loop/scripts/post_audit_thread.py` reading
|
|
45
|
+
`_shared/pr-loop/audit-reply-template.md` at runtime — opens with
|
|
46
|
+
`**Bugteam audit completed** —— Clean — no findings` on CLEAN and
|
|
47
|
+
`**Bugteam audit completed** —— Findings requested` on DIRTY. The legacy
|
|
48
|
+
shape — emitted before `post_audit_thread.py` became canonical — opens
|
|
49
|
+
with `## /bugteam loop <N> audit:` and ends with `→ clean` on CLEAN. Both
|
|
50
|
+
shapes are recognized so re-invocations on long-lived branches with
|
|
51
|
+
mixed-shape history classify correctly.
|
|
52
|
+
|
|
53
|
+
Iterate from index 0 (most recent) toward older entries:
|
|
54
|
+
|
|
55
|
+
- A bugteam review body whose first line carries the
|
|
56
|
+
`Clean — no findings` state label (new shape) or whose body ends with
|
|
57
|
+
`→ clean` (legacy shape) is **clean**; any other bugteam review body
|
|
58
|
+
is **dirty**.
|
|
59
|
+
- For a dirty review, increment `dirty_review_count` by one. The review's
|
|
60
|
+
specific finding bodies are not carried forward —
|
|
61
|
+
bugteam's AUDIT regenerates
|
|
62
|
+
findings against the current HEAD's diff each loop, so prior bodies are stale
|
|
63
|
+
by definition. The count alone is the carried signal.
|
|
64
|
+
- Stop at the first clean review. Older reviews are presumed addressed at that
|
|
65
|
+
clean checkpoint and are not re-read.
|
|
66
|
+
- When index 0 is itself clean AND its `commit_id` matches `git rev-parse HEAD`,
|
|
67
|
+
the PR is already converged on this HEAD — set `last_action="audited"`,
|
|
68
|
+
`last_findings='{"total": 0}'`, fall through to step 1's `converged` exit,
|
|
69
|
+
skip Step 3 iteration entirely.
|
|
70
|
+
- When `dirty_review_count > 0`, log the count and proceed into the normal
|
|
71
|
+
iteration; the next AUDIT regenerates anchored findings against the current
|
|
72
|
+
HEAD so `loop_comment_index` stays correct. Unlike `pr-converge` — where
|
|
73
|
+
Cursor Bugbot's prior dirty-review *bodies* are read back by the Fix protocol
|
|
74
|
+
because each dirty body lists specific findings the loop must still address
|
|
75
|
+
—
|
|
76
|
+
bugteam's per-loop bodies are anchored to the diff at *that loop's* HEAD, so
|
|
77
|
+
re-applying them against a newer diff would be incorrect. The count is
|
|
78
|
+
sufficient signal that "prior loops did not converge here."
|
|
79
|
+
|
|
3
80
|
## Step 3 — The cycle (full detail)
|
|
4
81
|
|
|
5
82
|
Repeat until an exit condition fires.
|
|
@@ -22,12 +99,12 @@ Repeat until an exit condition fires.
|
|
|
22
99
|
`git merge-base` + `git diff --name-only` live inside the script; see [`../../../_shared/pr-loop/scripts/README.md`](../../../_shared/pr-loop/scripts/README.md) for what lives under this directory, and [`../../../_shared/pr-loop/code-rules-gate.md`](../../../_shared/pr-loop/code-rules-gate.md) for gate-only merge-base / invocation semantics. The lead runs this (not a teammate).
|
|
23
100
|
|
|
24
101
|
2. If exit code **0** → continue to step 2.5 (AUDIT spawn) below.
|
|
25
|
-
3. If exit code **non-zero** → spawn a new **clean-coder** teammate — **standards-fix pass** — with instructions: read the script’s stderr, edit the repo until a **re-run** of the **same** gate command exits **0**, then one commit, `git push`, shutdown. Repeat standards-fix spawns until the gate exits **0** or **5** failed gate rounds (each round = one teammate session after a non-zero gate). If still non-zero after 5 rounds → exit reason = `error: code rules gate failed pre-audit`.
|
|
26
|
-
4. After gate exit **0**, increment `loop_count`. If `loop_count >
|
|
102
|
+
3. If exit code **non-zero** → spawn a new **clean-coder** teammate (`mode="bypassPermissions"`) — **standards-fix pass** — with instructions: read the script’s stderr, edit the repo until a **re-run** of the **same** gate command exits **0**, then one commit, `git push`, shutdown. Repeat standards-fix spawns until the gate exits **0** or **5** failed gate rounds (each round = one teammate session after a non-zero gate). If still non-zero after 5 rounds → exit reason = `error: code rules gate failed pre-audit`.
|
|
103
|
+
4. After gate exit **0**, increment `loop_count`. If `loop_count > 20`, exit reason = `cap reached` (counts **audits**, not standards-only rounds).
|
|
27
104
|
5. Execute **AUDIT action** (spawn bugfind). Print progress: `Loop <L> audit: ...`
|
|
28
105
|
|
|
29
106
|
3. **FIX path** (when `last_action == "audited"` and `last_findings.total > 0`):
|
|
30
|
-
1. Increment `loop_count`. If `loop_count >
|
|
107
|
+
1. Increment `loop_count`. If `loop_count > 20`, exit reason = `cap reached`.
|
|
31
108
|
2. Execute **FIX action** (spawn bugfix clean-coder for audit findings). Print: `Loop <L> fix: commit ...`
|
|
32
109
|
3. Set `last_action = "fixed"`, update `audit_log`, loop to step 1 (next iteration hits **pre-audit path** before the next AUDIT).
|
|
33
110
|
|
|
@@ -37,53 +114,47 @@ Repeat until an exit condition fires.
|
|
|
37
114
|
|
|
38
115
|
**Note:** The first iteration uses **pre-audit path** then **AUDIT**. After a **FIX**, the next iteration runs **pre-audit path** again (gate → then AUDIT), so `validate_content` stays green before semantic audit.
|
|
39
116
|
|
|
40
|
-
## AUDIT action
|
|
41
|
-
|
|
42
|
-
Capture a fresh PR diff for this loop into the per-PR scoped directory so concurrent `/bugteam` runs keep patches isolated. Use the literal `<run_temp_dir>` resolved once in Step 2 — Claude resolves the absolute path; every shell receives the same literal value.
|
|
117
|
+
## AUDIT action
|
|
43
118
|
|
|
44
|
-
|
|
119
|
+
Spawn one audit agent that walks all A–K categories:
|
|
45
120
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
121
|
+
```
|
|
122
|
+
Agent(
|
|
123
|
+
subagent_type="code-quality-agent",
|
|
124
|
+
name="bugfind-pr<N>-loop<L>",
|
|
125
|
+
model="opus",
|
|
126
|
+
run_in_background=true,
|
|
127
|
+
description="Audit {owner}/{repo}#{N} loop {L}",
|
|
128
|
+
prompt="<output of build_audit_prompt.py; see ../../_shared/pr-loop/scripts/build_audit_prompt.py>"
|
|
129
|
+
)
|
|
130
|
+
```
|
|
55
131
|
|
|
56
|
-
|
|
132
|
+
The audit prompt XML is emitted by
|
|
133
|
+
[`build_audit_prompt.py`](../../_shared/pr-loop/scripts/build_audit_prompt.py).
|
|
134
|
+
Run it with `--owner --repo --pr-number --loop --head-ref --base-ref --worktree-path --run-temp-dir`
|
|
135
|
+
to generate the complete `<spawn_prompt>` XML on stdout.
|
|
57
136
|
|
|
58
137
|
`last_action = "audited"`. Append audit metadata to `audit_log`.
|
|
59
138
|
|
|
60
|
-
|
|
139
|
+
## FIX action (fresh teammate)
|
|
61
140
|
|
|
62
|
-
|
|
141
|
+
Spawn:
|
|
63
142
|
|
|
64
143
|
```
|
|
65
|
-
Agent(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-j", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant j", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-j.outcomes.xml; skip PR posting>")
|
|
75
|
-
Agent(subagent_type="code-quality-agent", name="bugfind-pr<N>-loop<L>-k", team_name="<team_name>", model="haiku", run_in_background=true, description="Bugfind audit PR <N> loop <L> variant k", prompt="<audit XML; write outcome to <run_temp_dir>/pr-<N>/loop-<L>-k.outcomes.xml; skip PR posting>")
|
|
144
|
+
Agent(
|
|
145
|
+
subagent_type="clean-coder",
|
|
146
|
+
name="bugfix-pr<N>-loop<L>",
|
|
147
|
+
model="opus",
|
|
148
|
+
mode="bypassPermissions",
|
|
149
|
+
run_in_background=true,
|
|
150
|
+
description="Bugfix PR <N> loop <L>",
|
|
151
|
+
prompt="<output of build_fix_prompt.py; see ../../_shared/pr-loop/scripts/build_fix_prompt.py>"
|
|
152
|
+
)
|
|
76
153
|
```
|
|
77
154
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
All subagents self-terminate via background completion. The lead awaits only the validator (-a) notification (120s timeout). Missing notification → hard blocker.
|
|
81
|
-
|
|
82
|
-
## FIX action (fresh teammate)
|
|
83
|
-
|
|
84
|
-
`Agent` shape in `SKILL.md`. The teammate sees only the latest audit’s findings — each `Agent` call starts with a fresh context window; prior-loop findings, fix history, and chat stay in the lead.
|
|
155
|
+
The teammate sees only the latest audit’s findings — each `Agent` call starts with a fresh context window; prior-loop findings, fix history, and chat stay in the lead.
|
|
85
156
|
|
|
86
|
-
Pass finding comment URL and id for each finding (from `loop_comment_index`) in the XML prompt so the teammate owns
|
|
157
|
+
Pass finding comment URL, comment id, and thread node id for each finding (from `loop_comment_index`) in the XML prompt so the teammate owns both the reply and the thread resolution. After commit, the teammate posts one reply per finding using the unified template at [`../../../_shared/pr-loop/audit-reply-template.md`](../../../_shared/pr-loop/audit-reply-template.md) — the full header / horizontal rule / `<action_heading> ✅` / explanation / anchored-bullet / closing-paragraph skeleton, with `<status_line>` set per the path (`Fixed in <short_sha>` for `status=fixed`, `Could not address this loop` for `status=could_not_address`, `Hook blocked the fix commit` for `status=hook_blocked`). Per-thread reply and `resolve_thread` are atomic — see [`../../../_shared/pr-loop/fix-protocol.md`](../../../_shared/pr-loop/fix-protocol.md) step 12 for the exact sequence. Same identity model as bugfind: teammate posts; lead waits.
|
|
87
158
|
|
|
88
159
|
After replies, the teammate writes outcome XML (schema in [`../PROMPTS.md`](../PROMPTS.md)).
|
|
89
160
|
|
|
@@ -93,8 +164,10 @@ Same self-termination model as bugfind. Missing notification → hard blocker.
|
|
|
93
164
|
|
|
94
165
|
`approve: false` → `error: bugfix teammate refused shutdown` → Step 4 then 5.
|
|
95
166
|
|
|
96
|
-
Substitute placeholders from `last_findings` into the fix prompt per [`../PROMPTS.md`](../PROMPTS.md).
|
|
167
|
+
Substitute placeholders from `last_findings` into the fix prompt per [`../PROMPTS.md`](../PROMPTS.md). The spawn XML includes TaskCreate/self_audit_checklist for task tracking — the FIX subagent MUST create tasks before starting.
|
|
97
168
|
|
|
98
169
|
**Verify push:** `git rev-parse HEAD` after fix must differ from before; new HEAD must exist on `origin/<branch>` (`git fetch origin <branch> && git rev-parse origin/<branch>` matches `HEAD`). If HEAD did not change → `stuck — bugfix teammate could not address findings`.
|
|
99
170
|
|
|
171
|
+
**Scope verification.** Run `git diff HEAD~1 --name-only` and compare against the set of files referenced in `bugs_to_fix`. When the commit touches files NOT in the `bugs_to_fix` list, judge whether the extras are a coherent part of the fix: a shared helper the auditor did not think to name, a test file that exercises the fix, a config update the fix requires. If the extras are coherent with the fix, note them in the outcome XML's `<scope_notes>` and keep the outcome as `fixed`. If the extras look unrelated, suspicious, or out of scope, downgrade to `unverified_fixed` with reason `commit touched unexpected files: <list>`. The auditor's file list is a default, not a contract — the fix's coherence is the contract.
|
|
172
|
+
|
|
100
173
|
`last_action = "fixed"`. Append fix line to `audit_log`.
|
|
@@ -21,7 +21,7 @@ Each finding an audit produces MUST be one of exactly two shapes.
|
|
|
21
21
|
"id": "loop<L>-<K>",
|
|
22
22
|
"file": "path/relative/to/repo/root.py",
|
|
23
23
|
"line": 123,
|
|
24
|
-
"category": "A | B | C | D | E | F | G | H | I | J",
|
|
24
|
+
"category": "A | B | C | D | E | F | G | H | I | J | K",
|
|
25
25
|
"severity": "P0 | P1 | P2",
|
|
26
26
|
"excerpt": "verbatim code snippet from the offending line(s)",
|
|
27
27
|
"failure_mode": "one sentence describing what goes wrong and when",
|
|
@@ -37,7 +37,7 @@ Used when an audit investigates a category and does NOT find a bug. Bare "verifi
|
|
|
37
37
|
|
|
38
38
|
```json
|
|
39
39
|
{
|
|
40
|
-
"category": "A | B | C | D | E | F | G | H | I | J",
|
|
40
|
+
"category": "A | B | C | D | E | F | G | H | I | J | K",
|
|
41
41
|
"files_opened": ["file1.py", "file2.py"],
|
|
42
42
|
"lines_quoted": [
|
|
43
43
|
{"file": "file1.py", "line": 88, "text": "verbatim line content"}
|
|
@@ -89,25 +89,7 @@ After the primary finding list is complete, every audit runs a second pass again
|
|
|
89
89
|
|
|
90
90
|
The audit must either produce new Shape A findings citing new file:line references not present in the first pass, or cite explicit Shape B adversarial-probe entries for each category it re-examined. An adversarial pass that returns "nothing new, confident first pass was complete" is REJECTED — produce evidence or findings, not confidence.
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
For single-subagent skills (`/qbug`, `/findbugs`) the LEAD spawns two `Agent()` calls in one message:
|
|
95
|
-
|
|
96
|
-
- **Primary** — `subagent_type=clean-coder`, `model=sonnet` (for qbug cycle) or `subagent_type=code-quality-agent`, `model=sonnet` (for findbugs clean-room).
|
|
97
|
-
- **Secondary (Haiku)** — `subagent_type=code-quality-agent`, `model=haiku`, same self-contained clean-room prompt shape used by `/findbugs`.
|
|
98
|
-
|
|
99
|
-
Both audit the same diff. The secondary returns findings to the LEAD only — never posted to the PR.
|
|
100
|
-
|
|
101
|
-
Merge rules:
|
|
102
|
-
|
|
103
|
-
- **De-dup key**: `(file, line, category)`.
|
|
104
|
-
- **Severity conflict**: max wins (P0 > P1 > P2).
|
|
105
|
-
- **Unique-to-Haiku findings**: added to the primary set with Haiku's severity and source annotation.
|
|
106
|
-
- **Unique-to-primary findings**: kept as-is.
|
|
107
|
-
- **Zero Haiku findings**: primary set trusted; proceed.
|
|
108
|
-
- **Malformed or non-parseable Haiku output**: lead trusts the primary set, logs the event in `loop-<L>-diagnostics.json` under `haiku_findings` as `[{"parse_error": "<message>"}]`.
|
|
109
|
-
|
|
110
|
-
For multi-subagent skills (`/bugteam`) the parallel-auditors pattern in [`audit-and-teammates.md`](audit-and-teammates.md) already provides cross-model coverage via 10 haiku auditors + opus validator.
|
|
92
|
+
For `/bugteam`, the single audit agent provides per-category coverage by walking all A–K rubrics in one invocation.
|
|
111
93
|
|
|
112
94
|
## Post-fix self-audit
|
|
113
95
|
|
|
@@ -120,7 +102,7 @@ Sequence:
|
|
|
120
102
|
3. Run `py_compile` (or language-equivalent) on each modified file.
|
|
121
103
|
4. Compute `fix_diff` against pre-fix contents for the modified set.
|
|
122
104
|
5. Run `bugteam_code_rules_gate.py` with explicit paths for every modified file.
|
|
123
|
-
6. Spawn a scoped audit of `fix_diff` with full A–
|
|
105
|
+
6. Spawn a scoped audit of `fix_diff` with full A–K rigor, Shape A/B contract, adversarial pass, AND Haiku secondary in parallel (paranoid mode on post-fix).
|
|
124
106
|
7. Any new findings become same-loop fix-targets. Internal iteration count increments by one.
|
|
125
107
|
8. After 3 internal iterations with fresh findings each time, exit `stuck: post-fix audit not converging`.
|
|
126
108
|
9. Only when `gate_findings` empty AND `post_fix_findings` empty: `git add`, commit, push.
|
|
@@ -155,7 +155,7 @@ Each section names exactly one target file, the literal text or regex to add, an
|
|
|
155
155
|
**Verification step (one line, no `$(...)`):**
|
|
156
156
|
|
|
157
157
|
```
|
|
158
|
-
python
|
|
158
|
+
python $HOME/.claude/skills/bugteam/scripts/bugteam_code_rules_gate.py /tmp/pr70_writer.py /tmp/pr70_summary.py /tmp/pr73_constants.py /tmp/pr73_writer.py
|
|
159
159
|
```
|
|
160
160
|
|
|
161
161
|
Run after the K and L deterministic detectors land in §c/d below; the categories M and N stay rubric-only and are exercised by replaying PR #70 / PR #73 through `/bugteam` with the new PROMPTS.md and observing that the audit posts findings keyed to lines 158 (M), 125 (rubric N — naming clarity), 263 (rubric N — PR-description drift), 361 (initial/final standards review — file length), and 206 (N — wrapper plumb-through).
|
|
@@ -348,7 +348,7 @@ Wire into `run_gate` the same way as Detector 1, by appending its output to `iss
|
|
|
348
348
|
**Verification step:**
|
|
349
349
|
|
|
350
350
|
```
|
|
351
|
-
python
|
|
351
|
+
python $HOME/.claude/skills/bugteam/scripts/bugteam_code_rules_gate.py /tmp/pr70_writer.py /tmp/pr70_summary.py /tmp/pr73_constants.py /tmp/pr73_writer.py /tmp/pr73_tracker.py
|
|
352
352
|
```
|
|
353
353
|
|
|
354
354
|
Expected output after the patch lands: at minimum one `Column-name string magic 'theme_name' - extract to config` line on `pr70_writer.py` (Copilot id 3153098661) and one `Wrapper 'flush' drops optional kwargs ['loud_banner_stream'] of delegate 'flush'` line on `pr73_tracker.py` (Copilot id 3153475331).
|
|
@@ -488,13 +488,16 @@ def check_library_print(content: str, file_path: str) -> list[str]:
|
|
|
488
488
|
all_issues.extend(check_library_print(content, file_path))
|
|
489
489
|
```
|
|
490
490
|
|
|
491
|
-
**Verification step
|
|
491
|
+
**Verification step** — invoke the
|
|
492
|
+
[`probe_code_rules_enforcer_check.py`](../scripts/probe_code_rules_enforcer_check.py)
|
|
493
|
+
script (which dynamically loads `code_rules_enforcer` and runs the named
|
|
494
|
+
detector against a fixture):
|
|
492
495
|
|
|
493
496
|
```
|
|
494
|
-
python
|
|
497
|
+
python "${CLAUDE_SKILL_DIR}/scripts/probe_code_rules_enforcer_check.py" check_collection_prefix /tmp/pr73_constants.py shared_utils/theme_db/config/constants.py
|
|
495
498
|
```
|
|
496
499
|
|
|
497
|
-
Expected output after the patch lands: a list containing `Line 91: Collection constant THEMES_INSERT_REQUIRED_COLUMN_NAMES - prefix with ALL_ (CODE_RULES §5)`. The same command against `/tmp/pr73_writer.py` (Copilot id 3153475297) emits `Line 296: Collection parameter column_value_pairs - prefix with all_ (CODE_RULES §5)`.
|
|
500
|
+
Expected output after the patch lands: a list containing `Line 91: Collection constant THEMES_INSERT_REQUIRED_COLUMN_NAMES - prefix with ALL_ (CODE_RULES §5)`. The same command against `/tmp/pr73_writer.py` (Copilot id 3153475297) emits `Line 296: Collection parameter column_value_pairs - prefix with all_ (CODE_RULES §5)`. Re-running with `check_library_print /tmp/pr70_summary.py shared_utils/theme_db/summary.py` (Copilot id 3153098727) emits at minimum one `Line 256: Library print() - …` line.
|
|
498
501
|
|
|
499
502
|
**Justification for touching `code_rules_enforcer.py`:** the root-cause statement names write-time enforcement as the right layer for collection-prefix and library-print, because both rules in `CODE_RULES.md §5` are mechanical (no judgment), produce concrete fixes, and were the dominant source of follow-up Copilot findings (3 of 8 inventory rows). The bugteam pre-flight gate alone is insufficient — it only fires before each AUDIT, so a clean-coder fix pass that introduces a new violation lives unblocked until the next gate run; write-time enforcement closes that window.
|
|
500
503
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Core principle (expanded)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
One audit agent (`code-quality-agent`, opus) walks all A–K categories per loop. One fix agent (`clean-coder`, opus) addresses the audit's findings.
|
|
6
6
|
|
|
7
7
|
Fresh-spawn clean-room isolation: each `Agent` call creates a new subagent with its own context window and no access to prior conversation. After the subagent writes its outcome XML and self-terminates, the lead reads the file. Results never accumulate in the lead’s context beyond the XML artifact. Verbatim Anthropic quotes and URLs: [`../sources.md`](../sources.md).
|
|
8
8
|
|
|
@@ -12,7 +12,7 @@ The top-of-file list exists so partial reads (for example `head -100`) still sho
|
|
|
12
12
|
|
|
13
13
|
## When `/bugteam` applies (narrative)
|
|
14
14
|
|
|
15
|
-
The user wants automated convergence on a clean PR without babysitting each step. Typed `/bugteam` once means full authorization for up to
|
|
15
|
+
The user wants automated convergence on a clean PR without babysitting each step. Typed `/bugteam` once means full authorization for up to twenty audit cycles and the corresponding fix commits.
|
|
16
16
|
|
|
17
17
|
### Refusal reasons (detail)
|
|
18
18
|
|
|
@@ -1,86 +1,79 @@
|
|
|
1
|
-
# GitHub PR comments
|
|
1
|
+
# GitHub PR comments
|
|
2
2
|
|
|
3
|
-
Per-loop pull-request reviews
|
|
3
|
+
Per-loop pull-request reviews and post-fix replies use two distinct transports:
|
|
4
4
|
|
|
5
|
-
- **Per-loop review** —
|
|
5
|
+
- **Per-loop audit review** — posted via [`post_audit_thread.py`](../../../_shared/pr-loop/scripts/post_audit_thread.py). One review per audit pass. `APPROVE` on CLEAN (the request event; GitHub stores it as `state=APPROVED`; body documents "no findings", zero inline comments). `REQUEST_CHANGES` on DIRTY (one inline anchored comment per finding; each becomes its own resolvable thread).
|
|
6
|
+
- **Fix replies** — posted via the GitHub MCP `add_reply_to_pull_request_comment` after the fix commit lands. The reply body uses the unified template at [`../../../_shared/pr-loop/audit-reply-template.md`](../../../_shared/pr-loop/audit-reply-template.md); reply and `resolve_thread` are atomic per thread.
|
|
6
7
|
|
|
7
|
-
-
|
|
8
|
+
## Per-loop audit review (post_audit_thread.py)
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
Run the script at the end of every audit pass:
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
```
|
|
13
|
+
python "${CLAUDE_SKILL_DIR}/../../_shared/pr-loop/scripts/post_audit_thread.py" \
|
|
14
|
+
--skill bugteam \
|
|
15
|
+
--owner <owner> \
|
|
16
|
+
--repo <repo> \
|
|
17
|
+
--pr-number <N> \
|
|
18
|
+
--commit <head_sha> \
|
|
19
|
+
--state <CLEAN|DIRTY> \
|
|
20
|
+
--findings-json <path>
|
|
21
|
+
```
|
|
12
22
|
|
|
13
|
-
|
|
23
|
+
Capture `<head_sha>` via `git rev-parse HEAD` in the subagent cwd immediately before this call so the review attaches to the commit the audit actually scoped.
|
|
14
24
|
|
|
15
|
-
|
|
25
|
+
`--findings-json` points to a JSON file whose root is a list of objects shaped `{path, line, side, severity, description, fix_summary}`. Build it from the merged Shape A findings: finding `file` → `path`. Each finding's `failure_mode` carries the full audit-to-fix handoff text per [`agents/code-quality-agent.md`](../../../agents/code-quality-agent.md); split `failure_mode` at the literal `Fix:` heading so the failure narrative becomes `description` and the suffix beginning at `Fix:` (including the trailing `Validation:` clause) becomes `fix_summary`. When a finding's `failure_mode` omits the `Fix:` heading, write the full text to BOTH `description` and `fix_summary` so the script's body template (`INLINE_COMMENT_BODY_TEMPLATE` in [`scripts/config/post_audit_thread_constants.py`](../../../_shared/pr-loop/scripts/config/post_audit_thread_constants.py)) renders coherently. Set `side="RIGHT"` for every entry. On CLEAN the list is empty (`[]`); on DIRTY the list carries one entry per finding.
|
|
16
26
|
|
|
17
|
-
|
|
27
|
+
The script handles retries internally — 1s / 4s / 16s backoff across four attempts (one initial plus three retries). Exit codes:
|
|
18
28
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
event="COMMENT",
|
|
23
|
-
body=<review_body_markdown>,
|
|
24
|
-
commitID=<head_sha_at_post_time>,
|
|
25
|
-
owner=<owner>, repo=<repo>, pullNumber=<pull_number>,
|
|
26
|
-
comments=[
|
|
27
|
-
{path: <file_1>, line: <line_1>, side: "RIGHT", body: <finding_1_markdown>}
|
|
28
|
-
[, ... one object per anchored finding ...]
|
|
29
|
-
]
|
|
30
|
-
)
|
|
31
|
-
```
|
|
29
|
+
- `0` — review posted; the new review's `html_url` is on stdout.
|
|
30
|
+
- `1` — user input error (bad arguments, malformed findings JSON, missing template).
|
|
31
|
+
- `2` — retry exhaustion. Hard blocker; the lead exits `error: post_audit_thread retry exhausted` without retrying and without falling back to a flat issue comment.
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Harvest the parent review URL from stdout, then extract the numeric review id from the URL's `#pullrequestreview-<id>` suffix (the trailing URL fragment of `html_url`, the part after `#`). Fetch child-comment URLs via `pull_request_read(method="get_review_comments", owner=<owner>, repo=<repo>, pullNumber=<N>)` filtered to that review id. That same response carries each comment's PR review thread node id (e.g. `PRRT_kwDOxxx`) — capture it alongside the numeric comment id. Match children to findings in the order they appear in the findings JSON, and store the mapping as `loop_comment_index[finding_id]` carrying both `finding_comment_id` (numeric) and `thread_node_id` (`PRRT_kwDOxxx`) for the FIX step to reply against and resolve.
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
The script reads its body skeleton from [`../../../_shared/pr-loop/audit-reply-template.md`](../../../_shared/pr-loop/audit-reply-template.md) at runtime, so the template doc remains the single source of truth for the body shape — edits there propagate without restarting the caller.
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
add_reply_to_pull_request_comment(
|
|
39
|
-
commentId=<finding_comment_id>,
|
|
40
|
-
body=<reply_markdown>,
|
|
41
|
-
owner=<owner>, repo=<repo>, pullNumber=<pull_number>
|
|
42
|
-
)
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### Review POST failure fallback
|
|
37
|
+
## Fix reply (MCP)
|
|
46
38
|
|
|
47
|
-
|
|
39
|
+
After the fix commit lands, post one reply per finding thread and resolve the thread atomically.
|
|
48
40
|
|
|
49
41
|
```
|
|
50
|
-
|
|
51
|
-
owner
|
|
52
|
-
|
|
53
|
-
|
|
42
|
+
mcp__plugin_github_github__add_reply_to_pull_request_comment(
|
|
43
|
+
owner="<owner>",
|
|
44
|
+
repo="<repo>",
|
|
45
|
+
pullNumber=<number>,
|
|
46
|
+
commentId=<finding_comment_id>,
|
|
47
|
+
body="<reply body using unified template>"
|
|
54
48
|
)
|
|
55
49
|
```
|
|
56
50
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
Body text is passed directly as string parameters to the MCP tool calls — no temp files, no jq, no shell pipes.
|
|
51
|
+
The reply body uses the unified template from [`../../../_shared/pr-loop/audit-reply-template.md`](../../../_shared/pr-loop/audit-reply-template.md). Per-status `<status_line>` / `<action_heading>` values live in [`../PROMPTS.md`](../PROMPTS.md) § FIX execution step 8.
|
|
60
52
|
|
|
61
|
-
|
|
53
|
+
Immediately after the reply call returns, resolve the same thread:
|
|
62
54
|
|
|
63
55
|
```
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
<
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
56
|
+
mcp__plugin_github_github__pull_request_review_write(
|
|
57
|
+
method="resolve_thread",
|
|
58
|
+
owner="<owner>",
|
|
59
|
+
repo="<repo>",
|
|
60
|
+
pullNumber=<number>,
|
|
61
|
+
threadId=<thread_node_id>
|
|
62
|
+
)
|
|
70
63
|
```
|
|
71
64
|
|
|
72
|
-
|
|
65
|
+
`<thread_node_id>` is the PR review thread node ID (`PRRT_kwDOxxx`) harvested above when calling `get_review_comments`, distinct from the numeric comment ID used in the reply call. See [obstacles/fix-resolve-thread.md](obstacles/fix-resolve-thread.md) for the full identifier-shape rationale.
|
|
73
66
|
|
|
74
|
-
|
|
67
|
+
The two calls form one atomic per-thread action. Do not yield to the lead between them. Do not batch all replies before any resolves.
|
|
75
68
|
|
|
76
|
-
|
|
69
|
+
## Anchor validation
|
|
77
70
|
|
|
78
|
-
|
|
71
|
+
GitHub's reviews endpoint rejects the entire POST if any inline comment in `comments[]` targets a line not present in the diff at `--commit`. Validate `(path, line)` against the captured diff before adding a finding to the findings JSON. Findings without a diff anchor stay out of the JSON; surface them in the calling skill's user-facing output instead so the audit pass still completes.
|
|
79
72
|
|
|
80
|
-
|
|
73
|
+
## GitHub MCP tools used
|
|
81
74
|
|
|
82
|
-
|
|
75
|
+
- `add_reply_to_pull_request_comment` — fix replies on existing review comments.
|
|
76
|
+
- `pull_request_review_write` (`method="resolve_thread"`) — thread resolution after the reply lands; called atomically with the reply.
|
|
77
|
+
- `pull_request_read` (`method="get_review_comments"`) — harvest child-comment ids/urls after the script's parent review posts.
|
|
83
78
|
|
|
84
|
-
|
|
85
|
-
- Fix reply: `add_reply_to_pull_request_comment(commentId=..., body=..., owner=..., repo=..., pullNumber=...)` — wraps `POST /repos/{owner}/{repo}/pulls/{pull_number}/comments/{comment_id}/replies`
|
|
86
|
-
- Review-POST failure fallback: `add_issue_comment(owner=..., repo=..., issueNumber=..., body=...)` — wraps `POST /repos/{owner}/{repo}/issues/{issue_number}/comments`
|
|
79
|
+
Reference: https://github.com/github/github-mcp-server.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Assign IDs
|
|
2
|
+
|
|
3
|
+
Assign each finding a stable finding_id (loop<L>-<K>), 1-based within loop
|
|
4
|
+
|
|
5
|
+
## Self-population
|
|
6
|
+
|
|
7
|
+
Hit a wall on this step? Spawn a background agent to record it. Keep working.
|
|
8
|
+
|
|
9
|
+
1. Spawn — brief it: check for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
|
|
10
|
+
2. Tell the agent your obstacle and what fixed it. It writes the entry below.
|
|
11
|
+
|
|
12
|
+
## Obstacles
|
|
13
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Capture excerpts
|
|
2
|
+
|
|
3
|
+
Capture verbatim excerpts, validate anchors against diff, split into anchored and unanchored buckets
|
|
4
|
+
|
|
5
|
+
## Self-population
|
|
6
|
+
|
|
7
|
+
Hit a wall on this step? Spawn a background agent to record it. Keep working.
|
|
8
|
+
|
|
9
|
+
1. Spawn — brief it: check for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
|
|
10
|
+
2. Tell the agent your obstacle and what fixed it. It writes the entry below.
|
|
11
|
+
|
|
12
|
+
## Obstacles
|
|
13
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Walk categories
|
|
2
|
+
|
|
3
|
+
Audit every category A through K. Each returns Shape A finding or Shape B verified-clean. No skipped categories.
|
|
4
|
+
|
|
5
|
+
## Self-population
|
|
6
|
+
|
|
7
|
+
Hit a wall on this step? Spawn a background agent to record it. Keep working.
|
|
8
|
+
|
|
9
|
+
1. Spawn `Agent(run_in_background=true)` — brief it: check `jl-cmd/claude-code-config` for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
|
|
10
|
+
2. Tell the agent your obstacle and what fixed it. It writes the entry below.
|
|
11
|
+
|
|
12
|
+
## Obstacles
|
|
13
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Write outcome XML
|
|
2
|
+
|
|
3
|
+
Write outcome XML to worktree path with finding IDs, thread node IDs, and review URL
|
|
4
|
+
|
|
5
|
+
## Self-population
|
|
6
|
+
|
|
7
|
+
Hit a wall on this step? Spawn a background agent to record it. Keep working.
|
|
8
|
+
|
|
9
|
+
1. Spawn — brief it: check for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
|
|
10
|
+
2. Tell the agent your obstacle and what fixed it. It writes the entry below.
|
|
11
|
+
|
|
12
|
+
## Obstacles
|
|
13
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Append summary URL
|
|
2
|
+
|
|
3
|
+
Append fix summary URL to parent review via add_reply_to_pull_request_comment
|
|
4
|
+
|
|
5
|
+
## Self-population
|
|
6
|
+
|
|
7
|
+
Hit a wall on this step? Spawn a background agent to record it. Keep working.
|
|
8
|
+
|
|
9
|
+
1. Spawn — brief it: check for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
|
|
10
|
+
2. Tell the agent your obstacle and what fixed it. It writes the entry below.
|
|
11
|
+
|
|
12
|
+
## Obstacles
|
|
13
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Apply fixes
|
|
2
|
+
|
|
3
|
+
Apply each addressable fix, skip only with explicit reason
|
|
4
|
+
|
|
5
|
+
## Self-population
|
|
6
|
+
|
|
7
|
+
Hit a wall on this step? Spawn a background agent to record it. Keep working.
|
|
8
|
+
|
|
9
|
+
1. Spawn — brief it: check for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
|
|
10
|
+
2. Tell the agent your obstacle and what fixed it. It writes the entry below.
|
|
11
|
+
|
|
12
|
+
## Obstacles
|
|
13
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Git add + commit
|
|
2
|
+
|
|
3
|
+
git add by explicit path, commit with summary, capture hook failures
|
|
4
|
+
|
|
5
|
+
## Self-population
|
|
6
|
+
|
|
7
|
+
Hit a wall on this step? Spawn a background agent to record it. Keep working.
|
|
8
|
+
|
|
9
|
+
1. Spawn — brief it: check for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
|
|
10
|
+
2. Tell the agent your obstacle and what fixed it. It writes the entry below.
|
|
11
|
+
|
|
12
|
+
## Obstacles
|
|
13
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Git push
|
|
2
|
+
|
|
3
|
+
Fast-forward push, no flag overrides
|
|
4
|
+
|
|
5
|
+
## Self-population
|
|
6
|
+
|
|
7
|
+
Hit a wall on this step? Spawn a background agent to record it. Keep working.
|
|
8
|
+
|
|
9
|
+
1. Spawn — brief it: check for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
|
|
10
|
+
2. Tell the agent your obstacle and what fixed it. It writes the entry below.
|
|
11
|
+
|
|
12
|
+
## Obstacles
|
|
13
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Post fix replies
|
|
2
|
+
|
|
3
|
+
Post fix reply on each finding comment thread via add_reply_to_pull_request_comment
|
|
4
|
+
|
|
5
|
+
## Self-population
|
|
6
|
+
|
|
7
|
+
Hit a wall on this step? Spawn a background agent to record it. Keep working.
|
|
8
|
+
|
|
9
|
+
1. Spawn — brief it: check for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
|
|
10
|
+
2. Tell the agent your obstacle and what fixed it. It writes the entry below.
|
|
11
|
+
|
|
12
|
+
## Obstacles
|
|
13
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Publish fix summary
|
|
2
|
+
|
|
3
|
+
Publish fix summary HTML via /doc-gist with commit SHA, files, per-fix descriptions
|
|
4
|
+
|
|
5
|
+
## Self-population
|
|
6
|
+
|
|
7
|
+
Hit a wall on this step? Spawn a background agent to record it. Keep working.
|
|
8
|
+
|
|
9
|
+
1. Spawn — brief it: check for an open PR touching this file, add a commit to it, or create a fresh branch + worktree + draft PR.
|
|
10
|
+
2. Tell the agent your obstacle and what fixed it. It writes the entry below.
|
|
11
|
+
|
|
12
|
+
## Obstacles
|
|
13
|
+
|