claude-dev-env 1.92.1 → 1.93.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.
Files changed (214) hide show
  1. package/CLAUDE.md +6 -2
  2. package/_shared/CLAUDE.md +2 -1
  3. package/_shared/advisor/CLAUDE.md +21 -0
  4. package/_shared/advisor/advisor-protocol.md +142 -0
  5. package/_shared/advisor/scripts/config/advisor_scripts_constants/__init__.py +1 -0
  6. package/_shared/advisor/scripts/config/advisor_scripts_constants/model_tier_run_validator_constants.py +86 -0
  7. package/_shared/advisor/scripts/model_tier_run_validator.py +246 -0
  8. package/_shared/advisor/scripts/pyproject.toml +3 -0
  9. package/_shared/advisor/scripts/tests/test_model_tier_run_validator.py +302 -0
  10. package/_shared/advisor/scripts/tests/test_tier_model_ids.py +180 -0
  11. package/_shared/advisor/scripts/tier_model_ids.py +164 -0
  12. package/_shared/pr-loop/CLAUDE.md +1 -0
  13. package/_shared/pr-loop/precatch-rubric.md +65 -0
  14. package/_shared/pr-loop/scripts/CLAUDE.md +1 -1
  15. package/_shared/pr-loop/scripts/code_rules_gate.py +137 -5
  16. package/_shared/pr-loop/scripts/post_audit_thread.py +1 -1
  17. package/_shared/pr-loop/scripts/pr_loop_shared_constants/CLAUDE.md +1 -1
  18. package/_shared/pr-loop/scripts/pr_loop_shared_constants/code_rules_gate_constants.py +16 -0
  19. package/_shared/pr-loop/scripts/pr_loop_shared_constants/reviews_disabled_constants.py +2 -1
  20. package/_shared/pr-loop/scripts/reviewer_availability.py +42 -12
  21. package/_shared/pr-loop/scripts/reviews_disabled.py +65 -21
  22. package/_shared/pr-loop/scripts/terminology_sweep.py +69 -21
  23. package/_shared/pr-loop/scripts/tests/CLAUDE.md +1 -1
  24. package/_shared/pr-loop/scripts/tests/fixtures/{copilot_internal_user_jonecho.json → copilot_internal_user_example.json} +1 -1
  25. package/_shared/pr-loop/scripts/tests/test_agent_config_carveout.py +1 -1
  26. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +146 -2
  27. package/_shared/pr-loop/scripts/tests/test_copilot_quota.py +8 -8
  28. package/_shared/pr-loop/scripts/tests/test_reviewer_availability.py +18 -5
  29. package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +56 -5
  30. package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +104 -17
  31. package/agents/CLAUDE.md +3 -2
  32. package/agents/clasp-deployment-orchestrator.md +2 -2
  33. package/agents/code-advisor.md +7 -5
  34. package/agents/code-verifier.md +6 -2
  35. package/agents/session-advisor.md +27 -0
  36. package/audit-rubrics/category_rubrics/category-j-code-rules-compliance.md +1 -1
  37. package/audit-rubrics/category_rubrics/category-k-codebase-conflicts.md +1 -1
  38. package/audit-rubrics/prompts/category-a-api-contracts.md +2 -2
  39. package/audit-rubrics/prompts/category-b-selector-engine-compat.md +2 -2
  40. package/audit-rubrics/prompts/category-c-resource-cleanup.md +2 -2
  41. package/audit-rubrics/prompts/category-d-scoping-and-ordering.md +2 -2
  42. package/audit-rubrics/prompts/category-e-dead-code.md +2 -2
  43. package/audit-rubrics/prompts/category-f-silent-failures.md +2 -2
  44. package/audit-rubrics/prompts/category-g-bounds-and-overflow.md +2 -2
  45. package/audit-rubrics/prompts/category-h-security-boundaries.md +2 -2
  46. package/audit-rubrics/prompts/category-i-concurrency.md +2 -2
  47. package/audit-rubrics/prompts/category-j-code-rules-compliance.md +2 -2
  48. package/audit-rubrics/prompts/category-k-codebase-conflicts.md +2 -2
  49. package/audit-rubrics/prompts/category-l-behavior-equivalence.md +2 -2
  50. package/audit-rubrics/prompts/category-m-producer-consumer-cardinality.md +2 -2
  51. package/audit-rubrics/prompts/category-n-test-name-scenario-verifier.md +2 -2
  52. package/audit-rubrics/prompts/category-o-docstring-vs-impl-drift.md +2 -2
  53. package/audit-rubrics/prompts/category-p-name-vs-behavior-contract.md +2 -2
  54. package/bin/CLAUDE.md +1 -0
  55. package/bin/expand_home_directory_tokens.mjs +75 -0
  56. package/bin/install.mjs +21 -7
  57. package/bin/install.test.mjs +220 -10
  58. package/hooks/CLAUDE.md +1 -1
  59. package/hooks/blocking/CLAUDE.md +4 -1
  60. package/hooks/blocking/_path_setup.py +13 -0
  61. package/hooks/blocking/bash_pre_tool_use_dispatcher.py +281 -0
  62. package/hooks/blocking/code_rules_dead_module_constant.py +88 -16
  63. package/hooks/blocking/code_rules_enforcer.py +6 -0
  64. package/hooks/blocking/code_rules_imports_logging.py +34 -1
  65. package/hooks/blocking/code_rules_paths_syspath.py +1 -1
  66. package/hooks/blocking/code_rules_test_layout.py +272 -0
  67. package/hooks/blocking/nas_ssh_binary_enforcer.py +22 -12
  68. package/hooks/blocking/pii_prevention_blocker.py +781 -0
  69. package/hooks/blocking/pii_scanner.py +340 -0
  70. package/hooks/blocking/pre_tool_use_dispatcher.py +3 -3
  71. package/hooks/blocking/stop_dispatcher.py +84 -0
  72. package/hooks/blocking/test__path_setup.py +39 -0
  73. package/hooks/blocking/test_bash_dispatcher_interpreter_starts.py +61 -0
  74. package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +294 -0
  75. package/hooks/blocking/test_code_rules_enforcer_cross_skill_duplicate.py +1 -1
  76. package/hooks/blocking/test_code_rules_enforcer_dead_module_constant.py +51 -0
  77. package/hooks/blocking/test_code_rules_enforcer_dead_module_constant_read_cap.py +103 -0
  78. package/hooks/blocking/test_code_rules_enforcer_dot_test_pattern.py +1 -1
  79. package/hooks/blocking/test_code_rules_enforcer_file_global_constants.py +1 -1
  80. package/hooks/blocking/test_code_rules_enforcer_hardcoded_user_path.py +11 -11
  81. package/hooks/blocking/test_code_rules_enforcer_naive_datetime.py +1 -1
  82. package/hooks/blocking/test_code_rules_enforcer_same_file_inline_duplicate.py +1 -1
  83. package/hooks/blocking/test_code_rules_enforcer_test_layout.py +111 -0
  84. package/hooks/blocking/test_code_rules_enforcer_type_checking_scope.py +76 -0
  85. package/hooks/blocking/test_destructive_command_blocker.py +29 -9
  86. package/hooks/blocking/test_gh_body_arg_blocker.py +3 -3
  87. package/hooks/blocking/test_nas_ssh_binary_enforcer.py +96 -39
  88. package/hooks/blocking/test_pii_prevention_blocker.py +905 -0
  89. package/hooks/blocking/test_pii_prevention_windows_git_path.py +41 -0
  90. package/hooks/blocking/test_pii_scanner.py +165 -0
  91. package/hooks/blocking/test_pr_description_enforcer_pr_number.py +1 -1
  92. package/hooks/blocking/test_pre_tool_use_dispatcher.py +14 -13
  93. package/hooks/blocking/test_stop_dispatcher.py +187 -0
  94. package/hooks/blocking/test_verdict_directory_write_blocker.py +1 -1
  95. package/hooks/blocking/test_volatile_path_in_post_blocker.py +3 -3
  96. package/hooks/blocking/volatile_path_in_post_blocker.py +54 -5
  97. package/hooks/diagnostic/migrations/README.md +25 -26
  98. package/hooks/diagnostic/test_hook_log_extractor.py +10 -10
  99. package/hooks/hooks.json +10 -120
  100. package/hooks/hooks_constants/CLAUDE.md +12 -3
  101. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +78 -0
  102. package/hooks/hooks_constants/dead_module_constant_constants.py +1 -0
  103. package/hooks/hooks_constants/hosted_hook_runner.py +73 -0
  104. package/hooks/hooks_constants/local_identity.py +182 -0
  105. package/hooks/hooks_constants/nas_ssh_binary_enforcer_constants.py +4 -37
  106. package/hooks/hooks_constants/pii_prevention_constants.py +299 -0
  107. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +4 -0
  108. package/hooks/hooks_constants/python_style_checks_constants.py +15 -0
  109. package/hooks/hooks_constants/stop_dispatcher_constants.py +26 -0
  110. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +87 -0
  111. package/hooks/hooks_constants/test_hardcoded_user_path_constants.py +2 -2
  112. package/hooks/hooks_constants/test_hosted_hook_runner.py +101 -0
  113. package/hooks/hooks_constants/test_layout_constants.py +28 -0
  114. package/hooks/hooks_constants/test_local_identity.py +88 -0
  115. package/hooks/hooks_constants/test_session_env_cleanup_constants.py +1 -1
  116. package/hooks/hooks_constants/test_stop_dispatcher_constants.py +32 -0
  117. package/hooks/validators/README.md +5 -6
  118. package/hooks/validators/__init__.py +2 -2
  119. package/hooks/validators/python_style_checks.py +298 -243
  120. package/hooks/validators/run_all_validators.py +6 -0
  121. package/hooks/validators/test_python_style_checks.py +278 -163
  122. package/package.json +2 -2
  123. package/rules/CLAUDE.md +2 -1
  124. package/rules/bdd.md +1 -1
  125. package/rules/nas-ssh-invocation.md +6 -4
  126. package/rules/no-justification-noise.md +61 -0
  127. package/scripts/test_setup_project_paths.py +1 -1
  128. package/skills/CLAUDE.md +6 -3
  129. package/skills/_shared/pr-loop/scripts/_path_resolver.py +2 -2
  130. package/skills/_shared/pr-loop/scripts/build_audit_prompt.py +1 -1
  131. package/skills/_shared/pr-loop/scripts/build_fix_prompt.py +1 -1
  132. package/skills/_shared/pr-loop/scripts/test__path_resolver.py +42 -3
  133. package/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +11 -11
  134. package/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +26 -3
  135. package/skills/_shared/pr-loop/scripts/test_preflight_worktree.py +49 -25
  136. package/skills/autoconverge/CLAUDE.md +3 -3
  137. package/skills/autoconverge/SKILL.md +113 -35
  138. package/skills/autoconverge/reference/CLAUDE.md +2 -2
  139. package/skills/autoconverge/reference/convergence.md +44 -22
  140. package/skills/autoconverge/reference/gotchas.md +11 -0
  141. package/skills/autoconverge/reference/stop-conditions.md +23 -13
  142. package/skills/autoconverge/workflow/CLAUDE.md +2 -1
  143. package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +15 -19
  144. package/skills/autoconverge/workflow/converge.contract.test.mjs +43 -42
  145. package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +141 -16
  146. package/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +2 -2
  147. package/skills/autoconverge/workflow/converge.mjs +329 -68
  148. package/skills/autoconverge/workflow/converge.path-aware.test.mjs +1 -1
  149. package/skills/autoconverge/workflow/converge.precatch.test.mjs +152 -0
  150. package/skills/autoconverge/workflow/converge.run-input.test.mjs +3 -3
  151. package/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +15 -15
  152. package/skills/autoconverge/workflow/test_convergence_summary.py +6 -6
  153. package/skills/bdd-protocol/SKILL.md +4 -5
  154. package/skills/bdd-protocol/references/anti-patterns.md +1 -1
  155. package/skills/bugteam/SKILL.md +8 -0
  156. package/skills/bugteam/reference/copilot-gap-analysis.md +20 -20
  157. package/skills/bugteam/reference/obstacles/audit-walk-categories.md +1 -1
  158. package/skills/bugteam/reference/team-setup.md +7 -5
  159. package/skills/bugteam/scripts/reflow_skill_md.py +1 -1
  160. package/skills/copilot-finding-triage/SKILL.md +124 -0
  161. package/skills/copilot-finding-triage/reference/tier-rubric.md +49 -0
  162. package/skills/copilot-finding-triage/scripts/conftest.py +8 -0
  163. package/skills/copilot-finding-triage/scripts/copilot_finding_triage_constants/__init__.py +0 -0
  164. package/skills/copilot-finding-triage/scripts/copilot_finding_triage_constants/config/__init__.py +0 -0
  165. package/skills/copilot-finding-triage/scripts/copilot_finding_triage_constants/config/notify_ntfy_constants.py +32 -0
  166. package/skills/copilot-finding-triage/scripts/notify_ntfy.py +192 -0
  167. package/skills/copilot-finding-triage/scripts/test_notify_ntfy.py +141 -0
  168. package/skills/copilot-finding-triage/templates/notification.md +34 -0
  169. package/skills/copilot-review/SKILL.md +8 -6
  170. package/skills/findbugs/SKILL.md +4 -0
  171. package/skills/fixbugs/SKILL.md +8 -7
  172. package/skills/gotcha/CLAUDE.md +2 -2
  173. package/skills/gotcha/SKILL.md +4 -4
  174. package/skills/log-audit/SKILL.md +4 -6
  175. package/skills/monitor-open-prs/CLAUDE.md +1 -1
  176. package/skills/monitor-open-prs/SKILL.md +6 -1
  177. package/skills/orchestrator/SKILL.md +74 -78
  178. package/skills/orchestrator-refresh/SKILL.md +24 -12
  179. package/skills/post-audit-findings/SKILL.md +5 -9
  180. package/skills/pr-consistency-audit/SKILL.md +5 -1
  181. package/skills/pr-converge/CLAUDE.md +1 -1
  182. package/skills/pr-converge/SKILL.md +86 -47
  183. package/skills/pr-converge/reference/CLAUDE.md +1 -1
  184. package/skills/pr-converge/reference/convergence-gates.md +20 -17
  185. package/skills/pr-converge/reference/examples.md +63 -47
  186. package/skills/pr-converge/reference/fix-protocol.md +15 -15
  187. package/skills/pr-converge/reference/ground-rules.md +11 -7
  188. package/skills/pr-converge/reference/multi-pr-orchestration.md +6 -5
  189. package/skills/pr-converge/reference/per-tick.md +129 -107
  190. package/skills/pr-converge/reference/state-schema.md +15 -10
  191. package/skills/pr-converge/scripts/check_convergence.py +5 -4
  192. package/skills/pr-converge/scripts/test_check_convergence.py +6 -4
  193. package/skills/pr-fix-protocol/SKILL.md +3 -8
  194. package/skills/pr-loop-cloud-transport/SKILL.md +102 -0
  195. package/skills/pr-loop-cloud-transport/reference/identity-and-hooks.md +40 -0
  196. package/skills/pr-loop-cloud-transport/reference/substitution-matrix.md +48 -0
  197. package/skills/pr-loop-lifecycle/SKILL.md +5 -9
  198. package/skills/pr-scope-resolve/SKILL.md +3 -6
  199. package/skills/privacy-hygiene/SKILL.md +114 -0
  200. package/skills/qbug/SKILL.md +8 -8
  201. package/skills/rebase/SKILL.md +5 -1
  202. package/skills/refine/SKILL.md +4 -5
  203. package/skills/reviewer-gates/SKILL.md +7 -11
  204. package/skills/session-log/SKILL.md +4 -1
  205. package/skills/skill-builder/SKILL.md +3 -6
  206. package/skills/structure-prompt/SKILL.md +4 -5
  207. package/skills/team-advisor/SKILL.md +56 -0
  208. package/skills/test_markdown_link_integrity.py +10 -6
  209. package/skills/update/SKILL.md +5 -1
  210. package/skills/usage-pause/SKILL.md +14 -5
  211. package/skills/usage-pause/scripts/resolve_usage_window.py +83 -5
  212. package/skills/usage-pause/scripts/test_resolve_usage_window.py +185 -17
  213. package/skills/usage-pause/scripts/usage_pause_constants/resolve_usage_window_constants.py +4 -3
  214. package/skills/verified-build/SKILL.md +4 -9
