diff --git a/plugins/config-audit/scanners/token-hotspots.mjs b/plugins/config-audit/scanners/token-hotspots.mjs index f88ccef..d10aebd 100644 --- a/plugins/config-audit/scanners/token-hotspots.mjs +++ b/plugins/config-audit/scanners/token-hotspots.mjs @@ -39,7 +39,6 @@ const VOLATILE_PATTERNS = [ const MAX_IMPORT_DEPTH = 2; -const HOTSPOTS_MIN = 3; const HOTSPOTS_MAX = 10; /** @@ -210,13 +209,6 @@ async function buildHotspots(discovery, targetPath, activeConfig) { } ranked.sort((a, b) => b.estimated_tokens - a.estimated_tokens); - // If we have fewer than HOTSPOTS_MIN entries, pad with placeholder entries - // derived from the same set so the contract still holds for tiny fixtures. - let take = Math.min(Math.max(ranked.length, HOTSPOTS_MIN), HOTSPOTS_MAX); - // Cap to actual entries (don't fabricate) — tests run against marketplace-large - // for the 3-10 contract; tiny fixtures still produce a real array. - take = Math.min(take, Math.max(ranked.length, 1)); - const top = ranked.slice(0, HOTSPOTS_MAX); const out = []; for (let i = 0; i < top.length; i++) { @@ -229,19 +221,7 @@ async function buildHotspots(discovery, targetPath, activeConfig) { }); } - // Pad to HOTSPOTS_MIN with the smallest entries repeated as "summary" rows - // — this only triggers for fixtures with <3 sources. - while (out.length < HOTSPOTS_MIN && ranked.length > 0) { - const extra = ranked[ranked.length - 1]; - out.push({ - source: extra.relPath || extra.absPath, - estimated_tokens: extra.estimated_tokens, - rank: out.length + 1, - recommendations: hotspotRecommendations(extra), - }); - } - - return out.slice(0, HOTSPOTS_MAX); + return out; } function hotspotRecommendations(h) { diff --git a/plugins/config-audit/tests/scanners/token-hotspots.test.mjs b/plugins/config-audit/tests/scanners/token-hotspots.test.mjs index 1a71edb..f5fee1b 100644 --- a/plugins/config-audit/tests/scanners/token-hotspots.test.mjs +++ b/plugins/config-audit/tests/scanners/token-hotspots.test.mjs @@ -170,4 +170,16 @@ describe('TOK scanner — hotspots contract', () => { `hotspot.recommendations length should be 1–3, got ${h.recommendations.length}`); } }); + + it('every hotspot.source is unique (v5 F4: no padding)', () => { + const sources = result.hotspots.map(h => h.source); + const unique = new Set(sources); + assert.equal(unique.size, sources.length, + `expected unique sources; got duplicates in: ${sources.join(', ')}`); + }); + + it('hotspots.length never exceeds HOTSPOTS_MAX (10)', () => { + assert.ok(result.hotspots.length <= 10, + `expected ≤10 hotspots, got ${result.hotspots.length}`); + }); });