feat(humanizer): wire humanizer into posture and scoring scorecard

generateHealthScorecard signature: 2-arg → 3-arg (areaScores, opportunityCount,
options = {}). options.humanized=true renders friendlier title, grade-context
line per overall grade, and rephrased opportunity line. options.humanized=false
(or 2-arg call) preserves v5.0.0 verbatim output for backwards-compat.

topActions also gets an optional options.humanized that swaps recommendations
through humanizeFinding lookup.

posture.mjs main():
  --json → write JSON to stdout, suppress stderr scorecard
  --raw  → write JSON to stdout (byte-identical to --json), write v5.0.0
           verbatim scorecard to stderr
  default → humanized scorecard to stderr, no stdout

posture.test.mjs scorecard-prose assertions re-anchored to --raw mode (the
explicit v5.0.0 path) — Wave 0 audit only covered finding-title strings;
scorecard prose surfaces here for the first time.

Wave 3 / Step 6 of v5.1.0 humanizer.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-05-01 17:38:03 +02:00
commit 70ff900578
5 changed files with 331 additions and 14 deletions

View file

@ -92,8 +92,10 @@ describe('posture.mjs CLI — minimal project', () => {
});
describe('posture.mjs CLI — terminal output (v3 health format)', () => {
it('scorecard contains health sections', async () => {
const { stderr } = await runPosture([resolve(FIXTURES, 'healthy-project')]);
// These assertions verify the v5.0.0 verbatim scorecard prose. Default mode
// is humanized as of v5.1.0 (Wave 3); --raw is the explicit v5.0.0 path.
it('scorecard contains health sections (v5.0.0 verbatim via --raw)', async () => {
const { stderr } = await runPosture([resolve(FIXTURES, 'healthy-project'), '--raw']);
assert.ok(stderr.includes('Config-Audit Health Score'));
assert.ok(stderr.includes('Health:'));
assert.ok(stderr.includes('Area Scores'));
@ -101,14 +103,14 @@ describe('posture.mjs CLI — terminal output (v3 health format)', () => {
});
it('scorecard does NOT contain legacy metrics', async () => {
const { stderr } = await runPosture([resolve(FIXTURES, 'healthy-project')]);
const { stderr } = await runPosture([resolve(FIXTURES, 'healthy-project'), '--raw']);
assert.ok(!stderr.includes('Maturity:'));
assert.ok(!stderr.includes('Utilization:'));
assert.ok(!stderr.includes('Segment:'));
});
it('scorecard excludes Feature Coverage from area display', async () => {
const { stderr } = await runPosture([resolve(FIXTURES, 'healthy-project')]);
const { stderr } = await runPosture([resolve(FIXTURES, 'healthy-project'), '--raw']);
assert.ok(!stderr.includes('Feature Coverage'));
});
});