fix(acr): posture --output-file humanizes findings in default mode (M-BUG-12)
feature-gap.md (Step 3-4) and posture.md (Step 3-4) read findings from `posture.mjs --output-file` and group on the humanizer fields (userActionLanguage / userImpactCategory / relevanceContext). But posture.mjs only humanized the stderr scorecard — its --output-file JSON wrote the raw v5.0.0-shape `result`, so every finding's humanizer fields were `undefined`. Both commands silently degraded to the raw tier-fallback: v5.1.0 plain-language output was dead for feature-gap and for posture's finding-level grouping. Re-derived on tests/fixtures/marketplace-medium: 17 GAP findings, all three humanizer fields undefined in the default --output-file JSON. Fix (posture-CLI-local, surgical): humanize the output-file payload in default mode, mirroring scan-orchestrator.mjs:277 — but posture nests the scanner envelope under `result.scannerEnvelope` (its `result` has no top-level `scanners` array), so humanizeEnvelope is applied to `result.scannerEnvelope`, not `result` (the latter would no-op). --json / --raw stay raw, so the explicit-v5.0.0-shape contract and snapshot byte-compat are preserved. TDD: red-first test in posture-humanizer.test.mjs default-mode block asserts GAP findings in the output file carry userActionLanguage/userImpactCategory; a --raw --output-file guard asserts the raw shape is unchanged. Suite 1350/0 (+2). Frozen v5.0.0 + SC-5/6/7 + default-output snapshots byte-stable: --json/--raw bypass the humanizer (their snapshot tests use those flags), and the default --output-file JSON is not snapshot-pinned. Committed, not released — batches with M-BUG-11 in a later hardening release. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01683eAqVecv9VZfQzL8CQ9h
This commit is contained in:
parent
1d63492617
commit
b58393099a
2 changed files with 51 additions and 2 deletions
|
|
@ -10,6 +10,7 @@
|
|||
import { resolve } from 'node:path';
|
||||
import { writeFile } from 'node:fs/promises';
|
||||
import { runAllScanners } from './scan-orchestrator.mjs';
|
||||
import { humanizeEnvelope } from './lib/humanizer.mjs';
|
||||
import {
|
||||
calculateUtilization,
|
||||
determineMaturityLevel,
|
||||
|
|
@ -114,7 +115,14 @@ async function main() {
|
|||
}
|
||||
|
||||
if (outputFile) {
|
||||
const json = JSON.stringify(result, null, 2);
|
||||
// Consumers (feature-gap.md, posture.md) read scannerEnvelope.scanners[].findings
|
||||
// and group on humanizer fields. posture's result nests the envelope under
|
||||
// `scannerEnvelope`, so humanize THAT (not `result`, which has no top-level
|
||||
// `scanners` array — humanizeEnvelope would no-op). --json/--raw stay raw.
|
||||
const fileEnv = (jsonMode || rawMode)
|
||||
? result
|
||||
: { ...result, scannerEnvelope: humanizeEnvelope(result.scannerEnvelope) };
|
||||
const json = JSON.stringify(fileEnv, null, 2);
|
||||
await writeFile(outputFile, json, 'utf-8');
|
||||
process.stderr.write(`\nResults written to ${outputFile}\n`);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue