claude-dev-env 2.4.0 → 2.7.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 +26 -59
- package/_shared/pr-loop/scripts/_claude_permissions_common.py +84 -0
- package/_shared/pr-loop/scripts/code_rules_gate.py +6 -3
- package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +12 -2
- package/_shared/pr-loop/scripts/code_rules_gate_parts/baseline_import_isolation.py +309 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_regression.py +540 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_running.py +206 -70
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/__init__.py +1 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/_repo_test_helpers.py +76 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_baseline_import_isolation.py +248 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_staged_test_regression.py +309 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_staged_test_running.py +91 -58
- package/_shared/pr-loop/scripts/grant_project_claude_permissions.py +306 -306
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/claude_permissions_constants.py +44 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/code_rules_gate_constants.py +202 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/copilot_quota_constants.py +24 -24
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/stale_worktree_rule_sweep_constants.py +107 -107
- package/_shared/pr-loop/scripts/revoke_project_claude_permissions.py +290 -48
- package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +42 -2
- package/_shared/pr-loop/scripts/tests/test_claude_permissions_constants.py +36 -0
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +100 -1
- package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +497 -497
- package/_shared/pr-loop/scripts/tests/test_revoke_project_claude_permissions.py +311 -2
- package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep.py +301 -301
- package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep_constants.py +85 -85
- package/_shared/pr-loop/worker-spawn.md +1 -1
- package/agents/CLAUDE.md +3 -2
- package/agents/caveman.md +0 -1
- package/agents/clasp-deployment-orchestrator.md +0 -1
- package/agents/clean-coder.md +0 -1
- package/agents/code-advisor.md +0 -1
- package/agents/code-quality-agent.md +1 -2
- package/agents/code-verifier.md +36 -8
- package/agents/deep-research.md +0 -1
- package/agents/docs-agent.md +0 -1
- package/agents/git-commit-crafter.md +0 -1
- package/agents/issue-tracker.md +42 -0
- package/agents/plan-packet-validator.md +0 -1
- package/agents/pr-description-writer.md +0 -1
- package/agents/test_agent_frontmatter.py +67 -18
- package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +143 -141
- package/bin/CLAUDE.md +68 -5
- package/bin/codex-compat.mjs +104 -0
- package/bin/codex-compat.test.mjs +51 -0
- package/bin/ever-shipped-skills.mjs +1 -0
- package/bin/install-constants.mjs +88 -0
- package/bin/install.mjs +1138 -114
- package/bin/install.prune.test.mjs +869 -19
- package/bin/install.test.mjs +906 -2
- package/codex-capability-map.json +13 -0
- package/commands/implement.md +1 -1
- package/commands/right-size.md +1 -1
- package/docs/CLAUDE.md +1 -0
- package/docs/CODE_RULES.md +2 -0
- package/docs/codex-compatibility.md +25 -0
- package/docs/host-pool-health-monitor.md +102 -0
- package/docs/nas-ssh-invocation.md +96 -12
- package/docs/references/CLAUDE.md +4 -2
- package/docs/references/advisor-tool.md +13 -0
- package/docs/references/code-review-enforcement.md +35 -0
- package/docs/references/team-advisor-skill.md +14 -0
- package/hooks/blocking/CLAUDE.md +4 -0
- package/hooks/blocking/code_review_pr_create_gate.py +7 -3
- package/hooks/blocking/code_review_push_gate.py +9 -4
- package/hooks/blocking/code_review_stamp_directory_write_blocker.py +8 -0
- package/hooks/blocking/config/__init__.py +5 -5
- package/hooks/blocking/config/code_review_enforcement_constants.py +40 -7
- package/hooks/blocking/config/test_code_review_enforcement_constants.py +58 -0
- package/hooks/blocking/config/verified_commit_constants.py +160 -159
- package/hooks/blocking/eli11_reply_enforcer.py +479 -0
- package/hooks/blocking/gh_body_arg_blocker.py +1 -1
- package/hooks/blocking/nas_ssh_binary_enforcer.py +8 -46
- package/hooks/blocking/orchestrator_refresh_reschedule_gate.py +256 -0
- package/hooks/blocking/pre_tool_use_dispatcher.py +24 -24
- package/hooks/blocking/shell_substitution_blocker.py +129 -0
- package/hooks/blocking/state_description_blocker.py +1 -1
- package/hooks/blocking/stop_dispatcher.py +1 -1
- package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +2 -3
- package/hooks/blocking/test_code_review_pr_create_gate.py +14 -0
- package/hooks/blocking/test_code_review_push_gate.py +16 -0
- package/hooks/blocking/test_code_review_stamp_directory_write_blocker.py +19 -0
- package/hooks/blocking/test_eli11_reply_enforcer.py +457 -0
- package/hooks/blocking/test_orchestrator_refresh_reschedule_gate.py +231 -0
- package/hooks/blocking/test_pre_tool_use_dispatcher.py +10 -1
- package/hooks/blocking/test_shell_substitution_blocker.py +124 -0
- package/hooks/blocking/test_stop_dispatcher.py +23 -0
- package/hooks/blocking/test_unscoped_search_blocker.py +102 -0
- package/hooks/blocking/test_verdict_directory_write_blocker.py +804 -808
- package/hooks/blocking/test_verification_verdict_store.py +54 -0
- package/hooks/blocking/test_verified_commit_gate.py +581 -581
- package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +131 -131
- package/hooks/blocking/unscoped_search_blocker.py +391 -0
- package/hooks/blocking/verdict_directory_write_blocker.py +687 -687
- package/hooks/blocking/verification_verdict_store.py +1039 -1036
- package/hooks/blocking/verified_commit_message_accuracy_blocker.py +167 -167
- package/hooks/blocking/verifier_verdict_minter.py +280 -280
- package/hooks/git-hooks/CLAUDE.md +3 -0
- package/hooks/git-hooks/conftest.py +30 -0
- package/hooks/git-hooks/gate_utils.py +2 -2
- package/hooks/git-hooks/git_hooks_constants/__init__.py +41 -2
- package/hooks/git-hooks/pre_push.py +75 -4
- package/hooks/git-hooks/pre_push_base_reference.py +166 -0
- package/hooks/git-hooks/test_config.py +0 -15
- package/hooks/git-hooks/test_gate_utils.py +3 -15
- package/hooks/git-hooks/test_pre_commit.py +1 -15
- package/hooks/git-hooks/test_pre_push.py +257 -23
- package/hooks/git-hooks/test_pre_push_base_reference.py +339 -0
- package/hooks/hooks.json +10 -12
- package/hooks/hooks_constants/CLAUDE.md +7 -2
- package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +4 -4
- package/hooks/hooks_constants/eli11_reply_enforcer_constants.py +101 -0
- package/hooks/hooks_constants/enter_worktree_prefetch_constants.py +18 -18
- package/hooks/hooks_constants/nas_ssh_binary_enforcer_constants.py +2 -8
- package/hooks/hooks_constants/orchestrator_refresh_reschedule_gate_constants.py +48 -0
- package/hooks/hooks_constants/ruff_integration_constants.py +16 -0
- package/hooks/hooks_constants/shell_command_segments.py +82 -0
- package/hooks/hooks_constants/shell_substitution_blocker_constants.py +67 -0
- package/hooks/hooks_constants/stop_dispatcher_constants.py +1 -0
- package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +5 -6
- package/hooks/hooks_constants/test_stop_dispatcher_constants.py +1 -0
- package/hooks/hooks_constants/unscoped_search_blocker_constants.py +153 -0
- package/hooks/lifecycle/enter_worktree_origin_prefetch.py +163 -146
- package/hooks/lifecycle/test_enter_worktree_origin_prefetch.py +185 -178
- package/hooks/pyproject.toml +1 -0
- package/hooks/validators/CLAUDE.md +1 -0
- package/hooks/validators/config/__init__.py +0 -0
- package/hooks/validators/config/directory_exemption_constants.py +183 -0
- package/hooks/validators/config/test_directory_exemption_constants.py +21 -0
- package/hooks/validators/conftest.py +4 -0
- package/hooks/validators/ruff_integration.py +49 -5
- package/hooks/validators/run_all_validators.py +206 -9
- package/hooks/validators/test_directory_exemption_constants.py +185 -0
- package/hooks/validators/test_python_antipattern_checks.py +110 -5
- package/hooks/validators/test_ruff_integration.py +92 -1
- package/hooks/validators/test_run_all_validators.py +115 -68
- package/hooks/validators/test_run_all_validators_pretooluse.py +159 -1
- package/package.json +13 -3
- package/rules/CLAUDE.md +17 -22
- package/rules/agent-spawn-protocol.md +6 -6
- package/rules/anti-corollary-tests.md +1 -1
- package/rules/bdd.md +1 -1
- package/rules/cleanup-temp-files.md +10 -4
- package/rules/code-standards.md +7 -0
- package/rules/conservative-action.md +1 -5
- package/rules/context7.md +0 -4
- package/rules/destructive-commands.md +47 -0
- package/rules/doc-inventory-integrity.md +48 -0
- package/rules/doc-prose-cuts.md +58 -0
- package/rules/docstring-prose-matches-implementation.md +53 -44
- package/rules/durable-post-artifacts.md +0 -4
- package/rules/eli11-replies.md +31 -0
- package/rules/explore-thoroughly.md +4 -4
- package/rules/falsify-before-green.md +68 -0
- package/rules/file-global-constants.md +1 -1
- package/rules/filesystem-search.md +51 -0
- package/rules/gh-cli-conventions.md +27 -0
- package/rules/git-workflow.md +26 -0
- package/rules/hedging-claims.md +9 -0
- package/rules/long-horizon-autonomy.md +0 -4
- package/rules/measurement-denominators.md +48 -0
- package/rules/nas-ssh-invocation.md +23 -5
- package/rules/parallel-tools.md +2 -2
- package/rules/plain-illustrative-docstrings.md +3 -7
- package/rules/plain-language.md +2 -0
- package/rules/proof-of-work-pr-comments.md +0 -4
- package/rules/re-stage-before-commit.md +2 -0
- package/rules/research-mode.md +10 -0
- package/rules/shell-invocation.md +21 -0
- package/rules/testing.md +4 -0
- package/rules/verified-commit-gate-skip.md +3 -27
- package/rules/verify-before-asking.md +5 -0
- package/rules/windows-filesystem-safe.md +1 -1
- package/rules/workers-done-before-complete.md +4 -0
- package/scripts/CLAUDE.md +1 -0
- package/scripts/Capture-PoolHealth.ps1 +410 -0
- package/scripts/Migrate-ShellPolicy.ps1 +1 -1
- package/scripts/_code_review_test_support.py +404 -0
- package/scripts/claude_chain_runner.py +141 -1
- package/scripts/codex_capability_bridge.py +171 -0
- package/scripts/codex_compat_materializer.py +1087 -0
- package/scripts/codex_compat_watcher.py +502 -0
- package/scripts/conftest.py +16 -1
- package/scripts/dev_env_scripts_constants/CLAUDE.md +1 -1
- package/scripts/dev_env_scripts_constants/claude_chain_constants.py +9 -0
- package/scripts/dev_env_scripts_constants/code_review_constants.py +37 -0
- package/scripts/invoke_code_review.py +11 -4
- package/scripts/resolve_worker_spawn.py +626 -626
- package/scripts/spawn_grok_batch.py +672 -672
- package/scripts/sync_to_cursor/rules.py +0 -10
- package/scripts/test_claude_chain_runner.py +131 -0
- package/scripts/test_invoke_code_review.py +85 -908
- package/scripts/test_invoke_code_review_chain.py +70 -0
- package/scripts/test_invoke_code_review_cli.py +192 -0
- package/scripts/test_invoke_code_review_contract.py +256 -0
- package/scripts/test_invoke_code_review_git.py +123 -0
- package/scripts/test_invoke_code_review_mode.py +99 -0
- package/scripts/test_resolve_worker_spawn.py +1014 -1014
- package/scripts/tests/test_code_review_constants.py +80 -0
- package/scripts/tests/test_codex_capability_bridge.py +91 -0
- package/scripts/tests/test_codex_compat_materializer.py +632 -0
- package/scripts/tests/test_codex_compat_watcher.py +599 -0
- package/scripts/tests/test_sync_to_cursor.py +0 -1
- package/skills/CLAUDE.md +2 -0
- package/skills/auditing-claude-config/SKILL.md +114 -114
- package/skills/autoconverge/SKILL.md +427 -427
- package/skills/autoconverge/reference/convergence.md +24 -3
- package/skills/autoconverge/workflow/CLAUDE.md +1 -0
- package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +3 -3
- package/skills/autoconverge/workflow/converge.contract.test.mjs +1263 -1263
- package/skills/autoconverge/workflow/converge.mjs +168 -1
- package/skills/autoconverge/workflow/converge.p2-advance.test.mjs +202 -0
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +265 -265
- package/skills/bugteam/reference/copilot-gap-analysis.md +1 -1
- package/skills/closeout/SKILL.md +33 -50
- package/skills/codex-review/scripts/codex_review_scripts_constants/run_constants.py +8 -0
- package/skills/codex-review/scripts/run_codex_review.py +233 -1
- package/skills/codex-review/scripts/test_run_codex_review.py +189 -0
- package/skills/condensing-instructions/SKILL.md +72 -0
- package/skills/copilot-review/SKILL.md +119 -119
- package/skills/e-code-review/SKILL.md +52 -0
- package/skills/e-code-review/reference/fix.md +54 -0
- package/skills/e-code-review/reference/loop.md +43 -0
- package/skills/e-code-review/reference/low.md +57 -0
- package/skills/e-code-review/reference/medium.md +153 -0
- package/skills/e-code-review/reference/xhigh.md +182 -0
- package/skills/e-simplify/SKILL.md +97 -0
- package/skills/fresh-branch/CLAUDE.md +1 -1
- package/skills/fresh-branch/SKILL.md +5 -6
- package/skills/fresh-branch/scripts/create_fresh_branch.py +42 -24
- package/skills/fresh-branch/scripts/fresh_branch_scripts_constants/fresh_branch_cli_constants.py +1 -3
- package/skills/fresh-branch/scripts/test_create_fresh_branch.py +30 -126
- package/skills/issue-tracker/SKILL.md +92 -0
- package/skills/issue-tracker/reference/epic-and-sub-issue-model.md +55 -0
- package/skills/issue-tracker/reference/handoff-schema.md +64 -0
- package/skills/issue-tracker/reference/operation-matrix.md +41 -0
- package/skills/orchestrator/SKILL.md +177 -22
- package/skills/orchestrator/scripts/status_gate.py +625 -0
- package/skills/orchestrator/scripts/status_gate_constants/__init__.py +1 -0
- package/skills/orchestrator/scripts/status_gate_constants/config/__init__.py +1 -0
- package/skills/orchestrator/scripts/status_gate_constants/config/constants.py +47 -0
- package/skills/orchestrator/scripts/test_status_gate.py +439 -0
- package/skills/orchestrator-refresh/SKILL.md +129 -35
- package/skills/plan-to-pr/SKILL.md +155 -0
- package/skills/plan-to-pr/reference/final-validation-tasks.md +15 -0
- package/skills/plan-to-pr/reference/model-routing.md +36 -0
- package/skills/plan-to-pr/reference/packet-contract.md +43 -0
- package/skills/plan-to-pr/reference/packet-schema.json +57 -0
- package/skills/plan-to-pr/reference/process-inventory.md +22 -0
- package/skills/plan-to-pr/reference/review-loop.md +33 -0
- package/skills/plan-to-pr/reference/run-record.schema.json +27 -0
- package/skills/plan-to-pr/reference/self-audit-tasks.md +15 -0
- package/skills/plan-to-pr/reference/task-seeds.md +14 -0
- package/skills/plan-to-pr/reference/task-ticket.md +38 -0
- package/skills/plan-to-pr/scripts/config/__init__.py +1 -0
- package/skills/plan-to-pr/scripts/config/constants.py +193 -0
- package/skills/plan-to-pr/scripts/create_packet.py +173 -0
- package/skills/plan-to-pr/scripts/test_create_packet.py +102 -0
- package/skills/plan-to-pr/scripts/test_validate_packet.py +256 -0
- package/skills/plan-to-pr/scripts/test_validate_protocol.py +135 -0
- package/skills/plan-to-pr/scripts/test_validate_run.py +158 -0
- package/skills/plan-to-pr/scripts/validate_packet.py +655 -0
- package/skills/plan-to-pr/scripts/validate_protocol.py +622 -0
- package/skills/plan-to-pr/scripts/validate_run.py +173 -0
- package/skills/plan-to-pr/test_skill_contract.py +207 -0
- package/skills/plan-to-pr/test_task_ticket_contract.py +151 -0
- package/skills/pr-converge/SKILL.md +472 -469
- package/skills/pr-converge/reference/examples.md +3 -3
- package/skills/pr-converge/reference/fix-protocol.md +1 -1
- package/skills/pr-converge/reference/ground-rules.md +7 -4
- package/skills/pr-converge/reference/multi-pr-orchestration.md +4 -1
- package/skills/pr-converge/reference/per-tick.md +5 -5
- package/skills/pr-converge/reference/progress-checklist.md +1 -1
- package/skills/pr-converge/scripts/check_convergence_gates.py +279 -279
- package/skills/pr-converge/scripts/test_check_convergence_codex.py +507 -507
- package/skills/pr-converge/scripts/test_check_convergence_gates.py +84 -84
- package/skills/pr-converge/test_step5_host_branch.py +1 -1
- package/skills/pr-fix-protocol/SKILL.md +1 -1
- package/skills/privacy-hygiene/SKILL.md +68 -68
- package/skills/privacy-hygiene/reference/sweep-procedure.md +1 -1
- package/skills/prototype/workflows/promotion.md +1 -1
- package/skills/release-notes-html/SKILL.md +164 -0
- package/skills/session-log/SKILL.md +1 -1
- package/skills/task-build/CLAUDE.md +8 -7
- package/skills/task-build/SKILL.md +16 -8
- package/skills/task-build/reference/tool-routing.md +19 -0
- package/rules/claude-md-orphan-file.md +0 -28
- package/rules/cleanup-command-forms.md +0 -23
- package/rules/code-reviews.md +0 -11
- package/rules/env-var-table-code-drift.md +0 -10
- package/rules/gh-body-file.md +0 -5
- package/rules/gh-paginate.md +0 -3
- package/rules/hook-prose-matches-detector.md +0 -15
- package/rules/no-historical-clutter.md +0 -26
- package/rules/no-inline-destructive-literals.md +0 -9
- package/rules/no-justification-noise.md +0 -61
- package/rules/package-inventory-stale-entry.md +0 -25
- package/rules/right-sized-engineering.md +0 -28
- package/rules/self-contained-docs.md +0 -17
- package/rules/shell-invocation-policy.md +0 -5
- package/rules/tdd.md +0 -7
- package/skills/closeout/reference/issue-body-templates.md +0 -108
|
@@ -381,7 +381,7 @@ function runCodeEditorTask(task, context) {
|
|
|
381
381
|
`You are the COMMIT step opening the environment-hardening PR (${context.sourceLabel}) for the change staged in ${context.hardeningRepoPath} on branch ${context.hardeningBranch}. The edit step left the hooks/rules edits in the working tree and the verify step passed, so a verifier verdict already binds to this exact working tree. Do NOT touch the PR's own branch.\n\n` +
|
|
382
382
|
`Rules:\n` +
|
|
383
383
|
`- Make NO further file edits of any kind. Any edit changes the surface and invalidates the verdict that unlocks the commit gate, so the push would be blocked. Only commit and push what is already there.\n` +
|
|
384
|
-
`- In ${context.hardeningRepoPath}: make ONE commit of the staged hooks/rules change on branch ${context.hardeningBranch}, push it, then open a DRAFT PR. The PR body references the follow-up issue ${context.issueUrl || '(none)'} and states the PR hardens the environment so the deferred violation classes are blocked at Write/Edit time. Honor the gh-
|
|
384
|
+
`- In ${context.hardeningRepoPath}: make ONE commit of the staged hooks/rules change on branch ${context.hardeningBranch}, push it, then open a DRAFT PR. The PR body references the follow-up issue ${context.issueUrl || '(none)'} and states the PR hardens the environment so the deferred violation classes are blocked at Write/Edit time. Honor the gh-cli-conventions rule: write a BOM-free temp file and pass --body-file.\n` +
|
|
385
385
|
`- Title the PR as a Conventional Commit — a type prefix (feat, fix, chore, docs, refactor, perf, ci, style, test, build, revert), an optional scope in parentheses, then a colon and a short summary, e.g. "feat(hooks): block the deferred violation class". The target repo's CI validates the PR title as a semantic commit and rejects a non-conforming title.\n\n` +
|
|
386
386
|
`Return the full https URL of the DRAFT hardening PR in hardeningPrUrl (empty string when no PR was opened) and a one-line summary.`,
|
|
387
387
|
{ label, phase: 'Converge', schema: HARDENING_COMMIT_SCHEMA, agentType: 'clean-coder', ...TIERS.sonnetMedium },
|
|
@@ -2276,6 +2276,101 @@ function isStandardsOnlyRound(findings) {
|
|
|
2276
2276
|
return findings.length > 0 && findings.every((each) => each.category === 'code-standard')
|
|
2277
2277
|
}
|
|
2278
2278
|
|
|
2279
|
+
/**
|
|
2280
|
+
* Decide whether a review phase surfaced ONLY P2 findings — pure low-severity
|
|
2281
|
+
* items with no P0/P1 mixed in. Such a phase still applies the fixes once, then
|
|
2282
|
+
* treats the fixed HEAD as clean for that phase and advances forward rather than
|
|
2283
|
+
* re-converging the same phase.
|
|
2284
|
+
* @param {Array<object>} findings already-deduped findings for the phase
|
|
2285
|
+
* @returns {boolean} true when every finding is severity P2
|
|
2286
|
+
*/
|
|
2287
|
+
function isP2OnlyFindings(findings) {
|
|
2288
|
+
return findings.length > 0 && findings.every((each) => each.severity === 'P2')
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2291
|
+
/**
|
|
2292
|
+
* Map the phase that just finished a P2-only fix onto the next phase to enter
|
|
2293
|
+
* on the fixed HEAD. Pure P2 never returns to CONVERGE; each gate advances
|
|
2294
|
+
* forward only.
|
|
2295
|
+
*
|
|
2296
|
+
* ::
|
|
2297
|
+
*
|
|
2298
|
+
* nextPhaseAfterP2OnlyFix('CONVERGE') -> 'BUGBOT'
|
|
2299
|
+
* nextPhaseAfterP2OnlyFix('BUGBOT') -> 'COPILOT'
|
|
2300
|
+
* nextPhaseAfterP2OnlyFix('COPILOT') -> 'CODEX'
|
|
2301
|
+
* nextPhaseAfterP2OnlyFix('CODEX') -> 'FINALIZE'
|
|
2302
|
+
*
|
|
2303
|
+
* @param {string} currentPhase the phase that just applied the P2-only fixes
|
|
2304
|
+
* @returns {string} the next phase name
|
|
2305
|
+
*/
|
|
2306
|
+
function nextPhaseAfterP2OnlyFix(currentPhase) {
|
|
2307
|
+
const nextPhaseByCurrent = {
|
|
2308
|
+
CONVERGE: 'BUGBOT',
|
|
2309
|
+
BUGBOT: 'COPILOT',
|
|
2310
|
+
COPILOT: 'CODEX',
|
|
2311
|
+
}
|
|
2312
|
+
return nextPhaseByCurrent[currentPhase] || 'FINALIZE'
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
/**
|
|
2316
|
+
* Apply P2-only findings once and report whether the fixed HEAD advanced.
|
|
2317
|
+
* Shared by the four phase branches that fix pure-P2 findings then advance
|
|
2318
|
+
* forward without re-converging.
|
|
2319
|
+
*
|
|
2320
|
+
* ::
|
|
2321
|
+
*
|
|
2322
|
+
* await applyP2OnlyFix(head, findings, 'bugbot', 'bugbot gate', 'bugbot fix lens')
|
|
2323
|
+
* -> { progressed: true, newSha: '<fixed>', blocker: null }
|
|
2324
|
+
*
|
|
2325
|
+
* @param {string} head PR HEAD SHA the findings were raised against
|
|
2326
|
+
* @param {Array<object>} findings P2-only findings for this phase
|
|
2327
|
+
* @param {string} sourceLabel short label passed to applyFixes
|
|
2328
|
+
* @param {string} stallSubject noun phrase for the resolvedWithoutCommit stall message
|
|
2329
|
+
* @param {string} noPushSubject subject for the no-push stall message
|
|
2330
|
+
* @returns {Promise<{progressed: boolean, newSha: string, blocker: string|null}>} fix outcome
|
|
2331
|
+
*/
|
|
2332
|
+
async function applyP2OnlyFix(head, findings, sourceLabel, stallSubject, noPushSubject) {
|
|
2333
|
+
const fixResult = await applyFixes(head, findings, sourceLabel)
|
|
2334
|
+
const hadThreadBearingFinding = findings.some((each) => collectFindingThreadIds(each).length > 0)
|
|
2335
|
+
const fixProgress = detectFixProgress(fixResult, head, hadThreadBearingFinding)
|
|
2336
|
+
if (fixProgress.progressed) {
|
|
2337
|
+
return { progressed: true, newSha: fixProgress.newSha, blocker: null }
|
|
2338
|
+
}
|
|
2339
|
+
const blocker =
|
|
2340
|
+
fixResult?.resolvedWithoutCommit === true && !hadThreadBearingFinding
|
|
2341
|
+
? `fix stalled: ${stallSubject} raised ${findings.length} in-memory finding(s) with no GitHub thread, the fix judged them all stale (resolvedWithoutCommit) and moved no code on HEAD ${head} — re-raising would loop to the iteration cap`
|
|
2342
|
+
: `${noPushSubject} landed no push for ${findings.length} finding(s) on HEAD ${head}`
|
|
2343
|
+
return { progressed: false, newSha: head, blocker }
|
|
2344
|
+
}
|
|
2345
|
+
|
|
2346
|
+
/**
|
|
2347
|
+
* Route after a successful P2-only fix. HEAD-bound CLEAN/review stamps are
|
|
2348
|
+
* SHA-specific: a push that moves HEAD must re-enter CONVERGE so those stamps
|
|
2349
|
+
* rebuild. A no-push progress (resolvedWithoutCommit) advances to the next
|
|
2350
|
+
* phase on the same HEAD.
|
|
2351
|
+
*
|
|
2352
|
+
* ::
|
|
2353
|
+
*
|
|
2354
|
+
* routeAfterP2OnlyFix('aaa', {newSha: 'bbb'}, 'COPILOT')
|
|
2355
|
+
* -> {fixedHead: 'bbb', nextPhase: 'CONVERGE', didMoveHead: true}
|
|
2356
|
+
* routeAfterP2OnlyFix('aaa', {newSha: 'aaa'}, 'COPILOT')
|
|
2357
|
+
* -> {fixedHead: 'aaa', nextPhase: 'COPILOT', didMoveHead: false}
|
|
2358
|
+
*
|
|
2359
|
+
* @param {string} priorHead HEAD SHA before the P2-only fix
|
|
2360
|
+
* @param {{newSha: string}} p2Fix successful applyP2OnlyFix result
|
|
2361
|
+
* @param {string} advancePhase phase to enter when HEAD did not move
|
|
2362
|
+
* @returns {{fixedHead: string, nextPhase: string, didMoveHead: boolean}} routing
|
|
2363
|
+
*/
|
|
2364
|
+
function routeAfterP2OnlyFix(priorHead, p2Fix, advancePhase) {
|
|
2365
|
+
const fixedHead = p2Fix.newSha
|
|
2366
|
+
const didMoveHead =
|
|
2367
|
+
normalizeShaForComparison(fixedHead) !== normalizeShaForComparison(priorHead)
|
|
2368
|
+
if (didMoveHead) {
|
|
2369
|
+
return { fixedHead, nextPhase: 'CONVERGE', didMoveHead: true }
|
|
2370
|
+
}
|
|
2371
|
+
return { fixedHead, nextPhase: advancePhase, didMoveHead: false }
|
|
2372
|
+
}
|
|
2373
|
+
|
|
2279
2374
|
/**
|
|
2280
2375
|
* Decide whether a standards-only round should file the follow-up fix issue and
|
|
2281
2376
|
* open the environment-hardening PR. Standards findings are deferred rather than
|
|
@@ -2660,6 +2755,23 @@ while (iterations < CONFIG.maxIterations) {
|
|
|
2660
2755
|
phase = 'BUGBOT'
|
|
2661
2756
|
continue
|
|
2662
2757
|
}
|
|
2758
|
+
if (isP2OnlyFindings(findings)) {
|
|
2759
|
+
resetNoLensRounds()
|
|
2760
|
+
const advancePhase = nextPhaseAfterP2OnlyFix('CONVERGE')
|
|
2761
|
+
log(`Round ${rounds}: ${findings.length} P2-only finding(s) — fixing once then routing from CONVERGE`)
|
|
2762
|
+
const p2Fix = await applyP2OnlyFix(head, findings, 'converge-round', 'converge round', 'fix lens')
|
|
2763
|
+
if (!p2Fix.progressed) {
|
|
2764
|
+
blocker = p2Fix.blocker
|
|
2765
|
+
break
|
|
2766
|
+
}
|
|
2767
|
+
const p2Route = routeAfterP2OnlyFix(head, p2Fix, advancePhase)
|
|
2768
|
+
head = p2Route.fixedHead
|
|
2769
|
+
phase = p2Route.nextPhase
|
|
2770
|
+
if (p2Route.didMoveHead) {
|
|
2771
|
+
log(`Round ${rounds}: P2-only fix moved HEAD — re-converging so HEAD-bound stamps rebuild`)
|
|
2772
|
+
}
|
|
2773
|
+
continue
|
|
2774
|
+
}
|
|
2663
2775
|
if (findings.length > 0) {
|
|
2664
2776
|
resetNoLensRounds()
|
|
2665
2777
|
log(`Round ${rounds}: ${findings.length} finding(s) — applying fixes`)
|
|
@@ -2732,6 +2844,23 @@ while (iterations < CONFIG.maxIterations) {
|
|
|
2732
2844
|
phase = 'COPILOT'
|
|
2733
2845
|
continue
|
|
2734
2846
|
}
|
|
2847
|
+
if (isP2OnlyFindings(bugbotOutcome.findings)) {
|
|
2848
|
+
const advancePhase = nextPhaseAfterP2OnlyFix('BUGBOT')
|
|
2849
|
+
log(`Bugbot raised ${bugbotOutcome.findings.length} P2-only finding(s) — fixing once then routing from BUGBOT`)
|
|
2850
|
+
const p2Fix = await applyP2OnlyFix(head, bugbotOutcome.findings, 'bugbot', 'bugbot gate', 'bugbot fix lens')
|
|
2851
|
+
if (!p2Fix.progressed) {
|
|
2852
|
+
blocker = p2Fix.blocker
|
|
2853
|
+
break
|
|
2854
|
+
}
|
|
2855
|
+
const p2Route = routeAfterP2OnlyFix(head, p2Fix, advancePhase)
|
|
2856
|
+
head = p2Route.fixedHead
|
|
2857
|
+
bugbotDown = false
|
|
2858
|
+
phase = p2Route.nextPhase
|
|
2859
|
+
if (p2Route.didMoveHead) {
|
|
2860
|
+
log('Bugbot P2-only fix moved HEAD — re-converging so HEAD-bound stamps rebuild')
|
|
2861
|
+
}
|
|
2862
|
+
continue
|
|
2863
|
+
}
|
|
2735
2864
|
log(`Bugbot raised ${bugbotOutcome.findings.length} finding(s) — fixing and re-converging`)
|
|
2736
2865
|
const fixResult = await applyFixes(head, bugbotOutcome.findings, 'bugbot')
|
|
2737
2866
|
const hadThreadBearingFinding = bugbotOutcome.findings.some((each) => collectFindingThreadIds(each).length > 0)
|
|
@@ -2813,6 +2942,22 @@ while (iterations < CONFIG.maxIterations) {
|
|
|
2813
2942
|
phase = 'CODEX'
|
|
2814
2943
|
continue
|
|
2815
2944
|
}
|
|
2945
|
+
if (isP2OnlyFindings(roundFindings)) {
|
|
2946
|
+
const advancePhase = nextPhaseAfterP2OnlyFix('COPILOT')
|
|
2947
|
+
log(`Copilot raised ${roundFindings.length} P2-only finding(s) — fixing once then routing from COPILOT`)
|
|
2948
|
+
const p2Fix = await applyP2OnlyFix(head, roundFindings, 'copilot', 'copilot round', 'copilot fix lens')
|
|
2949
|
+
if (!p2Fix.progressed) {
|
|
2950
|
+
blocker = p2Fix.blocker
|
|
2951
|
+
break
|
|
2952
|
+
}
|
|
2953
|
+
const p2Route = routeAfterP2OnlyFix(head, p2Fix, advancePhase)
|
|
2954
|
+
head = p2Route.fixedHead
|
|
2955
|
+
phase = p2Route.nextPhase
|
|
2956
|
+
if (p2Route.didMoveHead) {
|
|
2957
|
+
log('Copilot P2-only fix moved HEAD — re-converging so HEAD-bound stamps rebuild')
|
|
2958
|
+
}
|
|
2959
|
+
continue
|
|
2960
|
+
}
|
|
2816
2961
|
log(`Copilot raised ${roundFindings.length} finding(s) — fixing and re-converging`)
|
|
2817
2962
|
const fixResult = await applyFixes(head, roundFindings, 'copilot')
|
|
2818
2963
|
const hadThreadBearingFinding = roundFindings.some((each) => collectFindingThreadIds(each).length > 0)
|
|
@@ -2873,6 +3018,28 @@ while (iterations < CONFIG.maxIterations) {
|
|
|
2873
3018
|
phase = 'FINALIZE'
|
|
2874
3019
|
continue
|
|
2875
3020
|
}
|
|
3021
|
+
if (isP2OnlyFindings(codexOutcome.findings)) {
|
|
3022
|
+
const advancePhase = nextPhaseAfterP2OnlyFix('CODEX')
|
|
3023
|
+
log(`Codex raised ${codexOutcome.findings.length} P2-only finding(s) — fixing once then routing from CODEX`)
|
|
3024
|
+
const p2Fix = await applyP2OnlyFix(head, codexOutcome.findings, 'codex', 'codex gate', 'codex fix lens')
|
|
3025
|
+
if (!p2Fix.progressed) {
|
|
3026
|
+
blocker = p2Fix.blocker
|
|
3027
|
+
break
|
|
3028
|
+
}
|
|
3029
|
+
const p2Route = routeAfterP2OnlyFix(head, p2Fix, advancePhase)
|
|
3030
|
+
head = p2Route.fixedHead
|
|
3031
|
+
if (p2Route.didMoveHead) {
|
|
3032
|
+
log('Codex P2-only fix moved HEAD — re-converging so HEAD-bound stamps rebuild')
|
|
3033
|
+
codexDown = false
|
|
3034
|
+
codexCleanAt = null
|
|
3035
|
+
phase = p2Route.nextPhase
|
|
3036
|
+
continue
|
|
3037
|
+
}
|
|
3038
|
+
codexDown = false
|
|
3039
|
+
codexCleanAt = head
|
|
3040
|
+
phase = p2Route.nextPhase
|
|
3041
|
+
continue
|
|
3042
|
+
}
|
|
2876
3043
|
log(`Codex raised ${codexOutcome.findings.length} finding(s) — fixing and re-converging`)
|
|
2877
3044
|
const fixResult = await applyFixes(head, codexOutcome.findings, 'codex')
|
|
2878
3045
|
const hadThreadBearingFinding = codexOutcome.findings.some((each) => collectFindingThreadIds(each).length > 0)
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { test } from 'node:test';
|
|
2
|
+
import { strict as assert } from 'node:assert';
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
6
|
+
|
|
7
|
+
const workflowDirectory = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const convergeSource = readFileSync(join(workflowDirectory, 'converge.mjs'), 'utf8');
|
|
9
|
+
|
|
10
|
+
function functionBody(functionName) {
|
|
11
|
+
const functionStart = convergeSource.indexOf(`function ${functionName}(`);
|
|
12
|
+
assert.notEqual(functionStart, -1, `expected ${functionName} to exist`);
|
|
13
|
+
const nextFunctionStart = convergeSource.indexOf('\nfunction ', functionStart + 1);
|
|
14
|
+
const functionEnd = nextFunctionStart === -1 ? convergeSource.length : nextFunctionStart;
|
|
15
|
+
return convergeSource.slice(functionStart, functionEnd);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const productionModule = new Function(
|
|
19
|
+
`const SHA_COMPARISON_PREFIX_LENGTH = 7;\n` +
|
|
20
|
+
`${functionBody('normalizeShaForComparison')}\n` +
|
|
21
|
+
`${functionBody('isP2OnlyFindings')}\n` +
|
|
22
|
+
`${functionBody('nextPhaseAfterP2OnlyFix')}\n` +
|
|
23
|
+
`${functionBody('routeAfterP2OnlyFix')}\n` +
|
|
24
|
+
'return { isP2OnlyFindings, nextPhaseAfterP2OnlyFix, routeAfterP2OnlyFix };',
|
|
25
|
+
)();
|
|
26
|
+
|
|
27
|
+
const { isP2OnlyFindings, nextPhaseAfterP2OnlyFix, routeAfterP2OnlyFix } = productionModule;
|
|
28
|
+
|
|
29
|
+
function finding(overrides) {
|
|
30
|
+
return {
|
|
31
|
+
file: 'a.py',
|
|
32
|
+
line: 1,
|
|
33
|
+
severity: 'P2',
|
|
34
|
+
category: 'bug',
|
|
35
|
+
title: 't',
|
|
36
|
+
detail: 'd',
|
|
37
|
+
replyToCommentId: null,
|
|
38
|
+
...overrides,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function phaseBranch(phaseMarker) {
|
|
43
|
+
const phaseStart = convergeSource.indexOf(phaseMarker);
|
|
44
|
+
assert.notEqual(phaseStart, -1, `expected ${phaseMarker} to exist`);
|
|
45
|
+
const nextPhaseStart = convergeSource.indexOf('\n if (phase === ', phaseStart + 1);
|
|
46
|
+
const phaseEnd = nextPhaseStart === -1 ? convergeSource.length : nextPhaseStart;
|
|
47
|
+
return convergeSource.slice(phaseStart, phaseEnd);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
test('isP2OnlyFindings is false for an empty findings list', () => {
|
|
51
|
+
assert.equal(isP2OnlyFindings([]), false);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('isP2OnlyFindings is true when every finding is severity P2', () => {
|
|
55
|
+
assert.equal(isP2OnlyFindings([finding(), finding({ file: 'b.py', line: 2 })]), true);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('isP2OnlyFindings is false when a P1 is mixed in with P2 findings', () => {
|
|
59
|
+
assert.equal(isP2OnlyFindings([finding(), finding({ severity: 'P1' })]), false);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('isP2OnlyFindings is false when every finding is severity P1', () => {
|
|
63
|
+
assert.equal(isP2OnlyFindings([finding({ severity: 'P1' })]), false);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('isP2OnlyFindings is false when a finding is missing severity', () => {
|
|
67
|
+
assert.equal(isP2OnlyFindings([{ file: 'a.py', line: 1, category: 'bug' }]), false);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('nextPhaseAfterP2OnlyFix advances CONVERGE to BUGBOT', () => {
|
|
71
|
+
assert.equal(nextPhaseAfterP2OnlyFix('CONVERGE'), 'BUGBOT');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('nextPhaseAfterP2OnlyFix advances BUGBOT to COPILOT', () => {
|
|
75
|
+
assert.equal(nextPhaseAfterP2OnlyFix('BUGBOT'), 'COPILOT');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('nextPhaseAfterP2OnlyFix advances COPILOT to CODEX', () => {
|
|
79
|
+
assert.equal(nextPhaseAfterP2OnlyFix('COPILOT'), 'CODEX');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('nextPhaseAfterP2OnlyFix advances CODEX to FINALIZE', () => {
|
|
83
|
+
assert.equal(nextPhaseAfterP2OnlyFix('CODEX'), 'FINALIZE');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('routeAfterP2OnlyFix re-converges when the fix moved HEAD', () => {
|
|
87
|
+
const route = routeAfterP2OnlyFix('aaa111', { newSha: 'bbb222' }, 'COPILOT');
|
|
88
|
+
assert.equal(route.didMoveHead, true);
|
|
89
|
+
assert.equal(route.fixedHead, 'bbb222');
|
|
90
|
+
assert.equal(route.nextPhase, 'CONVERGE');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('routeAfterP2OnlyFix advances when HEAD is unchanged', () => {
|
|
94
|
+
const route = routeAfterP2OnlyFix('aaa111', { newSha: 'aaa111' }, 'COPILOT');
|
|
95
|
+
assert.equal(route.didMoveHead, false);
|
|
96
|
+
assert.equal(route.fixedHead, 'aaa111');
|
|
97
|
+
assert.equal(route.nextPhase, 'COPILOT');
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('nextPhaseAfterP2OnlyFix uses an in-function lookup map', () => {
|
|
101
|
+
const body = functionBody('nextPhaseAfterP2OnlyFix');
|
|
102
|
+
assert.match(body, /nextPhaseByCurrent/);
|
|
103
|
+
assert.match(body, /CONVERGE:\s*'BUGBOT'/);
|
|
104
|
+
assert.match(body, /BUGBOT:\s*'COPILOT'/);
|
|
105
|
+
assert.match(body, /COPILOT:\s*'CODEX'/);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test('applyP2OnlyFix runs applyFixes then detectFixProgress in order', () => {
|
|
109
|
+
const body = functionBody('applyP2OnlyFix');
|
|
110
|
+
const applyIndex = body.indexOf('applyFixes(head, findings, sourceLabel)');
|
|
111
|
+
const detectIndex = body.indexOf('detectFixProgress(fixResult, head, hadThreadBearingFinding)');
|
|
112
|
+
assert.notEqual(applyIndex, -1, 'expected applyFixes in applyP2OnlyFix');
|
|
113
|
+
assert.notEqual(detectIndex, -1, 'expected detectFixProgress in applyP2OnlyFix');
|
|
114
|
+
assert.ok(applyIndex < detectIndex, 'applyFixes must precede detectFixProgress');
|
|
115
|
+
assert.match(body, /collectFindingThreadIds/);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('CONVERGE places the P2-only branch between standards-only and generic fix', () => {
|
|
119
|
+
const convergeBranch = phaseBranch("if (phase === 'CONVERGE')");
|
|
120
|
+
const standardsIndex = convergeBranch.indexOf('isStandardsOnlyRound(findings)');
|
|
121
|
+
const p2OnlyIndex = convergeBranch.indexOf('isP2OnlyFindings(findings)');
|
|
122
|
+
const genericFixIndex = convergeBranch.indexOf("finding(s) — applying fixes");
|
|
123
|
+
assert.notEqual(standardsIndex, -1, 'expected the standards-only branch');
|
|
124
|
+
assert.notEqual(p2OnlyIndex, -1, 'expected the P2-only branch');
|
|
125
|
+
assert.notEqual(genericFixIndex, -1, 'expected the generic fix branch');
|
|
126
|
+
assert.ok(standardsIndex < p2OnlyIndex, 'standards-only must precede P2-only');
|
|
127
|
+
assert.ok(p2OnlyIndex < genericFixIndex, 'P2-only must precede generic fix');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test('CONVERGE P2-only branch fixes once and routes via routeAfterP2OnlyFix', () => {
|
|
131
|
+
const convergeBranch = phaseBranch("if (phase === 'CONVERGE')");
|
|
132
|
+
const p2Start = convergeBranch.indexOf('isP2OnlyFindings(findings)');
|
|
133
|
+
const genericFixStart = convergeBranch.indexOf("finding(s) — applying fixes");
|
|
134
|
+
const p2Branch = convergeBranch.slice(p2Start, genericFixStart);
|
|
135
|
+
assert.match(p2Branch, /P2-only/);
|
|
136
|
+
assert.match(p2Branch, /applyP2OnlyFix\(head, findings, 'converge-round'/);
|
|
137
|
+
assert.match(p2Branch, /routeAfterP2OnlyFix\(head, p2Fix, advancePhase\)/);
|
|
138
|
+
assert.match(p2Branch, /nextPhaseAfterP2OnlyFix\('CONVERGE'\)/);
|
|
139
|
+
assert.match(p2Branch, /head = p2Route\.fixedHead/);
|
|
140
|
+
assert.match(p2Branch, /phase = p2Route\.nextPhase/);
|
|
141
|
+
assert.doesNotMatch(p2Branch, /head = null/);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('BUGBOT P2-only branch routes through routeAfterP2OnlyFix', () => {
|
|
145
|
+
const bugbotBranch = phaseBranch("if (phase === 'BUGBOT')");
|
|
146
|
+
const standardsIndex = bugbotBranch.indexOf('isStandardsOnlyRound(bugbotOutcome.findings)');
|
|
147
|
+
const p2OnlyIndex = bugbotBranch.indexOf('isP2OnlyFindings(bugbotOutcome.findings)');
|
|
148
|
+
const genericFixIndex = bugbotBranch.indexOf('fixing and re-converging');
|
|
149
|
+
assert.ok(standardsIndex < p2OnlyIndex, 'standards-only must precede P2-only on BUGBOT');
|
|
150
|
+
assert.ok(p2OnlyIndex < genericFixIndex, 'P2-only must precede generic re-converge on BUGBOT');
|
|
151
|
+
const p2Branch = bugbotBranch.slice(p2OnlyIndex, genericFixIndex);
|
|
152
|
+
assert.match(p2Branch, /P2-only/);
|
|
153
|
+
assert.match(p2Branch, /nextPhaseAfterP2OnlyFix\('BUGBOT'\)/);
|
|
154
|
+
assert.match(p2Branch, /applyP2OnlyFix\(head, bugbotOutcome\.findings, 'bugbot'/);
|
|
155
|
+
assert.match(p2Branch, /routeAfterP2OnlyFix\(head, p2Fix, advancePhase\)/);
|
|
156
|
+
assert.match(p2Branch, /phase = p2Route\.nextPhase/);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test('COPILOT P2-only branch routes through routeAfterP2OnlyFix', () => {
|
|
160
|
+
const copilotBranch = phaseBranch("if (phase === 'COPILOT')");
|
|
161
|
+
const standardsIndex = copilotBranch.indexOf('isStandardsOnlyRound(roundFindings)');
|
|
162
|
+
const p2OnlyIndex = copilotBranch.indexOf('isP2OnlyFindings(roundFindings)');
|
|
163
|
+
const genericFixIndex = copilotBranch.indexOf('fixing and re-converging');
|
|
164
|
+
assert.ok(standardsIndex < p2OnlyIndex, 'standards-only must precede P2-only on COPILOT');
|
|
165
|
+
assert.ok(p2OnlyIndex < genericFixIndex, 'P2-only must precede generic re-converge on COPILOT');
|
|
166
|
+
const p2Branch = copilotBranch.slice(p2OnlyIndex, genericFixIndex);
|
|
167
|
+
assert.match(p2Branch, /P2-only/);
|
|
168
|
+
assert.match(p2Branch, /nextPhaseAfterP2OnlyFix\('COPILOT'\)/);
|
|
169
|
+
assert.match(p2Branch, /applyP2OnlyFix\(head, roundFindings, 'copilot'/);
|
|
170
|
+
assert.match(p2Branch, /routeAfterP2OnlyFix\(head, p2Fix, advancePhase\)/);
|
|
171
|
+
assert.match(p2Branch, /phase = p2Route\.nextPhase/);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test('CODEX P2-only branch routes through routeAfterP2OnlyFix and stamps codexCleanAt only when HEAD is stable', () => {
|
|
175
|
+
const codexBranch = phaseBranch("if (phase === 'CODEX')");
|
|
176
|
+
const standardsIndex = codexBranch.indexOf('isStandardsOnlyRound(codexOutcome.findings)');
|
|
177
|
+
const p2OnlyIndex = codexBranch.indexOf('isP2OnlyFindings(codexOutcome.findings)');
|
|
178
|
+
const genericFixIndex = codexBranch.indexOf('fixing and re-converging');
|
|
179
|
+
assert.ok(standardsIndex < p2OnlyIndex, 'standards-only must precede P2-only on CODEX');
|
|
180
|
+
assert.ok(p2OnlyIndex < genericFixIndex, 'P2-only must precede generic re-converge on CODEX');
|
|
181
|
+
const p2Branch = codexBranch.slice(p2OnlyIndex, genericFixIndex);
|
|
182
|
+
assert.match(p2Branch, /P2-only/);
|
|
183
|
+
assert.match(p2Branch, /nextPhaseAfterP2OnlyFix\('CODEX'\)/);
|
|
184
|
+
assert.match(p2Branch, /applyP2OnlyFix\(head, codexOutcome\.findings, 'codex'/);
|
|
185
|
+
assert.match(p2Branch, /routeAfterP2OnlyFix\(head, p2Fix, advancePhase\)/);
|
|
186
|
+
assert.match(p2Branch, /codexCleanAt = head/);
|
|
187
|
+
assert.match(p2Branch, /didMoveHead/);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test('generic fix branches still re-converge for mixed or P0/P1 findings', () => {
|
|
191
|
+
const bugbotBranch = phaseBranch("if (phase === 'BUGBOT')");
|
|
192
|
+
const genericStart = bugbotBranch.indexOf('fixing and re-converging');
|
|
193
|
+
const genericBranch = bugbotBranch.slice(genericStart);
|
|
194
|
+
assert.match(genericBranch, /phase = 'CONVERGE'/);
|
|
195
|
+
assert.match(genericBranch, /head = null/);
|
|
196
|
+
|
|
197
|
+
const copilotBranch = phaseBranch("if (phase === 'COPILOT')");
|
|
198
|
+
const copilotGenericStart = copilotBranch.indexOf('fixing and re-converging');
|
|
199
|
+
const copilotGeneric = copilotBranch.slice(copilotGenericStart);
|
|
200
|
+
assert.match(copilotGeneric, /phase = 'CONVERGE'/);
|
|
201
|
+
assert.match(copilotGeneric, /head = null/);
|
|
202
|
+
});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
{"type": "user", "uuid": "a11d903476b803493-u", "message": {"role": "user", "content": "Return the structured result."}}
|
|
2
|
-
{"type": "assistant", "uuid": "a11d903476b803493-a", "message": {"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_a11d903476b803493", "name": "StructuredOutput", "input": {"sha": "7c2f420c4d5b7c83aa47f93d99a0f1420e3373c4", "clean": false, "findings": [{"file": "src/exports/core/export_runner.py", "line": 96, "severity": "P2", "title": "New inline log string literal flagged by Magic-values rule", "detail": "Copilot (CodingGuidelineID 1000000, \"Magic values & configuration\"): the new log message at this line introduces a new string literal in production code. Prefer reusing an existing configured UI message (e.g. web_editor_config.ui_messages.msg_detected_version) instead of adding a new inline literal.", "replyToCommentId": 3407912224}, {"file": "src/web/services/os_generation_ssot.py", "line": 265, "severity": "P2", "title": "New inline warning string literal flagged by Magic-values rule", "detail": "Copilot (CodingGuidelineID 1000000, \"Magic values & configuration\"): read_current_version_name_or_none() adds a new inline warning string in production code. Per repo convention, extract this message into a shared config constant (in src/shared/web_automation/config/) so future callers reuse it consistently.", "replyToCommentId": 3407912234}], "blocker": null}}]}}
|
|
1
|
+
{"type": "user", "uuid": "a11d903476b803493-u", "message": {"role": "user", "content": "Return the structured result."}}
|
|
2
|
+
{"type": "assistant", "uuid": "a11d903476b803493-a", "message": {"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_a11d903476b803493", "name": "StructuredOutput", "input": {"sha": "7c2f420c4d5b7c83aa47f93d99a0f1420e3373c4", "clean": false, "findings": [{"file": "src/exports/core/export_runner.py", "line": 96, "severity": "P2", "title": "New inline log string literal flagged by Magic-values rule", "detail": "Copilot (CodingGuidelineID 1000000, \"Magic values & configuration\"): the new log message at this line introduces a new string literal in production code. Prefer reusing an existing configured UI message (e.g. web_editor_config.ui_messages.msg_detected_version) instead of adding a new inline literal.", "replyToCommentId": 3407912224}, {"file": "src/web/services/os_generation_ssot.py", "line": 265, "severity": "P2", "title": "New inline warning string literal flagged by Magic-values rule", "detail": "Copilot (CodingGuidelineID 1000000, \"Magic values & configuration\"): read_current_version_name_or_none() adds a new inline warning string in production code. Per repo convention, extract this message into a shared config constant (in src/shared/web_automation/config/) so future callers reuse it consistently.", "replyToCommentId": 3407912234}], "blocker": null}}]}}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
{"type": "user", "uuid": "a26213978adeef6fb-u", "message": {"role": "user", "content": "Return the structured result."}}
|
|
2
|
-
{"type": "assistant", "uuid": "a26213978adeef6fb-a", "message": {"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_a26213978adeef6fb", "name": "StructuredOutput", "input": {"newSha": "620382f766c4731ba92eefeb30bdbb9d0bcd4c90", "pushed": true, "resolvedWithoutCommit": false, "summary": "Fixed all 11 Copilot findings in one commit (620382f7): renamed banned `result` to `skip_path` in test_resume_skip_export.py and added `-> None` return annotations to the test functions across test_resume_skip_export.py, test_stp_path_selection.py, test_version_export_guards.py, and test_import_isolation.py; all 9 affected tests pass; pushed to fix/example-feature, posted 11 inline replies, and all 11 review threads are resolved."}}]}}
|
|
1
|
+
{"type": "user", "uuid": "a26213978adeef6fb-u", "message": {"role": "user", "content": "Return the structured result."}}
|
|
2
|
+
{"type": "assistant", "uuid": "a26213978adeef6fb-a", "message": {"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_a26213978adeef6fb", "name": "StructuredOutput", "input": {"newSha": "620382f766c4731ba92eefeb30bdbb9d0bcd4c90", "pushed": true, "resolvedWithoutCommit": false, "summary": "Fixed all 11 Copilot findings in one commit (620382f7): renamed banned `result` to `skip_path` in test_resume_skip_export.py and added `-> None` return annotations to the test functions across test_resume_skip_export.py, test_stp_path_selection.py, test_version_export_guards.py, and test_import_isolation.py; all 9 affected tests pass; pushed to fix/example-feature, posted 11 inline replies, and all 11 review threads are resolved."}}]}}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
{"type": "user", "uuid": "a3def0d15ed9d9110-u", "message": {"role": "user", "content": "Return the structured result."}}
|
|
2
|
-
{"type": "assistant", "uuid": "a3def0d15ed9d9110-a", "message": {"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_a3def0d15ed9d9110", "name": "StructuredOutput", "input": {"sha": "6a5169ef635ddb841e6f0465a309691ff77f033e", "clean": false, "blocker": null, "findings": [{"file": "src/exports/tests/test_resume_skip_export.py", "line": 35, "severity": "P2", "title": "Banned identifier `result` in test", "detail": "Naming guideline (CodingGuidelineID 1000000): newly introduced identifier `result` is banned; rename to a descriptive name such as `existing_apk_path` or `skip_path`.", "replyToCommentId": 3407883689}, {"file": "src/exports/tests/test_resume_skip_export.py", "line": 47, "severity": "P2", "title": "Banned identifier `result` in test", "detail": "Naming guideline (CodingGuidelineID 1000000): newly introduced identifier `result` is banned; rename to a descriptive name such as `existing_apk_path` or `skip_path`.", "replyToCommentId": 3407883707}, {"file": "src/logging/tests/test_import_isolation.py", "line": 33, "severity": "P2", "title": "Missing return type annotation on test function", "detail": "Repository guideline (CodingGuidelineID 1000000 \u2014 Types): newly added test function is missing an explicit return type annotation. Add `-> None`.", "replyToCommentId": 3407883713}, {"file": "src/logging/tests/test_import_isolation.py", "line": 43, "severity": "P2", "title": "Missing return type annotation on test function", "detail": "Repository guideline (CodingGuidelineID 1000000 \u2014 Types): newly added test function is missing an explicit return type annotation. Add `-> None`.", "replyToCommentId": 3407883717}, {"file": "src/exports/tests/test_version_export_guards.py", "line": 37, "severity": "P2", "title": "Missing return type annotation on async test", "detail": "Repository guideline (CodingGuidelineID 1000000 \u2014 Types): newly added async test is missing an explicit return type annotation. Add `-> None`.", "replyToCommentId": 3407883723}, {"file": "src/exports/tests/test_version_export_guards.py", "line": 74, "severity": "P2", "title": "Missing return type annotation on async test", "detail": "Repository guideline (CodingGuidelineID 1000000 \u2014 Types): newly added async test is missing an explicit return type annotation. Add `-> None`.", "replyToCommentId": 3407883727}, {"file": "src/exports/tests/test_stp_path_selection.py", "line": 19, "severity": "P2", "title": "Missing return type annotation on test function", "detail": "Repository guideline (CodingGuidelineID 1000000 \u2014 Types): newly added test function is missing an explicit return type annotation. Add `-> None`.", "replyToCommentId": 3407883731}, {"file": "src/exports/tests/test_stp_path_selection.py", "line": 31, "severity": "P2", "title": "Missing return type annotation on test function", "detail": "Repository guideline (CodingGuidelineID 1000000 \u2014 Types): newly added test function is missing an explicit return type annotation. Add `-> None`.", "replyToCommentId": 3407883736}, {"file": "src/exports/tests/test_stp_path_selection.py", "line": 43, "severity": "P2", "title": "Missing return type annotation on test function", "detail": "Repository guideline (CodingGuidelineID 1000000 \u2014 Types): newly added test function is missing an explicit return type annotation. Add `-> None`.", "replyToCommentId": 3407883740}, {"file": "src/exports/tests/test_resume_skip_export.py", "line": 21, "severity": "P2", "title": "Missing return type annotation on test function", "detail": "Repository guideline (CodingGuidelineID 1000000 \u2014 Types): newly added test function is missing an explicit return type annotation. Add `-> None`.", "replyToCommentId": 3407883749}, {"file": "src/exports/tests/test_resume_skip_export.py", "line": 38, "severity": "P2", "title": "Missing return type annotation on test function", "detail": "Repository guideline (CodingGuidelineID 1000000 \u2014 Types): newly added test function is missing an explicit return type annotation. Add `-> None`.", "replyToCommentId": 3407883755}]}}]}}
|
|
1
|
+
{"type": "user", "uuid": "a3def0d15ed9d9110-u", "message": {"role": "user", "content": "Return the structured result."}}
|
|
2
|
+
{"type": "assistant", "uuid": "a3def0d15ed9d9110-a", "message": {"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_a3def0d15ed9d9110", "name": "StructuredOutput", "input": {"sha": "6a5169ef635ddb841e6f0465a309691ff77f033e", "clean": false, "blocker": null, "findings": [{"file": "src/exports/tests/test_resume_skip_export.py", "line": 35, "severity": "P2", "title": "Banned identifier `result` in test", "detail": "Naming guideline (CodingGuidelineID 1000000): newly introduced identifier `result` is banned; rename to a descriptive name such as `existing_apk_path` or `skip_path`.", "replyToCommentId": 3407883689}, {"file": "src/exports/tests/test_resume_skip_export.py", "line": 47, "severity": "P2", "title": "Banned identifier `result` in test", "detail": "Naming guideline (CodingGuidelineID 1000000): newly introduced identifier `result` is banned; rename to a descriptive name such as `existing_apk_path` or `skip_path`.", "replyToCommentId": 3407883707}, {"file": "src/logging/tests/test_import_isolation.py", "line": 33, "severity": "P2", "title": "Missing return type annotation on test function", "detail": "Repository guideline (CodingGuidelineID 1000000 \u2014 Types): newly added test function is missing an explicit return type annotation. Add `-> None`.", "replyToCommentId": 3407883713}, {"file": "src/logging/tests/test_import_isolation.py", "line": 43, "severity": "P2", "title": "Missing return type annotation on test function", "detail": "Repository guideline (CodingGuidelineID 1000000 \u2014 Types): newly added test function is missing an explicit return type annotation. Add `-> None`.", "replyToCommentId": 3407883717}, {"file": "src/exports/tests/test_version_export_guards.py", "line": 37, "severity": "P2", "title": "Missing return type annotation on async test", "detail": "Repository guideline (CodingGuidelineID 1000000 \u2014 Types): newly added async test is missing an explicit return type annotation. Add `-> None`.", "replyToCommentId": 3407883723}, {"file": "src/exports/tests/test_version_export_guards.py", "line": 74, "severity": "P2", "title": "Missing return type annotation on async test", "detail": "Repository guideline (CodingGuidelineID 1000000 \u2014 Types): newly added async test is missing an explicit return type annotation. Add `-> None`.", "replyToCommentId": 3407883727}, {"file": "src/exports/tests/test_stp_path_selection.py", "line": 19, "severity": "P2", "title": "Missing return type annotation on test function", "detail": "Repository guideline (CodingGuidelineID 1000000 \u2014 Types): newly added test function is missing an explicit return type annotation. Add `-> None`.", "replyToCommentId": 3407883731}, {"file": "src/exports/tests/test_stp_path_selection.py", "line": 31, "severity": "P2", "title": "Missing return type annotation on test function", "detail": "Repository guideline (CodingGuidelineID 1000000 \u2014 Types): newly added test function is missing an explicit return type annotation. Add `-> None`.", "replyToCommentId": 3407883736}, {"file": "src/exports/tests/test_stp_path_selection.py", "line": 43, "severity": "P2", "title": "Missing return type annotation on test function", "detail": "Repository guideline (CodingGuidelineID 1000000 \u2014 Types): newly added test function is missing an explicit return type annotation. Add `-> None`.", "replyToCommentId": 3407883740}, {"file": "src/exports/tests/test_resume_skip_export.py", "line": 21, "severity": "P2", "title": "Missing return type annotation on test function", "detail": "Repository guideline (CodingGuidelineID 1000000 \u2014 Types): newly added test function is missing an explicit return type annotation. Add `-> None`.", "replyToCommentId": 3407883749}, {"file": "src/exports/tests/test_resume_skip_export.py", "line": 38, "severity": "P2", "title": "Missing return type annotation on test function", "detail": "Repository guideline (CodingGuidelineID 1000000 \u2014 Types): newly added test function is missing an explicit return type annotation. Add `-> None`.", "replyToCommentId": 3407883755}]}}]}}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
{"type": "user", "uuid": "a41f41b1b708ee3b7-u", "message": {"role": "user", "content": "Return the structured result."}}
|
|
2
|
-
{"type": "assistant", "uuid": "a41f41b1b708ee3b7-a", "message": {"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_a41f41b1b708ee3b7", "name": "StructuredOutput", "input": {"sha": "7c2f420c4d5b7c83aa47f93d99a0f1420e3373c4", "clean": true, "findings": [], "blocker": null}}]}}
|
|
1
|
+
{"type": "user", "uuid": "a41f41b1b708ee3b7-u", "message": {"role": "user", "content": "Return the structured result."}}
|
|
2
|
+
{"type": "assistant", "uuid": "a41f41b1b708ee3b7-a", "message": {"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_a41f41b1b708ee3b7", "name": "StructuredOutput", "input": {"sha": "7c2f420c4d5b7c83aa47f93d99a0f1420e3373c4", "clean": true, "findings": [], "blocker": null}}]}}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
{"type": "user", "uuid": "a758b880abecc3ff7-u", "message": {"role": "user", "content": "Return the structured result."}}
|
|
2
|
-
{"type": "assistant", "uuid": "a758b880abecc3ff7-a", "message": {"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_a758b880abecc3ff7", "name": "StructuredOutput", "input": {"newSha": "7c2f420c4d5b7c83aa47f93d99a0f1420e3373c4", "pushed": false, "resolvedWithoutCommit": true, "summary": "Both Copilot magic-value findings were already fixed at HEAD 7c2f420c (export_runner.py uses web_editor_config.ui_messages.msg_detected_version; os_generation_ssot.py uses os_generation_ssot_constants.unavailable_warning_template); posted inline replies and resolved both review threads (PRRT_kwDORiaSZc6JUqSw, PRRT_kwDORiaSZc6JUqS6)."}}]}}
|
|
1
|
+
{"type": "user", "uuid": "a758b880abecc3ff7-u", "message": {"role": "user", "content": "Return the structured result."}}
|
|
2
|
+
{"type": "assistant", "uuid": "a758b880abecc3ff7-a", "message": {"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_a758b880abecc3ff7", "name": "StructuredOutput", "input": {"newSha": "7c2f420c4d5b7c83aa47f93d99a0f1420e3373c4", "pushed": false, "resolvedWithoutCommit": true, "summary": "Both Copilot magic-value findings were already fixed at HEAD 7c2f420c (export_runner.py uses web_editor_config.ui_messages.msg_detected_version; os_generation_ssot.py uses os_generation_ssot_constants.unavailable_warning_template); posted inline replies and resolved both review threads (PRRT_kwDORiaSZc6JUqSw, PRRT_kwDORiaSZc6JUqS6)."}}]}}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
{"type": "user", "uuid": "a8897b89656b1bd16-u", "message": {"role": "user", "content": "Return the structured result."}}
|
|
2
|
-
{"type": "assistant", "uuid": "a8897b89656b1bd16-a", "message": {"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_a8897b89656b1bd16", "name": "StructuredOutput", "input": {"newSha": "7c2f420c4d5b7c83aa47f93d99a0f1420e3373c4", "pushed": true, "resolvedWithoutCommit": false, "summary": "Fixed both Copilot magic-value findings on PR #211: export_runner.py now reuses web_editor_config.ui_messages.msg_detected_version, and os_generation_ssot.py references a new os_generation_ssot_constants.unavailable_warning_template. Added a behavioral TDD test, committed (7c2f420c) and pushed; posted inline replies to both comments (3407912224, 3407912234) and resolved both review threads (PRRT_kwDORiaSZc6JUqSw, PRRT_kwDORiaSZc6JUqS6)."}}]}}
|
|
1
|
+
{"type": "user", "uuid": "a8897b89656b1bd16-u", "message": {"role": "user", "content": "Return the structured result."}}
|
|
2
|
+
{"type": "assistant", "uuid": "a8897b89656b1bd16-a", "message": {"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_a8897b89656b1bd16", "name": "StructuredOutput", "input": {"newSha": "7c2f420c4d5b7c83aa47f93d99a0f1420e3373c4", "pushed": true, "resolvedWithoutCommit": false, "summary": "Fixed both Copilot magic-value findings on PR #211: export_runner.py now reuses web_editor_config.ui_messages.msg_detected_version, and os_generation_ssot.py references a new os_generation_ssot_constants.unavailable_warning_template. Added a behavioral TDD test, committed (7c2f420c) and pushed; posted inline replies to both comments (3407912224, 3407912234) and resolved both review threads (PRRT_kwDORiaSZc6JUqSw, PRRT_kwDORiaSZc6JUqS6)."}}]}}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
{"type": "user", "uuid": "abd463d744a1437bc-u", "message": {"role": "user", "content": "Return the structured result."}}
|
|
2
|
-
{"type": "assistant", "uuid": "abd463d744a1437bc-a", "message": {"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_abd463d744a1437bc", "name": "StructuredOutput", "input": {"sha": "6a5169ef635ddb841e6f0465a309691ff77f033e", "clean": true, "down": false, "findings": []}}]}}
|
|
1
|
+
{"type": "user", "uuid": "abd463d744a1437bc-u", "message": {"role": "user", "content": "Return the structured result."}}
|
|
2
|
+
{"type": "assistant", "uuid": "abd463d744a1437bc-a", "message": {"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_abd463d744a1437bc", "name": "StructuredOutput", "input": {"sha": "6a5169ef635ddb841e6f0465a309691ff77f033e", "clean": true, "down": false, "findings": []}}]}}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
{"type": "user", "uuid": "ad19d027ae8ee1816-u", "message": {"role": "user", "content": "Return the structured result."}}
|
|
2
|
-
{"type": "assistant", "uuid": "ad19d027ae8ee1816-a", "message": {"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_ad19d027ae8ee1816", "name": "StructuredOutput", "input": {"sha": "620382f766c4731ba92eefeb30bdbb9d0bcd4c90", "clean": false, "findings": [{"file": "src/exports/core/export_runner.py", "line": 94, "severity": "P2", "title": "New inline log string literal in production code", "detail": "Copilot (CodingGuidelineID 1000000, Magic values & configuration): the new log message at this line introduces a new string literal in production code. Prefer reusing an existing configured UI message (e.g., web_editor_config.ui_messages.msg_detected_version) instead of adding a new inline literal here.", "replyToCommentId": 3407912224}, {"file": "src/web/services/os_generation_ssot.py", "line": 266, "severity": "P2", "title": "New inline warning string literal in read_current_version_name_or_none()", "detail": "Copilot (CodingGuidelineID 1000000, Magic values & configuration): read_current_version_name_or_none() adds a new inline warning string in production code. Per repo convention, extract this message into a shared config constant (in src/shared/web_automation/config/) so future callers reuse it consistently.", "replyToCommentId": 3407912234}], "blocker": null}}]}}
|
|
1
|
+
{"type": "user", "uuid": "ad19d027ae8ee1816-u", "message": {"role": "user", "content": "Return the structured result."}}
|
|
2
|
+
{"type": "assistant", "uuid": "ad19d027ae8ee1816-a", "message": {"role": "assistant", "content": [{"type": "tool_use", "id": "toolu_ad19d027ae8ee1816", "name": "StructuredOutput", "input": {"sha": "620382f766c4731ba92eefeb30bdbb9d0bcd4c90", "clean": false, "findings": [{"file": "src/exports/core/export_runner.py", "line": 94, "severity": "P2", "title": "New inline log string literal in production code", "detail": "Copilot (CodingGuidelineID 1000000, Magic values & configuration): the new log message at this line introduces a new string literal in production code. Prefer reusing an existing configured UI message (e.g., web_editor_config.ui_messages.msg_detected_version) instead of adding a new inline literal here.", "replyToCommentId": 3407912224}, {"file": "src/web/services/os_generation_ssot.py", "line": 266, "severity": "P2", "title": "New inline warning string literal in read_current_version_name_or_none()", "detail": "Copilot (CodingGuidelineID 1000000, Magic values & configuration): read_current_version_name_or_none() adds a new inline warning string in production code. Per repo convention, extract this message into a shared config constant (in src/shared/web_automation/config/) so future callers reuse it consistently.", "replyToCommentId": 3407912234}], "blocker": null}}]}}
|