@@ -1,13 +1,12 @@
1
1
  ---
2
2
  name: autoconverge
3
3
  description: >-
4
- Drives one draft PR to convergence in a single autonomous workflow run.
5
- Each round runs Cursor Bugbot, a code-review pass, and a bug-audit in
6
- parallel on the same HEAD, dedups findings, applies every fix in one
7
- commit, re-verifies, then clears a Copilot wait-gate and a closing
8
- convergence check before marking the PR ready. Use when the user says
9
- '/autoconverge', 'autoconverge this PR', 'converge this PR in one run',
10
- 'run the converge workflow', or 'drive the PR to ready autonomously'.
4
+ Drives one draft PR to convergence in one autonomous run: a deterministic static
5
+ sweep, then code review, bug audit, and self-review on one HEAD, all fixes in one
6
+ commit, then Bugbot and Copilot as terminal confirmation gates before ready.
7
+ Use when the user says '/autoconverge', 'autoconverge this PR', 'converge this
8
+ PR in one run', 'run the converge workflow', or 'drive the PR to ready
9
+ autonomously'.
11
10
  ---
12
11
 
13
12
  # Autoconverge
@@ -46,6 +45,19 @@ Scan the tool list at the top of this conversation for the literal string
46
45
  aborting` and stop. The workflow also needs the `gh` CLI authenticated for the
47
46
  PR's owner.
48
47
 
48
+ ## Transport check (before any GitHub step)
49
+
50
+ Run `command -v gh`; when it succeeds, run `gh auth status`; once the PR
51
+ scope is resolved, run `gh api repos/<owner>/<repo> --jq .permissions.push`
52
+ and take `true` as the pass. When any check fails, run the
53
+ `pr-loop-cloud-transport` skill first and route every `gh` operation in this
54
+ skill through its substitution matrix. The workflow script
55
+ (`workflow/converge.mjs`) embeds `gh` commands and gh-backed helper scripts in
56
+ its agent prompts, so a cloud run also applies the same substitution to those
57
+ agent prompts when it authors the launch — the transport skill covers the
58
+ orchestrating session's own steps, and the script's agent-prompt text carries
59
+ `gh` calls the spawned agents cannot run in a cloud session.
60
+
49
61
  ## Pre-flight (main session)
50
62
 
51
63
  1. **Enter a worktree.** Call `EnterWorktree` with no arguments before any
@@ -80,7 +92,7 @@ PR's owner.
80
92
  enter the branch worktree. A non-zero exit prints a `PREFLIGHT_OUTCOME` line
81
93
  and an `ABORT` line: report that line and stop. Autoconverge runs inside the
82
94
  PR's own repo, so a working directory rooted in a different repo (for
83
- example, `claude-code-config` while the PR lives in `llm-settings`) or in no
95
+ example, `claude-dev-env` while the PR lives in `llm-settings`) or in no
84
96
  git checkout at all cannot continue.
85
97
 
86
98
  4. **Grant project permissions.** Apply the `pr-loop-lifecycle` skill's Open
@@ -129,13 +141,40 @@ Write it again when the result lands, so the handoff carries the final run id an
129
141
  names the teardown phase the fresh session picks up from.
130
142
 
131
143
  The workflow returns
132
- `{ converged, rounds, finalSha, blocker, standardsNote, copilotNote, reuseNote, deferredPrs }`.
144
+ `{ converged, rounds, finalSha, blocker, standardsNote, copilotNote, reuseNote, deferredPrs }`,
145
+ plus a `userReview` field on a `blocker: "user-review"` return.
133
146
  `deferredPrs` is the list of draft environment-hardening PRs the standards-deferral
134
147
  path opened this run, each as `{ owner, repo, prNumber, copilotDisabled, bugbotDisabled }`.
135
148
  The two flags carry this run's Copilot and Bugbot availability, so the next generation
136
149
  skips a reviewer that is down or out of quota without re-probing. This list is the seed the
137
150
  [self-closing loop](#self-closing-loop-converge-the-deferred-prs) converges next.
138
151
 
152
+ ## Copilot findings — two-tier triage
153
+
154
+ The Copilot gate tiers each finding it surfaces. A **self-healing** finding is
155
+ pure style, type hints, misplaced or unused imports, formatting, magic-value
156
+ extraction, a test-only change, a doc-or-description vs code mismatch, or code
157
+ de-duplication — a fix that cannot change observable runtime behavior for
158
+ production callers. Self-healing findings flow into the fix round and count
159
+ toward convergence, with no user notification.
160
+
161
+ A **code-concern** finding is behavior-changing or needs a product decision:
162
+ logic or correctness, security, data handling, error-handling semantics, or
163
+ concurrency. Copilot tiers a finding as code-concern whenever the tier is in
164
+ doubt. When one or more code-concern findings land, the workflow neither
165
+ auto-fixes them nor marks the PR ready. It returns `converged: false`,
166
+ `blocker: "user-review"`, and a `userReview` field carrying
167
+ `{ reviewUrl, findings: [{ file, line, severity, tier, title }] }`.
168
+
169
+ A background workflow cannot hold for a human, so the wait belongs to the
170
+ orchestrating session. On a `blocker: "user-review"` return, run the
171
+ [`copilot-finding-triage`](../copilot-finding-triage/SKILL.md) skill: send the
172
+ ntfy notification (the finding summary plus the `reviewUrl` Copilot review link),
173
+ then hold with a 45-minute `ScheduleWakeup` for the user's response. When the
174
+ user answers within the window, follow their direction. When the window closes
175
+ with no response, run normal teardown and report the code-concern findings
176
+ un-reviewed.
177
+
139
178
  ## Budget-aware round boundaries
140
179
 
141
180
  The workflow's `budget` API is the pacing signal: when a usage target is
@@ -173,6 +212,25 @@ On teardown entry, when `~/.claude/runtime/pr-loop/bugteam-pr-<N>/handoff.json`
173
212
  exists, read its `completed_steps` and skip any checkpoint the list already
174
213
  names, so a resumed run performs only the checkpoints left.
175
214
 
215
+ On a `blocker: "user-review"` return, run the
216
+ [`copilot-finding-triage`](../copilot-finding-triage/SKILL.md) gate before
217
+ teardown: send the ntfy alert with the finding summary and the
218
+ `userReview.reviewUrl` link, then hold with a 45-minute `ScheduleWakeup`. Act on
219
+ the user's direction when it arrives inside the window; when the window closes
220
+ with no response, fall through to normal teardown and report the
221
+ `userReview.findings` un-reviewed. The PR stays a draft in this path — the
222
+ workflow marked nothing ready.
223
+
224
+ Before the checkpoints, when the workflow returned a non-null `copilotNote`
225
+ (the Copilot gate was bypassed), query the PR's reviews once more for a
226
+ `copilot-pull-request-reviewer[bot]` review on the final HEAD
227
+ (`fetch_copilot_reviews.py`, or the GitHub MCP `pull_request_read` method
228
+ `get_reviews`). Copilot typically posts within 10–15 minutes of a request, so
229
+ a review can land between the bypass and teardown. When one exists and
230
+ carries findings, mark the PR draft, route the findings through one fix
231
+ round per the `pr-fix-protocol` skill, re-verify, push, and mark the PR
232
+ ready again — then run the checkpoints.
233
+
176
234
  1. **When `converged` is true — build and publish the closing report.**
177
235
  Skip this entire step (report, artifact publish, comment, Chrome open) when the
178
236
  workflow returned a non-null `blocker`. Per-round live-dashboard refresh is out of
@@ -300,9 +358,13 @@ Every agent prompt carries a headless-safety preamble: the run is unattended, so
300
358
  agents never inline a destructive-command literal (`rm -rf`, `git reset --hard`,
301
359
  `dd`) into a Bash command — the `destructive_command_blocker` hook matches those
302
360
  patterns as raw text, and a confirmation prompt no human can answer would stall
303
- the run. Agents verify destructive-blocker behavior through the committed test
304
- suite (`python -m pytest`) and keep scratch work in the OS temp dir. The preamble
305
- describes the narrowest rm auto-allow patha standalone Bash call whose target
361
+ the run. The preamble has two forms. Read-only agents the review, verify, and
362
+ utility spawns that edit nothing receive a trimmed form that drops the rm-shape
363
+ rules, since a read-only agent never runs `rm`. Edit agentsthe fix and commit
364
+ spawns — receive the full form that carries the rm-shape rules described below.
365
+ Agents verify destructive-blocker behavior through the committed test
366
+ suite (`python -m pytest`) and keep scratch work in the OS temp dir. The full
367
+ preamble describes the narrowest rm auto-allow path — a standalone Bash call whose target
306
368
  resolves inside the ephemeral namespace (`/tmp`, `/temp`, the OS temp root, or the
307
369
  run worktree) — and a compound path that accepts an rm joined with benign
308
370
  reporting segments when every rm target is an absolute ephemeral path. Both of
@@ -323,36 +385,52 @@ helper file and run it as `python <file>.py` — keeping every destructive liter
323
385
  out of a Bash command string entirely and independent of which auto-allow path
324
386
  matches.
325
387
 
326
- - **Converge:** `parallel([Bugbot lens, code-review lens, bug-audit lens])` on
327
- the current HEAD, full `origin/main...HEAD` diff. The preflight step fetches
328
- `origin/main` once for the round and enumerates the diff (changed-file list plus
329
- diffstat); each lens receives that list and reads only the files it needs rather
330
- than re-deriving the diff, forming its own review judgment. Dedup findings; one
331
- `clean-coder` applies the round's fixes per the `pr-fix-protocol` skill
332
- (`../pr-fix-protocol/SKILL.md`) fix, reply, resolve landing every fix in
333
- one commit per round, which the workflow journal records; re-verify next
334
- round on the new HEAD. Every edit step ends with a pre-commit gate check:
335
- before its turn ends, the fixer dry-runs the CODE_RULES commit gate
336
- (`code_rules_gate.py --staged`) and keeps fixing until that gate would accept
337
- the commit it makes no commit itself. When all three are clean on a stable
338
- HEAD, post the CLEAN bugteam audit artifact.
388
+ - **Static sweep:** each round opens with a deterministic static-sweep lens that
389
+ runs the CODE_RULES gate (`code_rules_gate.py --base origin/main`), `ruff`,
390
+ `mypy`, and stem-matched `pytest` over the changed files. Any failure routes
391
+ through the same fix flow and the round re-runs, so the reading lenses only ever
392
+ review sweep-clean code. The sweep uses local commands only, so it runs in any
393
+ session.
394
+ - **Converge:** `parallel([code-review lens, bug-audit lens, self-review lens])`
395
+ on the current HEAD, full `origin/main...HEAD` diff. The bug-audit lens applies
396
+ the A-P rubric and then its adversarial second pass; the self-review lens covers
397
+ the doc-vs-code parity, test-assertion completeness, and PR-description-vs-diff
398
+ parity lanes. The preflight step fetches `origin/main` once for the round and
399
+ enumerates the diff (changed-file list plus diffstat); each lens receives that
400
+ list and reads only the files it needs rather than re-deriving the diff, forming
401
+ its own review judgment. Dedup findings; one `clean-coder` applies the round's
402
+ fixes per the `pr-fix-protocol` skill (`../pr-fix-protocol/SKILL.md`) — fix,
403
+ reply, resolve — landing every fix in one commit per round, which the workflow
404
+ journal records; re-verify next round on the new HEAD. Every edit step ends with
405
+ a pre-commit gate check: before its turn ends, the fixer dry-runs the CODE_RULES
406
+ commit gate (`code_rules_gate.py --staged`) and keeps fixing until that gate
407
+ would accept the commit — it makes no commit itself. When all three internal
408
+ lenses are clean on a stable HEAD, post the CLEAN bugteam audit artifact.
339
409
  A round whose findings are ALL code-standard violations (pure CODE_RULES/style,
340
410
  no behavioral impact) passes for convergence purposes: the workflow files a
341
411
  follow-up issue listing the findings, opens a draft environment-hardening PR
342
412
  (hooks/rules that block those violation classes at Write/Edit time), resolves
343
413
  any bot threads with a deferral note, and reports the deferral in
344
414
  `standardsNote`.
345
- - **Copilot gate:** request a Copilot review, poll up to the configured cap; findings
346
- route back into Converge. When Copilot is down or out of quota it posts an
347
- out-of-usage notice (the requester hit their quota) on the HEAD, or surfaces no
348
- review at all after the configured cap the gate logs a notice and the run marks the PR
349
- ready with the Copilot gate bypassed. `copilotNote` records the bypass.
415
+ - **Bugbot gate:** the terminal Cursor Bugbot confirmation gate runs once the
416
+ internal lenses are clean. When Bugbot is disabled or opted out for the run (the
417
+ default) or unreachable, the gate spawns no agent and passes straight to the
418
+ Copilot gate. Otherwise it fetches Bugbot's verdict on the HEAD; findings route
419
+ back into Converge, and a clean verdict advances to the Copilot gate.
420
+ - **Copilot gate:** the terminal GitHub Copilot confirmation gate. Request a
421
+ Copilot review, poll up to the configured cap; findings route back into
422
+ Converge. When Copilot is down or out of quota — it posts an out-of-usage notice
423
+ (the requester hit their quota) on the HEAD, or surfaces no review at all after
424
+ the configured cap — the gate logs a notice and the run marks the PR ready with
425
+ the Copilot gate bypassed. `copilotNote` records the bypass.
350
426
  - **Convergence check:** `check_convergence.py` is the authoritative gate; one
351
427
  agent runs it and, on a full pass, marks `draft=false` in the same turn. Each
352
- spawned agent runs on the model tier its role needs — opus/medium for the review
353
- lenses and the code-editing fix steps, sonnet/medium for the verify, commit, and
354
- recovery steps, haiku/low for the mechanical probes (preflight, Copilot gate,
355
- CLEAN-audit post, convergence check).
428
+ spawned agent runs on the model tier its role needs — sonnet/medium for the
429
+ deterministic static sweep, opus/medium for the code-review, bug-audit,
430
+ self-review, reuse, and terminal Bugbot lenses and the code-editing fix steps,
431
+ sonnet/medium for the verify, commit, and recovery steps, and haiku/low for the
432
+ mechanical probes (preflight, Copilot gate, CLEAN-audit post, convergence
433
+ check).
356
434
 
357
435
  ## Multiple PRs
358
436
 
@@ -471,7 +549,7 @@ so there is nothing to converge. Report that and stop.
471
549
  Given a non-empty list of deferred PRs `{ owner, repo, prNumber, copilotDisabled, bugbotDisabled }`
472
550
  (a generation may span more than one repository — a hardening PR lands in whichever repo owns
473
551
  the surface that blocks the deferred class, so `JonEcho/llm-settings` for hooks
474
- and `jl-cmd/claude-code-config` for rules and skills both appear):
552
+ and `jl-cmd/claude-dev-env` for rules and skills both appear):
475
553
 
476
554
  1. **Check out each deferred PR.** Run the
477
555
  [Multi-PR pre-flight](#multi-pr-pre-flight-main-session) once per deferred PR.
@@ -6,7 +6,7 @@ Reference documentation for the `autoconverge` skill. The `converge.mjs` workflo
6
6
 
7
7
  | File | Role |
8
8
  |---|---|
9
- | `convergence.md` | Round shape: the three parallel lenses (Bugbot, code-review, bug-audit), deduplication, the fix commit step, and the definition of a clean convergence. |
10
- | `stop-conditions.md` | Every condition that ends the run short of ready: budget cap, iteration cap, blocker exit, Copilot bypass. |
9
+ | `convergence.md` | Round shape: the static sweep, the three parallel internal lenses (code-review, bug-audit, self-review), deduplication, the fix commit step, the terminal Bugbot and Copilot gates, and the definition of a clean convergence. |
10
+ | `stop-conditions.md` | Every condition that ends the run short of ready: budget cap, iteration cap, blocker exit, static-sweep stall, Bugbot and Copilot bypass. |
11
11
  | `gotchas.md` | Hard-won lessons from failed runs: PR title validation, conflicting PRs, worktree branch lock, resumed sessions rerooting, and minter issues. |
12
12
  | `closing-report.md` | Specification for the closing HTML convergence report the teardown step builds and publishes. |
@@ -39,34 +39,45 @@ any improvement that did not land.
39
39
 
40
40
  ## The round loop
41
41
 
42
- The workflow holds three states and moves between them until the PR is ready or
42
+ The workflow holds four states and moves between them until the PR is ready or
43
43
  a blocker ends the run. A single iteration counter increments on every pass
44
44
  through any phase and caps the whole run at 20 loop iterations; the round counter
45
- tracks CONVERGE passes only and is never the cap.
45
+ tracks CONVERGE passes only and is never the cap. The internal lenses drive the
46
+ code to clean first; the external reviewers run only after that, as terminal
47
+ confirmation gates that are expected to return zero.
46
48
 
47
- **CONVERGE** (one round = one parallel sweep):
49
+ **CONVERGE** (one round = a static sweep then one parallel lens sweep):
48
50
 
49
51
  1. Resolve the current PR HEAD SHA. The same preflight step also fetches
50
52
  `origin/main` once for the round and enumerates the diff — the
51
53
  `git diff --name-status origin/main...HEAD` changed-file list and the
52
54
  `git diff --stat` diffstat — and carries both into the round.
53
- 2. Run three lenses in parallel on that HEAD, each over the full
55
+ 2. Run the **static-sweep lens** on that HEAD: a deterministic pass that runs the
56
+ CODE_RULES gate (`code_rules_gate.py --base origin/main`), `ruff`, `mypy`, and
57
+ stem-matched `pytest` over the changed files, mapping each failure to a
58
+ finding. It uses local commands only, so it runs in any session. When the sweep
59
+ raises a finding, one `clean-coder` fixes it through the same fix flow below and
60
+ the round re-runs, so the reading lenses only ever review sweep-clean code.
61
+ 3. Run three reading lenses in parallel on that HEAD, each over the full
54
62
  `origin/main...HEAD` diff. Each lens receives the preflight's changed-file
55
63
  list and diffstat and reads only the files it needs from that list rather than
56
64
  re-deriving the diff; each lens forms its own review judgment.
57
- - **Bugbot lens** — drive Cursor Bugbot to a verdict on HEAD (trigger and
58
- poll its CI check run when needed) and return its findings, or mark itself
59
- down when Bugbot is opted out or unreachable.
60
65
  - **Code-review lens** — a correctness-focused review pass (`code-quality-agent`)
61
66
  that reports findings without editing.
62
67
  - **Bug-audit lens** — the bug-audit (`code-quality-agent`) applying the
63
- shared A–P rubric from `_shared/pr-loop/audit-contract.md`, reporting
68
+ shared A–P rubric from `_shared/pr-loop/audit-contract.md`, then its
69
+ adversarial second pass, and the doc-parity, test-assertion, and
70
+ PR-description lanes from `_shared/pr-loop/precatch-rubric.md`, reporting
64
71
  findings without editing.
65
- 3. Dedup findings across the three lenses by file, line, and title. A collision
72
+ - **Self-review lens** the semantic parity pass (`code-quality-agent`) that
73
+ reads `_shared/pr-loop/precatch-rubric.md` and covers doc-vs-code parity,
74
+ test-assertion completeness, and PR-description-vs-diff parity, reporting
75
+ findings without editing.
76
+ 4. Dedup findings across the three lenses by file, line, and title. A collision
66
77
  keeps the most severe duplicate's severity (P0 > P1 > P2), unions the detail
67
78
  text, and collects every distinct bot thread id so the fix lens resolves all
68
79
  colliding threads.
69
- 4. **Any findings** → one `clean-coder` applies every fix per the
80
+ 5. **Any findings** → one `clean-coder` applies every fix per the
70
81
  `pr-fix-protocol` skill (`../../pr-fix-protocol/SKILL.md`): a single
71
82
  test-first commit, a push, then a reply and resolve on each finding that
72
83
  carries a GitHub review thread. Before its turn ends, the edit step dry-runs
@@ -79,10 +90,22 @@ tracks CONVERGE passes only and is never the cap.
79
90
  re-converges on the unchanged HEAD). A round whose fix lens reports neither
80
91
  a moved-HEAD push nor a full thread-resolution ends the run with a
81
92
  fix-stalled blocker. The next round re-verifies on the current HEAD.
82
- 5. **Zero findings on a stable HEAD** → post the CLEAN bugteam audit artifact
83
- for that HEAD, then move to the Copilot gate.
93
+ 6. **Zero findings on a stable HEAD** → post the CLEAN bugteam audit artifact
94
+ for that HEAD, then move to the terminal Bugbot gate.
95
+
96
+ **BUGBOT** gate (terminal external confirmation):
97
+
98
+ - Runs once the internal lenses are clean. When Bugbot is off for the run — the
99
+ default unless `CLAUDE_REVIEWS_ENABLED` lists `bugbot` — opted out via
100
+ `CLAUDE_REVIEWS_DISABLED`, or unreachable, the gate spawns no agent and moves
101
+ to the Copilot gate with `bugbotDown` set.
102
+ - Otherwise drive Cursor Bugbot to a verdict on HEAD (trigger and poll its CI
103
+ check run when needed).
104
+ - Bugbot findings → fix them and return to CONVERGE on the new HEAD.
105
+ - Bugbot clean or approved → move to the Copilot gate.
106
+ - Bugbot down after the poll cap → move to the Copilot gate with `bugbotDown` set.
84
107
 
85
- **COPILOT** gate:
108
+ **COPILOT** gate (terminal external confirmation):
86
109
 
87
110
  - Request a Copilot review on HEAD (skipping a duplicate request), then poll up
88
111
  to the configured cap, 360 seconds apart.
@@ -104,14 +127,11 @@ tracks CONVERGE passes only and is never the cap.
104
127
  Each spawned agent runs on the model and effort its role needs, so the run spends
105
128
  the strongest model only where judgment is dense:
106
129
 
107
- - **opus / medium** — the review lenses (Bugbot, code-review, bug-audit, reuse)
108
- and the code-editing steps that fix findings (fix-edit, conflict-edit,
109
- repair-edit, standards-edit).
110
- - **sonnet / medium** the verify steps, the commit steps, and the recovery
111
- edits that clear a commit-gate or verdict rejection.
112
- - **haiku / low** — the mechanical steps: the preflight git-and-availability
113
- probe, the Copilot gate, the CLEAN-audit post, and the convergence check that
114
- marks the PR ready.
130
+ - **sonnet** — the deterministic static-sweep lens, and the verify,
131
+ commit, and recovery steps that clear a commit-gate or verdict rejection.
132
+ - **opus** — the reading lenses (code-review, bug-audit, self-review,
133
+ reuse), the terminal Bugbot gate, and the code-editing steps that fix findings
134
+ (fix-edit, conflict-edit, repair-edit, standards-edit).
115
135
 
116
136
  ## Full-diff rule
117
137
 
@@ -126,7 +146,9 @@ every condition from GitHub and marks the PR ready only when all of these hold o
126
146
  the current HEAD:
127
147
 
128
148
  1. Bugbot CI check run is completed with a success or neutral conclusion
129
- (bypassed when Bugbot is opted out or proved unreachable this run).
149
+ (bypassed when Bugbot is off for the run the default unless
150
+ `CLAUDE_REVIEWS_ENABLED` lists `bugbot` — opted out via
151
+ `CLAUDE_REVIEWS_DISABLED`, or proved unreachable this run).
130
152
  2. The Bugbot review body on HEAD reports no findings (checked when a Bugbot
131
153
  review is present).
132
154
  3. A CLEAN bugteam audit review sits on HEAD.
@@ -60,3 +60,14 @@ fails in a new way.
60
60
  own. When landing a fix needs it, stop and tell the user the verified-commit
61
61
  gate is blocking the push and that going forward needs either a `# verify-skip`
