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>
- AbortSignal threading bounds ReasoningBank.initialize() (#478)
prevents leaked init from runaway patterns.rvf writes
- CapturedExperienceBridge wires hook activity to domain plugins (#479)
via kernel-side drain of captured_experiences
- Removes dead v3-qe-bridge.sh, two stale planning docs, five orphan
workers in qe-workers.ts (subsumed by LearningConsolidationWorker)
Net: +430 / -2,090 lines
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Imp-15: Session Reuse for Repeated Operations
Adds a SHA-256 fingerprint-based operation cache as layer 0 before HNSW
early exit. Exact-match lookups run in O(1) before O(log n) similarity
search, catching repeated operations instantly.
- SessionOperationCache with TTL, capacity eviction, and kv_store persistence
- Wired into TokenOptimizerService.checkEarlyExit() as first check
- cacheOperationResult() stores results after successful LLM execution
- session_cache_stats MCP tool for monitoring hit rates
- CLI: aqe token-usage --cache-stats for cache performance
- Cross-session persistence via existing kv_store table
- 26 new tests covering fingerprinting, TTL, eviction, stats, degradation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
125 test files had beforeEach/beforeAll but no afterEach/afterAll,
leaking state between tests and causing order-dependent failures.
Added cleanup to 104 files (skipped 4 archived, 16 import-only):
- 2 critical DB handle leaks (witness-chain): added db.close()
- 7 high-risk service files: added vi.restoreAllMocks()
- 7 beforeAll files: added matching afterAll
- 88 medium/low risk: added afterEach with appropriate cleanup
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>