Files
Dragan Spiridonov b6fd679254 fix(#569): stop the MCP layer laundering missing provenance into confident numbers
Found by the qe-devils-advocate session review, AFTER #569 was already committed.
The handler was producing honest provenance; `coverageAnalyzeConfig.mapToResult`
was converting it back into fabricated certainty on three paths.

1. Absent provenance was treated as "collected".
   `data.branchDataCollected !== false` — and `undefined !== false` is true. Any
   producer that supplies no provenance (notably the coverage-analysis domain
   plugin, whose handler returns a nested-`summary` CoverageReport) therefore
   surfaced issue #569's EXACT reported symptom: 100% branch coverage alongside
   0% function coverage, labelled `measured: true`, with `confidence: 0.7` on its
   gaps. Now requires an explicit `true`; absence means unknown, so an
   unprovenanced result reports `null`.

2. `measured` was derived as `!estimated`.
   These are not complements — there is a third state where nothing was collected
   at all. An empty project reported `lineCoverage: 0, measured: true`: "we
   measured 0%" when the truth was "we measured nothing". Verified through the
   real MCP server before and after. `measured` now requires an explicit claim.

3. `null` was coerced to `0`, and risk was graded off it.
   `?? 0` turned "no data" into a plottable 0%, and `null < 70` is `false` in JS,
   so an unguarded comparison graded "no data" as 'low' risk — the most dangerous
   possible default. Nulls now survive; risk grading requires a real number.

Also fixes the stale-result mystery that dogged verification all session.
`src/optimization/session-cache.ts` fingerprints on domain+action+input only, and
persists to kv_store with a 1-hour TTL, so entries survive package upgrades: a
project analyzed before a fix keeps replaying the old answer, making the fix look
broken. I twice mis-diagnosed this (first as a cache, then wrongly retracted that;
it WAS the cache). The fingerprint now includes the build identity, so an upgrade
misses cleanly and old entries age out. `AQE_SESSION_CACHE_SALT` forces a cold
cache without deleting anything.

This matters beyond #569: every fix in this release would have appeared not to
work for any user with a warm cache.

`CoverageAnalyzeResult.lineCoverage`/`statementCoverage` are now `number | null`,
joining `branchCoverage`/`functionCoverage`. `0` means a measured zero; `null`
means unknown.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 14:46:31 +00:00
..