62
62
  bypass or a switch to `/pr-converge`, then let the user decide.
63
+
64
+ - **A Copilot "down" verdict is valid only after the full poll budget.** A
65
+ successful review request means the review is in flight — Copilot typically
66
+ posts within 10–15 minutes of the request. A gate agent that returns
67
+ `down:true` on a partial poll misreports an in-flight review as reviewer
68
+ unavailability, and the run marks the PR ready moments before the review
69
+ lands. After a successful request the only valid gate outcomes are a
70
+ received review on HEAD, an out-of-usage notice, or the full poll budget
71
+ spent. The teardown re-checks the PR for a late-arriving Copilot review
72
+ whenever the gate was bypassed, and routes its findings through one more
73
+ fix round.
@@ -26,7 +26,13 @@ skill still runs teardown (revoke permissions, final report).
26
26
  stalled HEAD. An all-stale round that makes no commit but resolves every
27
27
  finding thread (`resolvedWithoutCommit: true` with at least one thread-bearing
28
28
  finding) is not a stall — the run re-converges on the unchanged HEAD and
29
- reaches the Copilot and convergence gates.
29
+ reaches the terminal Bugbot, Copilot, and convergence gates.
30
+ - **Static-sweep stalled** — the deterministic static sweep (`code_rules_gate.py
31
+ --base origin/main`, `ruff`, `mypy`, stem-matched `pytest`) raises gate or test
32
+ failures the fixer cannot clear on the current HEAD, so HEAD does not move. The
33
+ reading lenses never run on a sweep-dirty HEAD, so the run ends with a
34
+ static-sweep stall `blocker` naming the failure count and the stalled HEAD
35
+ rather than looping to the iteration cap.
30
36
  - **Mark-ready failed** — the convergence check passes but the mark-ready step
