feat(config-audit): wire TOK into posture scorecard as 8th quality area (Token Efficiency)
This commit is contained in:
parent
068622e513
commit
4b385bf456
3 changed files with 23 additions and 8 deletions
|
|
@ -150,12 +150,21 @@ const SCANNER_AREA_MAP = {
|
|||
IMP: 'Imports',
|
||||
CNF: 'Conflicts',
|
||||
GAP: 'Feature Coverage',
|
||||
TOK: 'Token Efficiency',
|
||||
};
|
||||
|
||||
/**
|
||||
* Slugify an area name into a stable id.
|
||||
* Example: "Token Efficiency" → "token_efficiency", "CLAUDE.md" → "claude_md".
|
||||
*/
|
||||
function slugify(name) {
|
||||
return String(name).toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Score per config area from scanner results.
|
||||
* @param {object[]} scannerResults - Array of scanner result objects from envelope.scanners
|
||||
* @returns {{ areas: Array<{ name: string, grade: string, score: number, findingCount: number }>, overallGrade: string }}
|
||||
* @returns {{ areas: Array<{ id: string, name: string, grade: string, score: number, findingCount: number }>, overallGrade: string }}
|
||||
*/
|
||||
export function scoreByArea(scannerResults) {
|
||||
const areas = [];
|
||||
|
|
@ -178,7 +187,7 @@ export function scoreByArea(scannerResults) {
|
|||
}
|
||||
|
||||
const grade = gradeFromPassRate(score);
|
||||
areas.push({ name, grade, score, findingCount });
|
||||
areas.push({ id: slugify(name), name, grade, score, findingCount });
|
||||
}
|
||||
|
||||
// Overall grade: quality areas only (exclude GAP — feature coverage is informational, not a quality issue)
|
||||
|
|
@ -262,7 +271,7 @@ export function generateScorecard(areaScores, utilization, maturity, segment, ac
|
|||
|
||||
/**
|
||||
* Generate a v3 health-focused terminal scorecard.
|
||||
* Shows only the 7 quality areas — no utilization, maturity, or segment.
|
||||
* Shows only the quality areas (currently 8) — no utilization, maturity, or segment.
|
||||
* @param {{ areas: Array<{ name: string, grade: string, score: number }>, overallGrade: string }} areaScores
|
||||
* @param {number} opportunityCount - Number of GAP findings (shown as opportunity count)
|
||||
* @returns {string}
|
||||
|
|
|
|||
|
|
@ -265,11 +265,11 @@ describe('determineSegment', () => {
|
|||
// scoreByArea
|
||||
// ========================================
|
||||
describe('scoreByArea', () => {
|
||||
it('returns areas for all 8 scanners', () => {
|
||||
const scanners = ['CML', 'SET', 'HKV', 'RUL', 'MCP', 'IMP', 'CNF', 'GAP']
|
||||
it('returns areas for all 9 scanners', () => {
|
||||
const scanners = ['CML', 'SET', 'HKV', 'RUL', 'MCP', 'IMP', 'CNF', 'GAP', 'TOK']
|
||||
.map(s => makeScannerResult(s, 0));
|
||||
const result = scoreByArea(scanners);
|
||||
assert.equal(result.areas.length, 8);
|
||||
assert.equal(result.areas.length, 9);
|
||||
});
|
||||
|
||||
it('zero findings → A grade', () => {
|
||||
|
|
|
|||
|
|
@ -45,9 +45,10 @@ describe('posture.mjs CLI — healthy project', () => {
|
|||
assert.ok(result.segment.segment.length > 0);
|
||||
});
|
||||
|
||||
it('returns 8 area scores', () => {
|
||||
assert.equal(result.areas.length, 8);
|
||||
it('returns 9 area scores', () => {
|
||||
assert.equal(result.areas.length, 9);
|
||||
for (const area of result.areas) {
|
||||
assert.ok('id' in area);
|
||||
assert.ok('name' in area);
|
||||
assert.ok('grade' in area);
|
||||
assert.ok('score' in area);
|
||||
|
|
@ -55,6 +56,11 @@ describe('posture.mjs CLI — healthy project', () => {
|
|||
}
|
||||
});
|
||||
|
||||
it('exposes a token_efficiency area id', () => {
|
||||
const te = result.areas.find(a => a.id === 'token_efficiency');
|
||||
assert.ok(te, 'token_efficiency id present');
|
||||
});
|
||||
|
||||
it('returns overallGrade', () => {
|
||||
assert.ok(['A', 'B', 'C', 'D', 'F'].includes(result.overallGrade));
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue