claude-dev-env 1.93.1 → 1.95.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/_shared/advisor/CLAUDE.md +2 -2
- package/_shared/advisor/advisor-protocol.md +35 -27
- package/_shared/advisor/scripts/config/advisor_scripts_constants/model_tier_run_validator_constants.py +3 -2
- package/_shared/advisor/scripts/model_tier_run_validator.py +23 -15
- package/_shared/advisor/scripts/tests/test_model_tier_run_validator.py +81 -17
- package/_shared/pr-loop/CLAUDE.md +1 -0
- package/_shared/pr-loop/audit-contract.md +1 -1
- package/_shared/pr-loop/gh-payloads.md +3 -3
- package/_shared/pr-loop/post-audit-thread-contract.md +51 -0
- package/_shared/pr-loop/scripts/README.md +2 -2
- package/_shared/pr-loop/scripts/fix_hookspath.py +47 -12
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +0 -69
- package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +497 -374
- package/_shared/pr-loop/state-schema.md +3 -22
- package/bin/CLAUDE.md +11 -2
- package/bin/ever-shipped-skills.mjs +70 -0
- package/bin/install.mjs +138 -13
- package/bin/install.prune.test.mjs +457 -0
- package/bin/install.test.mjs +10 -4
- package/docs/CODE_RULES.md +1 -1
- package/hooks/blocking/CLAUDE.md +2 -0
- package/hooks/blocking/code_rules_enforcer.py +4 -0
- package/hooks/blocking/code_rules_shared.py +82 -0
- package/hooks/blocking/code_rules_test_layout.py +9 -3
- package/hooks/blocking/pii_commit_command.py +398 -0
- package/hooks/blocking/pii_payload_scan.py +133 -0
- package/hooks/blocking/pii_prevention_blocker.py +151 -449
- package/hooks/blocking/plain_language_blocker.py +138 -4
- package/hooks/blocking/sensitive_file_protector.py +114 -48
- package/hooks/blocking/tdd_enforcer.py +9 -2
- package/hooks/blocking/test_code_rules_enforcer_scratchpad.py +105 -0
- package/hooks/blocking/test_code_rules_shared.py +181 -0
- package/hooks/blocking/test_pii_prevention_blocker.py +299 -0
- package/hooks/blocking/test_plain_language_blocker_allowlist.py +184 -0
- package/hooks/blocking/test_sensitive_file_protector.py +185 -0
- package/hooks/blocking/test_tdd_enforcer_scratchpad.py +105 -0
- package/hooks/blocking/test_verdict_directory_write_blocker.py +42 -7
- package/hooks/hooks_constants/CLAUDE.md +4 -2
- package/hooks/hooks_constants/code_rules_path_utils_constants.py +0 -2
- package/hooks/hooks_constants/harness_scratchpad_constants.py +17 -0
- package/hooks/hooks_constants/local_identity.py +65 -15
- package/hooks/hooks_constants/pii_prevention_constants.py +16 -0
- package/hooks/hooks_constants/plain_language_blocker_constants.py +5 -0
- package/hooks/hooks_constants/pr_description_enforcer_constants.py +1 -1
- package/hooks/hooks_constants/sensitive_file_protector_constants.py +42 -0
- package/hooks/hooks_constants/test_local_identity.py +68 -0
- package/hooks/pyproject.toml +75 -4
- package/hooks/validators/CLAUDE.md +1 -1
- package/hooks/validators/README.md +2 -0
- package/hooks/validators/python_style_checks.py +114 -136
- package/hooks/validators/python_style_helpers.py +95 -0
- package/hooks/validators/test_python_style_checks.py +0 -164
- package/hooks/validators/test_python_style_checks_decorator_gap.py +119 -0
- package/hooks/validators/test_python_style_fixes.py +251 -0
- package/hooks/validators/test_python_style_helpers.py +125 -0
- package/package.json +1 -1
- package/rules/CLAUDE.md +1 -0
- package/rules/anti-corollary-tests.md +69 -0
- package/rules/bdd.md +1 -3
- package/rules/code-reviews.md +1 -1
- package/rules/gh-paginate.md +1 -1
- package/rules/plain-language.md +2 -0
- package/scripts/CLAUDE.md +10 -1
- package/scripts/Get-SessionAccount.ps1 +210 -0
- package/scripts/tests/CLAUDE.md +15 -1
- package/scripts/tests/Get-SessionAccount.Tests.ps1 +350 -0
- package/skills/CLAUDE.md +6 -27
- package/skills/anthropic-plan/SKILL.md +1 -13
- package/skills/autoconverge/CLAUDE.md +5 -2
- package/skills/autoconverge/SKILL.md +112 -387
- package/skills/autoconverge/reference/CLAUDE.md +4 -1
- package/skills/autoconverge/reference/closing-report.md +9 -2
- package/skills/autoconverge/reference/convergence.md +26 -22
- package/skills/autoconverge/reference/headless-safety.md +44 -0
- package/skills/autoconverge/reference/multi-pr.md +88 -0
- package/skills/autoconverge/reference/self-closing-loop.md +84 -0
- package/skills/autoconverge/reference/stop-conditions.md +21 -13
- package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +87 -27
- package/skills/autoconverge/workflow/converge.contract.test.mjs +40 -10
- package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +179 -47
- package/skills/autoconverge/workflow/converge.fix-progress.test.mjs +1 -1
- package/skills/autoconverge/workflow/converge.mjs +286 -96
- package/skills/bugteam/CLAUDE.md +1 -1
- package/skills/bugteam/CONSTRAINTS.md +3 -3
- package/skills/bugteam/PROMPTS.md +8 -19
- package/skills/bugteam/SKILL.md +13 -14
- package/skills/bugteam/reference/CLAUDE.md +1 -1
- package/skills/bugteam/reference/README.md +2 -3
- package/skills/bugteam/reference/audit-and-teammates.md +2 -2
- package/skills/bugteam/reference/copilot-gap-analysis.md +2 -0
- package/skills/bugteam/reference/github-pr-reviews.md +56 -38
- package/skills/bugteam/reference/team-setup.md +11 -11
- package/skills/bugteam/scripts/CLAUDE.md +6 -6
- package/skills/bugteam/scripts/README.md +20 -8
- package/skills/bugteam/scripts/bugteam_code_rules_gate.py +13 -1463
- package/skills/bugteam/scripts/bugteam_fix_hookspath.py +23 -358
- package/skills/bugteam/scripts/bugteam_preflight.py +13 -315
- package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +2 -3
- package/skills/bugteam/scripts/test_bugteam_code_rules_gate.py +34 -1053
- package/skills/bugteam/scripts/test_bugteam_fix_hookspath.py +30 -347
- package/skills/bugteam/scripts/test_bugteam_preflight.py +30 -305
- package/skills/closeout/SKILL.md +153 -0
- package/skills/closeout/reference/handoff-prompt-template.md +72 -0
- package/skills/closeout/reference/issue-body-templates.md +108 -0
- package/skills/closeout/reference/pii-redaction-checklist.md +36 -0
- package/skills/copilot-finding-triage/SKILL.md +80 -28
- package/skills/copilot-finding-triage/reference/tier-rubric.md +70 -11
- package/skills/copilot-finding-triage/templates/notification.md +8 -3
- package/skills/everything-search/SKILL.md +1 -2
- package/skills/grokify/SKILL.md +58 -0
- package/skills/grokify/templates/handoff-template.md +92 -0
- package/skills/orchestrator/SKILL.md +35 -25
- package/skills/orchestrator-refresh/SKILL.md +15 -11
- package/skills/pr-converge/CLAUDE.md +1 -1
- package/skills/pr-converge/SKILL.md +132 -233
- package/skills/pr-converge/reference/convergence-gates.md +102 -66
- package/skills/pr-converge/reference/examples.md +37 -25
- package/skills/pr-converge/reference/fix-protocol.md +7 -7
- package/skills/pr-converge/reference/multi-pr-orchestration.md +10 -4
- package/skills/pr-converge/reference/per-tick.md +64 -41
- package/skills/pr-converge/reference/state-schema.md +27 -2
- package/skills/pr-converge/scripts/CLAUDE.md +8 -0
- package/skills/pr-converge/scripts/README.md +4 -3
- package/skills/pr-converge/scripts/_pr_converge_path_setup.py +23 -0
- package/skills/pr-converge/scripts/check_convergence.py +189 -645
- package/skills/pr-converge/scripts/check_convergence_gates.py +235 -0
- package/skills/pr-converge/scripts/check_convergence_thread_gates.py +219 -0
- package/skills/pr-converge/scripts/conftest.py +8 -0
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/CLAUDE.md +1 -0
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/convergence_gate_constants.py +36 -0
- package/skills/pr-converge/scripts/test__pr_converge_path_setup.py +26 -0
- package/skills/pr-converge/scripts/test_check_convergence.py +73 -228
- package/skills/pr-converge/scripts/test_check_convergence_contract.py +321 -0
- package/skills/pr-converge/scripts/test_check_convergence_gates.py +68 -0
- package/skills/pr-converge/scripts/test_check_convergence_thread_gates.py +75 -0
- package/skills/pr-fix-protocol/SKILL.md +20 -20
- package/skills/privacy-hygiene/SKILL.md +4 -3
- package/skills/reviewer-gates/SKILL.md +26 -8
- package/skills/session-log/SKILL.md +11 -12
- package/skills/session-tidy/SKILL.md +40 -30
- package/skills/skill-builder/CLAUDE.md +13 -10
- package/skills/skill-builder/SKILL.md +31 -31
- package/skills/skill-builder/references/CLAUDE.md +10 -6
- package/skills/skill-builder/references/delegation-map.md +13 -4
- package/skills/skill-builder/references/description-field.md +113 -0
- package/skills/skill-builder/references/self-audit-checklist.md +21 -4
- package/skills/skill-builder/references/skill-modularity.md +113 -0
- package/skills/skill-builder/references/skill-types.md +4 -0
- package/skills/skill-builder/templates/CLAUDE.md +4 -4
- package/skills/skill-builder/templates/gap-analysis.md +25 -1
- package/skills/skill-builder/workflows/CLAUDE.md +6 -4
- package/skills/skill-builder/workflows/improve-skill.md +17 -16
- package/skills/skill-builder/workflows/new-skill.md +34 -10
- package/skills/skill-builder/workflows/polish-skill.md +59 -43
- package/skills/team-advisor/SKILL.md +15 -11
- package/skills/usage-pause/SKILL.md +10 -14
- package/system-prompts/software-engineer.xml +7 -6
- package/hooks/validators/test_verify_paths.py +0 -32
- package/hooks/validators/verify_paths.py +0 -57
- package/skills/bdd-protocol/CLAUDE.md +0 -26
- package/skills/bdd-protocol/SKILL.md +0 -30
- package/skills/bdd-protocol/references/CLAUDE.md +0 -10
- package/skills/bdd-protocol/references/anti-patterns.md +0 -26
- package/skills/bdd-protocol/references/example-mapping.md +0 -23
- package/skills/bg-agent/CLAUDE.md +0 -17
- package/skills/bg-agent/SKILL.md +0 -69
- package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_code_rules_gate_constants.py +0 -55
- package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_fix_hookspath_constants.py +0 -26
- package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_preflight_constants.py +0 -35
- package/skills/caveman/CLAUDE.md +0 -15
- package/skills/caveman/SKILL.md +0 -38
- package/skills/code/CLAUDE.md +0 -17
- package/skills/code/SKILL.md +0 -178
- package/skills/deep-research/CLAUDE.md +0 -17
- package/skills/deep-research/SKILL.md +0 -80
- package/skills/findbugs/CLAUDE.md +0 -20
- package/skills/findbugs/SKILL.md +0 -241
- package/skills/fixbugs/CLAUDE.md +0 -19
- package/skills/fixbugs/SKILL.md +0 -142
- package/skills/gh-paginate/CLAUDE.md +0 -18
- package/skills/gh-paginate/SKILL.md +0 -84
- package/skills/gotcha/CLAUDE.md +0 -33
- package/skills/gotcha/SKILL.md +0 -73
- package/skills/implement/CLAUDE.md +0 -27
- package/skills/implement/SKILL.md +0 -66
- package/skills/implement/scripts/CLAUDE.md +0 -22
- package/skills/implement/scripts/append_note.py +0 -133
- package/skills/implement/scripts/implement_scripts_constants/CLAUDE.md +0 -22
- package/skills/implement/scripts/implement_scripts_constants/__init__.py +0 -0
- package/skills/implement/scripts/implement_scripts_constants/notes_constants.py +0 -12
- package/skills/implement/scripts/test_append_note.py +0 -191
- package/skills/log-audit/CLAUDE.md +0 -20
- package/skills/log-audit/SKILL.md +0 -66
- package/skills/log-audit/reference/CLAUDE.md +0 -9
- package/skills/log-audit/reference/charter.md +0 -52
- package/skills/log-audit/scripts/CLAUDE.md +0 -27
- package/skills/log-audit/scripts/cluster_recurrences.py +0 -261
- package/skills/log-audit/scripts/collect_log_window.py +0 -199
- package/skills/log-audit/scripts/log_audit_constants/CLAUDE.md +0 -12
- package/skills/log-audit/scripts/log_audit_constants/__init__.py +0 -0
- package/skills/log-audit/scripts/log_audit_constants/cluster_recurrences_constants.py +0 -23
- package/skills/log-audit/scripts/log_audit_constants/collect_log_window_constants.py +0 -24
- package/skills/log-audit/scripts/log_audit_constants/mine_copilot_findings_constants.py +0 -49
- package/skills/log-audit/scripts/mine_copilot_findings.py +0 -302
- package/skills/log-audit/scripts/test_cluster_recurrences.py +0 -160
- package/skills/log-audit/scripts/test_collect_log_window.py +0 -111
- package/skills/log-audit/scripts/test_mine_copilot_findings.py +0 -126
- package/skills/logifix/CLAUDE.md +0 -36
- package/skills/logifix/SKILL.md +0 -69
- package/skills/logifix/scripts/CLAUDE.md +0 -16
- package/skills/logifix/scripts/logifix.ps1 +0 -205
- package/skills/monitor-open-prs/CLAUDE.md +0 -34
- package/skills/monitor-open-prs/SKILL.md +0 -88
- package/skills/monitor-open-prs/scripts/CLAUDE.md +0 -17
- package/skills/monitor-open-prs/scripts/discover_open_prs.py +0 -69
- package/skills/monitor-open-prs/scripts/test_discover_open_prs.py +0 -149
- package/skills/monitor-open-prs/test_skill_contract.py +0 -27
- package/skills/post-audit-findings/SKILL.md +0 -80
- package/skills/pr-consistency-audit/CLAUDE.md +0 -34
- package/skills/pr-consistency-audit/SKILL.md +0 -116
- package/skills/pr-consistency-audit/reference/CLAUDE.md +0 -16
- package/skills/pr-consistency-audit/reference/detection-rules.md +0 -96
- package/skills/pr-consistency-audit/reference/illustrations.md +0 -78
- package/skills/pr-review-responder/CLAUDE.md +0 -35
- package/skills/pr-review-responder/EXAMPLES.md +0 -590
- package/skills/pr-review-responder/PRINCIPLES.md +0 -533
- package/skills/pr-review-responder/README.md +0 -168
- package/skills/pr-review-responder/SKILL.md +0 -203
- package/skills/pr-review-responder/TESTING.md +0 -350
- package/skills/pr-scope-resolve/SKILL.md +0 -45
- package/skills/pre-compact/CLAUDE.md +0 -24
- package/skills/pre-compact/SKILL.md +0 -134
- package/skills/qbug/CLAUDE.md +0 -40
- package/skills/qbug/SKILL.md +0 -387
- package/skills/qbug/test_qbug_skill_audit_schema.py +0 -152
- package/skills/qbug/test_qbug_skill_post_fix_audit.py +0 -103
- package/skills/refine/CLAUDE.md +0 -44
- package/skills/refine/SKILL.md +0 -262
- package/skills/refine/templates/CLAUDE.md +0 -17
- package/skills/refine/templates/implementation-notes-template.html +0 -56
- package/skills/refine/templates/plan-template.md +0 -60
- package/skills/research-mode/CLAUDE.md +0 -35
- package/skills/research-mode/SKILL.md +0 -53
- package/skills/structure-prompt/CLAUDE.md +0 -42
- package/skills/structure-prompt/SKILL.md +0 -44
- package/skills/structure-prompt/reference/CLAUDE.md +0 -28
- package/skills/structure-prompt/reference/adversarial-tuning.md +0 -62
- package/skills/structure-prompt/reference/block-classification.md +0 -27
- package/skills/structure-prompt/reference/canonical-case.md +0 -48
- package/skills/structure-prompt/reference/citation-depth.md +0 -70
- package/skills/structure-prompt/reference/cleanup.md +0 -33
- package/skills/structure-prompt/reference/constraints.md +0 -33
- package/skills/structure-prompt/reference/directives.md +0 -37
- package/skills/structure-prompt/reference/examples.md +0 -72
- package/skills/structure-prompt/reference/instantiation.md +0 -51
- package/skills/structure-prompt/reference/output-contract.md +0 -72
- package/skills/structure-prompt/reference/per-category.md +0 -23
- package/skills/structure-prompt/reference/persona.md +0 -38
- package/skills/structure-prompt/reference/research.md +0 -33
- package/skills/structure-prompt/reference/structure.md +0 -28
- package/skills/verified-build/CLAUDE.md +0 -33
- package/skills/verified-build/SKILL.md +0 -33
|
@@ -17,17 +17,19 @@ function functionBody(functionName) {
|
|
|
17
17
|
|
|
18
18
|
const productionModule = new Function(
|
|
19
19
|
`${functionBody('classifyReviewerGateOutcome')}\n` +
|
|
20
|
-
`${functionBody('
|
|
21
|
-
`${functionBody('
|
|
20
|
+
`${functionBody('partitionFindingsByTier')}\n` +
|
|
21
|
+
`${functionBody('normalizeVerifierVerdict')}\n` +
|
|
22
|
+
`${functionBody('attachVerifiedRepro')}\n` +
|
|
22
23
|
`${functionBody('buildUserReview')}\n` +
|
|
23
24
|
`${functionBody('resolveCopilotDown')}\n` +
|
|
24
25
|
`${functionBody('resolveReviewerDown')}\n` +
|
|
25
|
-
'return { classifyReviewerGateOutcome,
|
|
26
|
+
'return { classifyReviewerGateOutcome, partitionFindingsByTier, normalizeVerifierVerdict, attachVerifiedRepro, buildUserReview, resolveCopilotDown, resolveReviewerDown };',
|
|
26
27
|
)();
|
|
27
28
|
const {
|
|
28
29
|
classifyReviewerGateOutcome,
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
partitionFindingsByTier,
|
|
31
|
+
normalizeVerifierVerdict,
|
|
32
|
+
attachVerifiedRepro,
|
|
31
33
|
buildUserReview,
|
|
32
34
|
resolveCopilotDown,
|
|
33
35
|
resolveReviewerDown,
|
|
@@ -95,59 +97,112 @@ test('Copilot findings route to a fix when Copilot is reachable and not down', (
|
|
|
95
97
|
assert.equal(outcome.kind, 'fix');
|
|
96
98
|
});
|
|
97
99
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
100
|
+
function verifierResult(overrides) {
|
|
101
|
+
return {
|
|
102
|
+
verdict: 'confirmed',
|
|
103
|
+
checkCommand: 'pytest -k repro',
|
|
104
|
+
checkOutput: 'AssertionError: boom',
|
|
105
|
+
evidence: 'ran the repro and it failed',
|
|
106
|
+
...overrides,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
test('partitionFindingsByTier splits self-healing findings from code-concern findings', () => {
|
|
111
|
+
const { selfHealing, codeConcern } = partitionFindingsByTier([
|
|
112
|
+
copilotFinding({ tier: 'self-healing' }),
|
|
113
|
+
copilotFinding({ tier: 'code-concern', file: 'b.py', line: 2 }),
|
|
114
|
+
]);
|
|
115
|
+
assert.equal(selfHealing.length, 1);
|
|
116
|
+
assert.equal(codeConcern.length, 1);
|
|
117
|
+
assert.equal(codeConcern[0].file, 'b.py');
|
|
105
118
|
});
|
|
106
119
|
|
|
107
|
-
test('a code-concern
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
findings: [copilotFinding({ tier: 'code-concern', severity: 'P0' })],
|
|
112
|
-
}),
|
|
113
|
-
);
|
|
114
|
-
assert.equal(outcome.kind, 'user-review');
|
|
115
|
-
assert.equal(outcome.findings.length, 1);
|
|
120
|
+
test('partitionFindingsByTier routes a finding with a missing tier into code-concern so an unlabeled finding is never auto-fixed', () => {
|
|
121
|
+
const { selfHealing, codeConcern } = partitionFindingsByTier([{ file: 'a.py', line: 1 }]);
|
|
122
|
+
assert.equal(selfHealing.length, 0);
|
|
123
|
+
assert.equal(codeConcern.length, 1);
|
|
116
124
|
});
|
|
117
125
|
|
|
118
|
-
test('
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
);
|
|
127
|
-
assert.
|
|
126
|
+
test('normalizeVerifierVerdict downgrades a confirmed verdict backed by an empty checkCommand to inconclusive', () => {
|
|
127
|
+
const normalized = normalizeVerifierVerdict(verifierResult({ checkCommand: '' }));
|
|
128
|
+
assert.equal(normalized.verdict, 'inconclusive');
|
|
129
|
+
assert.match(normalized.evidence, /downgraded to inconclusive/);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test('normalizeVerifierVerdict downgrades a refuted verdict backed by an empty checkOutput to inconclusive', () => {
|
|
133
|
+
const normalized = normalizeVerifierVerdict(verifierResult({ verdict: 'refuted', checkOutput: '' }));
|
|
134
|
+
assert.equal(normalized.verdict, 'inconclusive');
|
|
135
|
+
assert.match(normalized.evidence, /downgraded to inconclusive/);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test('normalizeVerifierVerdict treats whitespace-only check fields as no executed check and downgrades', () => {
|
|
139
|
+
const normalized = normalizeVerifierVerdict(verifierResult({ checkCommand: ' ', checkOutput: '\t' }));
|
|
140
|
+
assert.equal(normalized.verdict, 'inconclusive');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test('normalizeVerifierVerdict returns an inconclusive default when the verifier agent died', () => {
|
|
144
|
+
const normalized = normalizeVerifierVerdict(null);
|
|
145
|
+
assert.equal(normalized.verdict, 'inconclusive');
|
|
146
|
+
assert.equal(normalized.checkCommand, '');
|
|
147
|
+
assert.equal(normalized.checkOutput, '');
|
|
148
|
+
assert.match(normalized.evidence, /verifier agent died/);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test('normalizeVerifierVerdict passes a backed conclusive verdict through unchanged', () => {
|
|
152
|
+
const backed = verifierResult({ verdict: 'confirmed' });
|
|
153
|
+
assert.deepEqual(normalizeVerifierVerdict(backed), backed);
|
|
128
154
|
});
|
|
129
155
|
|
|
130
|
-
test('
|
|
131
|
-
|
|
132
|
-
assert.
|
|
133
|
-
assert.equal(hasCodeConcernFinding([{ file: 'a.py', line: 1 }]), true);
|
|
156
|
+
test('normalizeVerifierVerdict passes an inconclusive verdict through unchanged even with empty check fields', () => {
|
|
157
|
+
const inconclusive = verifierResult({ verdict: 'inconclusive', checkCommand: '', checkOutput: '' });
|
|
158
|
+
assert.deepEqual(normalizeVerifierVerdict(inconclusive), inconclusive);
|
|
134
159
|
});
|
|
135
160
|
|
|
136
|
-
test('
|
|
161
|
+
test('attachVerifiedRepro folds the repro command and captured output into the finding detail, requires the re-run, and drops the verification field', () => {
|
|
162
|
+
const finding = attachVerifiedRepro(
|
|
163
|
+
copilotFinding({
|
|
164
|
+
tier: 'code-concern',
|
|
165
|
+
detail: 'the original finding detail',
|
|
166
|
+
verification: {
|
|
167
|
+
verdict: 'confirmed',
|
|
168
|
+
checkCommand: 'pytest -k repro',
|
|
169
|
+
checkOutput: 'AssertionError: boom',
|
|
170
|
+
evidence: 'ran the repro and it failed',
|
|
171
|
+
},
|
|
172
|
+
}),
|
|
173
|
+
);
|
|
174
|
+
assert.equal(finding.verification, undefined, 'expected the verification field to be dropped from the fix-flow finding');
|
|
175
|
+
assert.match(finding.detail, /the original finding detail/, 'expected the original detail to be preserved');
|
|
176
|
+
assert.match(finding.detail, /pytest -k repro/, 'expected the repro command to be folded into the detail');
|
|
177
|
+
assert.match(finding.detail, /AssertionError: boom/, 'expected the captured failing output to be folded into the detail');
|
|
178
|
+
assert.match(finding.detail, /re-run the exact repro/, 'expected the detail to require re-running the exact repro after the fix');
|
|
179
|
+
assert.match(finding.detail, /regression test/i, 'expected the detail to ask for the repro as a regression test');
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test('buildUserReview carries the review URL and pares findings to the triage fields plus the verifier evidence note', () => {
|
|
137
183
|
const reviewUrl = 'https://github.com/o/r/pull/1#pullrequestreview-9';
|
|
138
184
|
const userReview = buildUserReview(
|
|
139
185
|
copilotResult({ reviewUrl }),
|
|
140
|
-
[
|
|
186
|
+
[
|
|
187
|
+
copilotFinding({
|
|
188
|
+
tier: 'code-concern',
|
|
189
|
+
severity: 'P0',
|
|
190
|
+
title: 'unsafe eval',
|
|
191
|
+
detail: 'ignored',
|
|
192
|
+
verification: { verdict: 'inconclusive', checkCommand: '', checkOutput: '', evidence: 'no runnable check exists for the claim' },
|
|
193
|
+
}),
|
|
194
|
+
],
|
|
141
195
|
);
|
|
142
196
|
assert.equal(userReview.reviewUrl, reviewUrl);
|
|
143
197
|
assert.deepEqual(userReview.findings, [
|
|
144
|
-
{ file: 'a.py', line: 1, severity: 'P0', tier: 'code-concern', title: 'unsafe eval' },
|
|
198
|
+
{ file: 'a.py', line: 1, severity: 'P0', tier: 'code-concern', title: 'unsafe eval', evidence: 'no runnable check exists for the claim' },
|
|
145
199
|
]);
|
|
146
200
|
});
|
|
147
201
|
|
|
148
|
-
test('buildUserReview defaults a missing review URL to
|
|
202
|
+
test('buildUserReview defaults a missing review URL and a missing verifier evidence note to empty strings', () => {
|
|
149
203
|
const userReview = buildUserReview(copilotResult({}), [copilotFinding({ tier: 'code-concern' })]);
|
|
150
204
|
assert.equal(userReview.reviewUrl, '');
|
|
205
|
+
assert.equal(userReview.findings[0].evidence, '');
|
|
151
206
|
});
|
|
152
207
|
|
|
153
208
|
test('COPILOT_SCHEMA carries a required down field', () => {
|
|
@@ -188,6 +243,29 @@ test('COPILOT_SCHEMA carries a reviewUrl the user-review payload links to', () =
|
|
|
188
243
|
assert.match(schemaSource, /reviewUrl:\s*\{\s*type:\s*'string'/, 'expected a reviewUrl string field on COPILOT_SCHEMA');
|
|
189
244
|
});
|
|
190
245
|
|
|
246
|
+
test('COPILOT_VERIFY_VERDICTS names the confirmed, refuted, and inconclusive verdicts', () => {
|
|
247
|
+
const verdictsMatch = convergeSource.match(/const COPILOT_VERIFY_VERDICTS = \[([^\]]*)\]/);
|
|
248
|
+
assert.notEqual(verdictsMatch, null, 'expected a COPILOT_VERIFY_VERDICTS constant');
|
|
249
|
+
assert.match(verdictsMatch[1], /'confirmed'/, 'expected the verdict enum to name confirmed');
|
|
250
|
+
assert.match(verdictsMatch[1], /'refuted'/, 'expected the verdict enum to name refuted');
|
|
251
|
+
assert.match(verdictsMatch[1], /'inconclusive'/, 'expected the verdict enum to name inconclusive');
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test('COPILOT_VERIFY_SCHEMA requires the verdict, checkCommand, checkOutput, and evidence fields with the verdict enum drawn from the verdict constant', () => {
|
|
255
|
+
const schemaStart = convergeSource.indexOf('const COPILOT_VERIFY_SCHEMA =');
|
|
256
|
+
const schemaEnd = convergeSource.indexOf('const REVIEWER_AVAILABILITY_SCHEMA =');
|
|
257
|
+
assert.notEqual(schemaStart, -1, 'expected COPILOT_VERIFY_SCHEMA to exist');
|
|
258
|
+
const schemaSource = convergeSource.slice(schemaStart, schemaEnd);
|
|
259
|
+
assert.match(schemaSource, /enum:\s*COPILOT_VERIFY_VERDICTS/, 'expected the verdict enum to draw from the COPILOT_VERIFY_VERDICTS constant');
|
|
260
|
+
for (const requiredField of ['verdict', 'checkCommand', 'checkOutput', 'evidence']) {
|
|
261
|
+
assert.match(
|
|
262
|
+
schemaSource,
|
|
263
|
+
new RegExp(`required:\\s*\\[[^\\]]*'${requiredField}'[^\\]]*\\]`),
|
|
264
|
+
`expected ${requiredField} to be a required field on the verifier schema`,
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
|
|
191
269
|
test('the Copilot gate prompt tiers each finding and returns the review URL', () => {
|
|
192
270
|
const copilotPrompt = functionBody('runCopilotGate');
|
|
193
271
|
assert.match(copilotPrompt, /tier 'self-healing'/, 'expected the prompt to define the self-healing tier');
|
|
@@ -196,18 +274,58 @@ test('the Copilot gate prompt tiers each finding and returns the review URL', ()
|
|
|
196
274
|
assert.match(copilotPrompt, /reviewUrl set to the Copilot review html_url/, 'expected the findings branch to return the review URL');
|
|
197
275
|
});
|
|
198
276
|
|
|
199
|
-
test('the COPILOT phase returns blocker user-review
|
|
277
|
+
test('the COPILOT phase returns blocker user-review only when inconclusive findings remain after verification, carrying the verifier-noted payload with no auto-fix in the branch', () => {
|
|
200
278
|
const copilotPhaseStart = convergeSource.indexOf("if (phase === 'COPILOT') {");
|
|
201
279
|
const finalizePhaseStart = convergeSource.indexOf("if (phase === 'FINALIZE') {", copilotPhaseStart);
|
|
202
280
|
const copilotPhase = convergeSource.slice(copilotPhaseStart, finalizePhaseStart);
|
|
203
|
-
const
|
|
204
|
-
assert.notEqual(
|
|
205
|
-
const userReviewBranch = copilotPhase.slice(
|
|
206
|
-
assert.match(userReviewBranch, /blocker:\s*'user-review'/, 'expected the branch to return blocker user-review');
|
|
281
|
+
const userReviewGuardStart = copilotPhase.indexOf('inconclusive.length > 0');
|
|
282
|
+
assert.notEqual(userReviewGuardStart, -1, 'expected the user-review return to be guarded by inconclusive.length > 0');
|
|
283
|
+
const userReviewBranch = copilotPhase.slice(userReviewGuardStart, userReviewGuardStart + 600);
|
|
284
|
+
assert.match(userReviewBranch, /blocker:\s*'user-review'/, 'expected the guarded branch to return blocker user-review');
|
|
207
285
|
assert.match(userReviewBranch, /converged:\s*false/, 'expected the branch to return converged false');
|
|
208
|
-
assert.match(
|
|
286
|
+
assert.match(
|
|
287
|
+
userReviewBranch,
|
|
288
|
+
/userReview:\s*buildUserReview\(copilot, inconclusive\)/,
|
|
289
|
+
'expected the branch to carry the inconclusive-findings user-review payload',
|
|
290
|
+
);
|
|
209
291
|
const autoFixIndex = userReviewBranch.indexOf('applyFixes');
|
|
210
|
-
assert.equal(autoFixIndex, -1, 'expected the user-review branch to not auto-fix the
|
|
292
|
+
assert.equal(autoFixIndex, -1, 'expected the user-review branch to not auto-fix the inconclusive findings');
|
|
293
|
+
const userReviewReturns = (copilotPhase.match(/blocker:\s*'user-review'/g) || []).length;
|
|
294
|
+
assert.equal(userReviewReturns, 1, 'expected exactly one user-review return in the COPILOT phase');
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
test('the COPILOT phase awaits verifyCodeConcernFindings exactly once, inside the code-concern guard', () => {
|
|
298
|
+
const copilotPhaseStart = convergeSource.indexOf("if (phase === 'COPILOT') {");
|
|
299
|
+
const finalizePhaseStart = convergeSource.indexOf("if (phase === 'FINALIZE') {", copilotPhaseStart);
|
|
300
|
+
const copilotPhase = convergeSource.slice(copilotPhaseStart, finalizePhaseStart);
|
|
301
|
+
const guardStart = copilotPhase.indexOf('if (codeConcern.length > 0)');
|
|
302
|
+
assert.notEqual(guardStart, -1, 'expected the verification to sit behind a codeConcern.length > 0 guard');
|
|
303
|
+
const verifyCalls = convergeSource.match(/await verifyCodeConcernFindings\(/g) || [];
|
|
304
|
+
assert.equal(verifyCalls.length, 1, 'expected verifyCodeConcernFindings to be awaited exactly once outside its own definition');
|
|
305
|
+
const verifyCallIndex = copilotPhase.indexOf('await verifyCodeConcernFindings(head, codeConcern)');
|
|
306
|
+
assert.ok(verifyCallIndex > guardStart, 'expected the verifyCodeConcernFindings call to sit inside the code-concern guard');
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
test('the all-refuted / empty-roundFindings COPILOT path advances to FINALIZE with the gate passed', () => {
|
|
310
|
+
const copilotPhaseStart = convergeSource.indexOf("if (phase === 'COPILOT') {");
|
|
311
|
+
const finalizePhaseStart = convergeSource.indexOf("if (phase === 'FINALIZE') {", copilotPhaseStart);
|
|
312
|
+
const copilotPhase = convergeSource.slice(copilotPhaseStart, finalizePhaseStart);
|
|
313
|
+
const emptyRoundStart = copilotPhase.indexOf('roundFindings.length === 0');
|
|
314
|
+
assert.notEqual(emptyRoundStart, -1, 'expected the COPILOT phase to handle an empty roundFindings set after verification');
|
|
315
|
+
const emptyRoundBranch = copilotPhase.slice(emptyRoundStart, emptyRoundStart + 300);
|
|
316
|
+
assert.match(emptyRoundBranch, /copilotDown = false/, 'expected the empty-roundFindings path to clear copilotDown');
|
|
317
|
+
assert.match(emptyRoundBranch, /phase = 'FINALIZE'/, 'expected the empty-roundFindings path to advance to FINALIZE');
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
test('the COPILOT phase folds confirmed findings through attachVerifiedRepro into the round fix list', () => {
|
|
321
|
+
const copilotPhaseStart = convergeSource.indexOf("if (phase === 'COPILOT') {");
|
|
322
|
+
const finalizePhaseStart = convergeSource.indexOf("if (phase === 'FINALIZE') {", copilotPhaseStart);
|
|
323
|
+
const copilotPhase = convergeSource.slice(copilotPhaseStart, finalizePhaseStart);
|
|
324
|
+
assert.match(
|
|
325
|
+
copilotPhase,
|
|
326
|
+
/roundFindings = \[\.\.\.selfHealing, \.\.\.confirmed\.map\(\(each\) => attachVerifiedRepro\(each\)\)\]/,
|
|
327
|
+
'expected the fix list to be the self-healing findings plus the confirmed findings mapped through attachVerifiedRepro',
|
|
328
|
+
);
|
|
211
329
|
});
|
|
212
330
|
|
|
213
331
|
test('the Copilot gate prompt detects an out-of-usage notice and returns a down result', () => {
|
|
@@ -332,7 +450,7 @@ test('resolveCopilotDown clears the bypass for a retry outcome', () => {
|
|
|
332
450
|
|
|
333
451
|
test('the standards-only Copilot sub-path resets copilotDown before FINALIZE', () => {
|
|
334
452
|
const standardsBranchStart = convergeSource.indexOf(
|
|
335
|
-
'isStandardsOnlyRound(
|
|
453
|
+
'isStandardsOnlyRound(roundFindings)',
|
|
336
454
|
);
|
|
337
455
|
assert.notEqual(
|
|
338
456
|
standardsBranchStart,
|
|
@@ -407,6 +525,20 @@ test('the merged FINALIZE check opts the unflagged convergence hook out of Copil
|
|
|
407
525
|
);
|
|
408
526
|
});
|
|
409
527
|
|
|
528
|
+
test('the merged FINALIZE check opts the unflagged convergence hook out of Bugbot when bugbotDown before gh pr ready', () => {
|
|
529
|
+
const checkBody = functionBody('runConvergenceCheck');
|
|
530
|
+
assert.match(
|
|
531
|
+
checkBody,
|
|
532
|
+
/context\.bugbotDown/,
|
|
533
|
+
'expected the merged check to branch on bugbotDown so a bugbot-down run reaches the opt-out token push',
|
|
534
|
+
);
|
|
535
|
+
assert.match(
|
|
536
|
+
checkBody,
|
|
537
|
+
/reviewerOptOutTokens\.push\('bugbot'\)/,
|
|
538
|
+
'expected the merged check opt-out to push the bugbot token so the unflagged mark-ready hook re-derives the Bugbot bypass',
|
|
539
|
+
);
|
|
540
|
+
});
|
|
541
|
+
|
|
410
542
|
test('the COPILOT phase short-circuits on the unified reviewer-down gate before spawning the gate agent', () => {
|
|
411
543
|
const copilotPhaseStart = convergeSource.indexOf("if (phase === 'COPILOT') {");
|
|
412
544
|
assert.notEqual(copilotPhaseStart, -1, 'expected a COPILOT phase block');
|
|
@@ -99,7 +99,7 @@ test('the converge call site sets a fix-stalled blocker when an all-null-thread
|
|
|
99
99
|
|
|
100
100
|
test('the copilot call site sets a fix-stalled blocker when an all-null-thread resolvedWithoutCommit round cannot progress', () => {
|
|
101
101
|
const copilotBranch = convergeSource.slice(
|
|
102
|
-
convergeSource.indexOf("const fixResult = await applyFixes(head,
|
|
102
|
+
convergeSource.indexOf("const fixResult = await applyFixes(head, roundFindings, 'copilot')"),
|
|
103
103
|
convergeSource.indexOf("phase = 'CONVERGE'\n continue\n }\n phase = 'FINALIZE'"),
|
|
104
104
|
);
|
|
105
105
|
assert.match(copilotBranch, /collectFindingThreadIds/);
|