31
37
  cannot confirm the PR left draft state (`gh pr ready` errored, or the draft
32
38
  re-query still reports true). The workflow does not report `converged: true`;
@@ -55,8 +61,12 @@ skill still runs teardown (revoke permissions, final report).
55
61
 
56
62
  ## Not a blocker (the run continues)
57
63
 
58
- - **Bugbot down** — when Cursor Bugbot is opted out, or never produces a check
59
- run or review after the lens poll budget, the Bugbot lens returns `down: true`.
64
+ - **Terminal Bugbot gate down or disabled** — the terminal Bugbot gate runs once
65
+ the internal lenses are clean. When Cursor Bugbot is off for the run (the
66
+ default unless `CLAUDE_REVIEWS_ENABLED` lists `bugbot`) or opted out via
67
+ `CLAUDE_REVIEWS_DISABLED`, the gate spawns no agent and passes to the Copilot
68
+ gate with `bugbotDown` set. When Bugbot is enabled but never produces a check
69
+ run or review after the gate poll budget, the gate returns down the same way.
60
70
  The run continues, and the convergence check runs with `--bugbot-down` so its
61
71
  Bugbot gate is bypassed.
62
72
  - **Copilot down or out of quota** — when Copilot posts an out-of-usage notice on
@@ -66,16 +76,16 @@ skill still runs teardown (revoke permissions, final report).
66
76
  check with `--copilot-down` (the Copilot review gate and the
67
77
  pending-requested-reviews gate bypassed), and marks the PR ready. `copilotNote`
