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',
|
IMP: 'Imports',
|
||||||
CNF: 'Conflicts',
|
CNF: 'Conflicts',
|
||||||
GAP: 'Feature Coverage',
|
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.
|
* Score per config area from scanner results.
|
||||||
* @param {object[]} scannerResults - Array of scanner result objects from envelope.scanners
|
* @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) {
|
export function scoreByArea(scannerResults) {
|
||||||
const areas = [];
|
const areas = [];
|
||||||
|
|
@ -178,7 +187,7 @@ export function scoreByArea(scannerResults) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const grade = gradeFromPassRate(score);
|
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)
|
// 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.
|
* 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 {{ areas: Array<{ name: string, grade: string, score: number }>, overallGrade: string }} areaScores
|
||||||
* @param {number} opportunityCount - Number of GAP findings (shown as opportunity count)
|
* @param {number} opportunityCount - Number of GAP findings (shown as opportunity count)
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
|
|
|
||||||
|
|
@ -265,11 +265,11 @@ describe('determineSegment', () => {
|
||||||
// scoreByArea
|
// scoreByArea
|
||||||
// ========================================
|
// ========================================
|
||||||
describe('scoreByArea', () => {
|
describe('scoreByArea', () => {
|
||||||
it('returns areas for all 8 scanners', () => {
|
it('returns areas for all 9 scanners', () => {
|
||||||
const scanners = ['CML', 'SET', 'HKV', 'RUL', 'MCP', 'IMP', 'CNF', 'GAP']
|
const scanners = ['CML', 'SET', 'HKV', 'RUL', 'MCP', 'IMP', 'CNF', 'GAP', 'TOK']
|
||||||
.map(s => makeScannerResult(s, 0));
|
.map(s => makeScannerResult(s, 0));
|
||||||
const result = scoreByArea(scanners);
|
const result = scoreByArea(scanners);
|
||||||
assert.equal(result.areas.length, 8);
|
assert.equal(result.areas.length, 9);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('zero findings → A grade', () => {
|
it('zero findings → A grade', () => {
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,10 @@ describe('posture.mjs CLI — healthy project', () => {
|
||||||
assert.ok(result.segment.segment.length > 0);
|
assert.ok(result.segment.segment.length > 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns 8 area scores', () => {
|
it('returns 9 area scores', () => {
|
||||||
assert.equal(result.areas.length, 8);
|
assert.equal(result.areas.length, 9);
|
||||||
for (const area of result.areas) {
|
for (const area of result.areas) {
|
||||||
|
assert.ok('id' in area);
|
||||||
assert.ok('name' in area);
|
assert.ok('name' in area);
|
||||||
assert.ok('grade' in area);
|
assert.ok('grade' in area);
|
||||||
assert.ok('score' 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', () => {
|
it('returns overallGrade', () => {
|
||||||
assert.ok(['A', 'B', 'C', 'D', 'F'].includes(result.overallGrade));
|
assert.ok(['A', 'B', 'C', 'D', 'F'].includes(result.overallGrade));
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue