Files
HologramAgent-DSH-Memory-Port/lib
jianf 07f8438964 fix(memory): count every dropped candidate, not just the two upstream ones (D2)
`recallBlocks` could make a candidate disappear in three downstream places, and
none of them incremented anything:

    · MinScore gate        it scored, but below the threshold
    · structural gate      neither a usable vector score nor a symbol hit
    · caller topK          survived everything, fell outside the requested count

Measured before this change, 6 blocks in one space, `minScore: 0.99`:

    hits=0  skipped=0  skippedDim=0

That reading is indistinguishable from "the space holds one block". An operator
whose threshold is swallowing the whole corpus is told "nothing was excluded",
and goes looking at the wrong subsystem. Only the space filter and the width
filter were ever counted — the two that are decided before scoring.

## What this adds

Three non-enumerable counters, each named after its own remedy:

    skippedScore       lower the threshold
    skippedNoEvidence  re-embed: there was nothing to score
    truncated          not a defect — reported so the totals reconcile

Plus the invariant that makes the next silent path impossible:
**hits + skipped + skippedDim + skippedScore + skippedNoEvidence + truncated
=== the candidate pool.** A future `continue` that forgets a counter breaks it.

## Criterion

`test/recall-accounting.test.js`, one fixture per path, asserting each counter's
own value (not a merged total — "scored too low" and "nothing to score" have
opposite remedies). The fourth test is the reconciliation above.

Mutations, both in a scratch copy:

    remove `gatedByScore += 1`     -> criteria 1 and 4 red
    remove `gatedNoEvidence += 1`  -> criterion 2 red

## Collateral: two static mutation anchors moved

`test/phase-b-a.test.js` pins the V5 gate and the caller-topK truncation by
rewriting `lib/recall.js` text. Making the gate multi-line (to hold a counter)
and threading `drops` through `withSkipped` changed those exact strings, so the
anchors are updated to the new text — same mutations, same properties pinned.
Running the file confirms 38/38 afterwards; without the update three V5†
mutations failed on a stale anchor rather than on their subject.

Gates: npm test 298/298 (0 skipped), npm run check 12/12. Frozen faces untouched.
2026-11-05 11:42:06 +08:00
..