68
78
  records the bypass for the final report.
69
- - **A lens agent dies** — when one parallel lens returns null (a terminal agent
70
- failure), the round proceeds on the surviving lenses. A real defect it would
71
- have caught surfaces in a later round or at the convergence check. A dead
72
- Bugbot lens (null result) counts as down for that HEAD, so the convergence
73
- check runs with `--bugbot-down` rather than demanding a Bugbot verdict the
74
- dead agent never produced.
75
- - **Every lens agent dies (a single round)** — when all three parallel lenses
76
- return null in the same round, the round is a failure, not a clean: the
77
- workflow posts no CLEAN bugteam artifact and does not advance to the Copilot
78
- gate. It re-resolves HEAD and retries on the next round. This is a
79
+ - **A lens agent dies** — when one parallel reading lens returns null (a terminal
80
+ agent failure), the round proceeds on the surviving lenses. A real defect it
81
+ would have caught surfaces in a later round or at the convergence check. A dead
82
+ terminal Bugbot gate agent (null result) is a retry rather than an approval, so
83
+ the gate re-runs on the same HEAD rather than treating a dead agent as a clean
84
+ Bugbot verdict.
85
+ - **Every lens agent dies (a single round)** — when all three parallel reading
86
+ lenses return null in the same round, the round is a failure, not a clean: the
87
+ workflow posts no CLEAN bugteam artifact and does not advance to the terminal
88
+ gates. It re-resolves HEAD and retries on the next round. This is a
79
89
  no-lens-reviewed round, so consecutive occurrences are bounded by the
