diff --git a/.github/scripts/__tests__/pr-triage-classify.test.js b/.github/scripts/__tests__/pr-triage-classify.test.js index 8b03d3af8c..5b7b1dcc60 100644 --- a/.github/scripts/__tests__/pr-triage-classify.test.js +++ b/.github/scripts/__tests__/pr-triage-classify.test.js @@ -373,9 +373,17 @@ describe('determineTier', () => { assert.equal(classify('alice', 'claude/small-multi', files), 2); }); - it('human branch at 149 prod lines (just under threshold)', () => { + it('human branch at 249 prod lines (just under threshold)', () => { assert.equal(classify('alice', 'fix/component', [ - makeFile('packages/app/src/Foo.tsx', 100, 49), // 149 lines + makeFile('packages/app/src/Foo.tsx', 200, 49), // 249 lines + ]), 2); + }); + + it('focused new UI component at 238 prod lines qualifies for Tier 2 (PR #2175 pattern)', () => { + assert.equal(classify('mikeshi', 'cursor/add-feedback-widget', [ + makeFile('packages/app/src/components/AppNav/AppNavFeedback.tsx', 217, 0), + makeFile('packages/app/src/components/AppNav/AppNav.module.scss', 17, 0), + makeFile('packages/app/src/components/AppNav/AppNav.tsx', 4, 0), ]), 2); }); @@ -438,13 +446,13 @@ describe('determineTier', () => { makeFile('packages/api/src/services/checkAlerts.ts', 180, 70), // prod: 250 lines makeFile('packages/api/src/__tests__/checkAlerts.test.ts', 1100, 0), // test: excluded ]; - // 250 prod lines > TIER2_MAX_LINES (150) → Tier 3, not Tier 4 + // 250 prod lines >= TIER2_MAX_LINES (250) → Tier 3, not Tier 4 assert.equal(classify('alice', 'feat/alert-thresholds', files), 3); }); - it('human branch at exactly 150 prod lines is Tier 3, not Tier 2', () => { + it('human branch at exactly 250 prod lines is Tier 3, not Tier 2', () => { assert.equal(classify('alice', 'fix/component', [ - makeFile('packages/app/src/Foo.tsx', 100, 50), // exactly TIER2_MAX_LINES — < is exclusive + makeFile('packages/app/src/Foo.tsx', 150, 100), // exactly TIER2_MAX_LINES — < is exclusive ]), 3); }); @@ -562,6 +570,13 @@ describe('buildTierComment', () => { assert.ok(body.includes('Standard feature/fix')); }); + it('explains line count trigger when prod lines exceed Tier 2 threshold', () => { + const body = buildTierComment(3, makeSignals({ prodLines: 260 })); + assert.ok(body.includes('260')); + assert.ok(body.includes('Diff size')); + assert.ok(!body.includes('Standard feature/fix')); + }); + it('includes bot-author trigger for Tier 1 bot PRs', () => { const body = buildTierComment(1, makeSignals({ isBotAuthor: true, author: 'dependabot[bot]' })); assert.ok(body.includes('Bot author')); diff --git a/.github/scripts/pr-triage-classify.js b/.github/scripts/pr-triage-classify.js index 5d5019013d..f32a635b52 100644 --- a/.github/scripts/pr-triage-classify.js +++ b/.github/scripts/pr-triage-classify.js @@ -36,7 +36,7 @@ const TEST_FILE_PATTERNS = [ ]; // ── Thresholds (all line counts exclude test and trivial files) ─────────────── -const TIER2_MAX_LINES = 150; // max prod lines eligible for Tier 2 +const TIER2_MAX_LINES = 250; // max prod lines eligible for Tier 2 const TIER4_ESCALATION_HUMAN = 1000; // Tier 3 → 4 for human branches const TIER4_ESCALATION_AGENT = 400; // Tier 3 → 4 for agent branches (stricter) @@ -191,6 +191,9 @@ function buildTierComment(tier, signals) { if (tier === 4 && prodLines > sizeThreshold && criticalFiles.length === 0) { triggers.push(`**Large diff**: ${prodLines} production lines changed (threshold: ${sizeThreshold})`); } + if (tier === 3 && prodLines >= TIER2_MAX_LINES) { + triggers.push(`**Diff size**: ${prodLines} production lines changed (Tier 2 max: < ${TIER2_MAX_LINES})`); + } if (isBotAuthor) triggers.push(`**Bot author**: \`${author}\``); if (allFilesTrivial && !isBotAuthor) triggers.push('**All files are docs / images / lock files**'); if (isCrossLayer) {