80
90
  no-review-lens cap in the blockers above, not just the iteration cap.
81
91
 
@@ -6,7 +6,7 @@ Workflow scripts and report utilities for the `autoconverge` skill.
6
6
 
7
7
  | File | Role |
8
8
  |---|---|
9
- | `converge.mjs` | Main convergence workflow script. Each round runs Bugbot, code-review, and bug-audit lenses in parallel, deduplicates findings, applies fixes, pushes, gates on Copilot, checks convergence, and marks the PR ready. Runs via the `Workflow` tool — not directly with Node. |
9
+ | `converge.mjs` | Main convergence workflow script. Each round runs a deterministic static sweep first, then code-review, bug-audit, and self-review lenses in parallel, deduplicates findings, applies fixes, and pushes; Bugbot and Copilot then run as terminal confirmation gates before it checks convergence and marks the PR ready. Runs via the `Workflow` tool — not directly with Node. |
10
10
  | `aggregate_runs.py` | Merges every autoconverge journal for a given PR (matched by run id) into one merged journal. Prints a JSON line with `mergedJournal`, `roundCount`, `finalSha`, and `findingCount`. |
11
11
  | `convergence_summary.py` | Builds the convergence-summary agent prompt over the merged journal's findings. The teardown step spawns a `general-purpose` subagent on this prompt. |
12
12
  | `render_report.py` | Builds the closing HTML insights report. Takes `--journal`, `--summary-file`, `--out`, `--pr`, `--final-sha`, and `--rounds`. Writes the HTML to `--out` and prints the output path on stdout. |
@@ -14,6 +14,7 @@ Workflow scripts and report utilities for the `autoconverge` skill.
14
14
  | `converge.contract.test.mjs` | Contract tests for `converge.mjs` — verify the workflow interface and step ordering. |
15
15
  | `converge.clean-audit.test.mjs` | Tests the clean-audit path (all lenses clean on first round). |
16
16
  | `converge.copilot-gate.test.mjs` | Tests Copilot gate behavior (bypass on quota exhaustion). |
17
+ | `converge.precatch.test.mjs` | Tests the pre-catch stage: static-sweep ordering and gate coverage, the adversarial second pass, the self-review lens, the terminal Bugbot gate, the read-only/edit preamble split, and the commit-recovery cap. |
17
18
  | `converge.fix-progress.test.mjs` | Tests fix-progress tracking across rounds. |
18
19
  | `converge.fix-recovery.test.mjs` | Tests recovery when a fix commit fails. |
19
20
  | `converge.run-input.test.mjs` | Tests workflow input validation. |
@@ -53,7 +53,7 @@ const {
53
53
 
54
54
  function buildRunGeneralUtilityTask(convergeAgentStub) {
55
55
  const factory = new Function(
56
- 'convergeAgent',
56
+ 'convergeReadOnlyAgent',
57
57
  'input',
58
58
  'CONFIG',
59
59
  'prCoordinates',
@@ -122,7 +122,7 @@ test('nameLensResults classifies a not-spawned stub, a dead agent, and a ran len
122
122
  assert.equal(namedLenses[2].status, 'ran');
123
123
  assert.equal(namedLenses[2].report, auditReport);
124
124
  const allLensNames = namedLenses.map((eachEntry) => eachEntry.lens);
125
- assert.deepEqual(allLensNames, ['Cursor Bugbot', 'code-review', 'bug-audit']);
125
+ assert.deepEqual(allLensNames, ['code-review', 'bug-audit', 'self-review']);
126
126
  });
127
127
 
128
128
  test('nameLensResults tags a down lens reported-down only with zero findings, and ran when it produced findings', () => {
@@ -145,10 +145,10 @@ test('nameLensResults tags a down lens reported-down only with zero findings, an
145
145
 
146
146
  test('describeNotRunLens words each not-run status without claiming a review or asserting a poll or timeout', () => {
147
147
  assert.match(
148
- describeNotRunLens({ lens: 'Cursor Bugbot', status: 'down' }),
148
+ describeNotRunLens({ lens: 'self-review', status: 'down' }),
149
149
  /down\/disabled — did not run/,
150
150
  );
151
- const reportedDownClause = describeNotRunLens({ lens: 'Cursor Bugbot', status: 'reported-down' });
151
+ const reportedDownClause = describeNotRunLens({ lens: 'self-review', status: 'reported-down' });
152
152
  assert.match(reportedDownClause, /reported itself down/);
153
153
  assert.match(reportedDownClause, /produced no review for this HEAD/);
154
154
  assert.doesNotMatch(reportedDownClause, /poll|timeout/i);
@@ -194,7 +194,7 @@ test('the standards-only branch reaches the deferral filing without a zero-ran g
194
194
  test('the all-clean zero-ran retry is inlined, registers a no-lens round, and the shared helper is gone', () => {
195
195
  const allCleanBranch = convergeSource.slice(
196
196
  convergeSource.indexOf('all lenses clean on'),
197
- convergeSource.indexOf("if (phase === 'COPILOT') {"),
197
+ convergeSource.indexOf("if (phase === 'BUGBOT') {"),
198
198
  );
199
199
  assert.match(allCleanBranch, /if \(auditResult\?\.noLensRan\)/);
200
200
  assert.match(allCleanBranch, /registerNoLensRound\(noLensRoundCausesFor\(allCleanNamedLenses\)\)/);
@@ -209,7 +209,7 @@ test('every no-lens-reviewed round registers one shared counter and every lens-r
209
209
  const registerSites = loopBody.match(/registerNoLensRound\(/g) || [];
210
210
  assert.equal(registerSites.length, 3, 'expected the preflight-no-SHA, all-lenses-dead, and no-lens-ran rounds to register');
211
211
  const resetSites = loopBody.match(/resetNoLensRounds\(\)/g) || [];
212
- assert.equal(resetSites.length, 4, 'expected a reset on the standards, findings, not-clean, and posted lens-ran rounds');
212
+ assert.equal(resetSites.length, 5, 'expected a reset on the static-sweep, standards, findings, not-clean, and posted lens-ran rounds');
213
213
  const deadBranch = convergeSource.slice(
214
214
  convergeSource.indexOf('if (roundOutcome.allLensesDead) {'),
215
215
  convergeSource.indexOf('const findings = roundOutcome.findings'),
@@ -554,14 +554,19 @@ test('the standards-only call site relays lens provenance, the deferred standard
554
554
  assert.match(buildBody, /hardeningPrOpened: wasStandardsHardeningPrOpened/);
555
555
  });
556
556
 
557
- test('both standardsDeferralNote call sites pass the shared deferral state with no legacy argument', () => {
557
+ test('every standardsDeferralNote call site passes the shared deferral state with no legacy argument', () => {
558
558
  const noteCalls = convergeSource.match(/standardsNote = standardsDeferralNote\([^\n]*/g) || [];
559
- assert.equal(noteCalls.length, 2);
559
+ assert.equal(noteCalls.length, 3);
560
560
  assert.equal(
561
561
  noteCalls.filter((eachCall) => /standardsDeferralNote\(findings\.length, standardsDeferral\)/.test(eachCall)).length,
562
562
  1,
563
563
  'expected the converge call site to pass the standardsDeferral local built from buildStandardsDeferral()',
564
564
  );
565
+ assert.equal(
566
+ noteCalls.filter((eachCall) => /standardsDeferralNote\(bugbotOutcome\.findings\.length, buildStandardsDeferral\(\)\)/.test(eachCall)).length,
567
+ 1,
568
+ 'expected the terminal-Bugbot call site to pass buildStandardsDeferral() inline',
569
+ );
565
570
  assert.equal(
566
571
  noteCalls.filter((eachCall) => /standardsDeferralNote\(copilotOutcome\.findings\.length, buildStandardsDeferral\(\)\)/.test(eachCall)).length,
567
572
  1,
@@ -573,19 +578,10 @@ test('both standardsDeferralNote call sites pass the shared deferral state with
573
578
  assert.doesNotMatch(convergeSource, /buildStandardsDeferral\(standardsOutcome\)/);
574
579
  });
575
580
 
576
- test('the parallel lens spawn marks the workflow-synthesized Bugbot down-stub as not-spawned', () => {
577
- const spawnRegion = convergeSource.slice(
578
- convergeSource.indexOf('const lenses = await parallel(['),
579
- convergeSource.indexOf('bugbotDown = lenses[0]'),
580
- );
581
- assert.match(spawnRegion, /isBugbotDownPreSpawn \?/);
582
- assert.match(spawnRegion, /notSpawned: true/);
583
- });
584
-
585
581
  test('the all-clean call site breaks with a clean-audit blocker when the post does not land', () => {
586
582
  const branch = convergeSource.slice(
587
583
  convergeSource.indexOf('all lenses clean on'),
588
- convergeSource.indexOf("if (phase === 'COPILOT') {"),
584
+ convergeSource.indexOf("if (phase === 'BUGBOT') {"),
589
585
  );
590
586
  assert.match(branch, /runGeneralUtilityTask\(.*'post-clean-audit'/);
591
587
  assert.match(branch, /if \(!auditResult\?\.posted\)/);
@@ -596,7 +592,7 @@ test('the all-clean call site breaks with a clean-audit blocker when the post do
596
592
  test('the all-clean call site relays lens provenance into the post-clean-audit context without a postFindings field', () => {
597
593
  const branch = convergeSource.slice(
598
594
  convergeSource.indexOf('all lenses clean on'),
599
- convergeSource.indexOf("if (phase === 'COPILOT') {"),
595
+ convergeSource.indexOf("if (phase === 'BUGBOT') {"),
600
596
  );
601
597
  assert.match(branch, /const allCleanNamedLenses = nameLensResults\(lenses\)/);
602
598
  assert.match(branch, /lensResults: allCleanNamedLenses/);