Files
HologramAgent-DSH-Memory-Port/test
jianf 09be4de0eb test(memory): pin that ORDINARY_DEGRADATIONS decides the log LEVEL (P1 follow-up)
P1 registered two healthy modes in `ORDINARY_DEGRADATIONS` — `hybrid` (the wired
success path) and `no_vector_space` (a space with nothing comparable to score) —
and the commit message claimed that meant "a healthy wired recall does not log a
warning every turn". Nothing tested it. Measured on 1309afe:

    M-a  delete 'hybrid'            → # tests 268  # pass 268  # fail 0
    M-b  delete 'no_vector_space'   → # tests 268  # pass 268  # fail 0
    M-ab delete both                → # tests 268  # pass 268  # fail 0

while the behaviour really broke (real apply(), debugLog=false):

    mutated hybrid recall → lines=[['warn', '... degraded=hybrid ... inject=138ch']]
    released hybrid recall → lines=[]

A false fault alarm on the happiest path, every single turn, and the suite green.

Why the existing tests could not see it: A3d/D3b assert the LABEL
(`hits.degraded === 'hybrid'`). Removing a member from the Set does not change any
label — it changes only whether `logRecallTurn` treats that label as a fault. The
defect lived exactly in the gap between "the label is right" and "the level is
right", and `grep ORDINARY_DEGRADATIONS test/` was empty. A claim in a commit
message with nothing behind it is the same failure mode as a guard that cannot
fail.

What this commit adds (test/memory-log.test.js only — lib/ untouched)

  L10    one group, three outcomes at the SAME verbosity (debugLog: false):
         `hybrid`               → zero lines
         `no_vector_space`      → zero lines
         `embed_error`          → exactly one line, type 'warn'   ← the control
         Each case asserts its own PRECONDITION first (the run really was
         `hybrid` / `no_vector_space`, and something was really injected), so a
         silent log cannot be confused with a build that never reached the route.
         Without the third case, "silent" would also be satisfied by a build that
         logs nothing at all — which is the original bug the log channel exists
         for (L4).
  L10†   real mutation: 'hybrid' removed from the Set → L10.1 red
  L11†   real mutation: 'no_vector_space' removed → L10.2 red
         Both via `withMutatedIndex` (copy the package, rewrite ONE anchor,
         `count === 1` self-check, import fresh). The mutant runs the SAME
         `assertLevelContract` body the released build passes — a criterion copied
         for the mutant can drift, a shared one cannot. The mutation then asserts
         the throw is `ERR_ASSERTION` AND that the message starts with the specific
         sub-assertion name, so an import failure cannot make it green for the
         wrong reason.
  L11    measured behaviour, pinned so nobody "fixes" it later: a fused recall
         whose candidates were ALL refused by `minScore` still reports `hybrid`
         with zero hits, and is still silent. `no_vector_space` is returned at
         exactly one place (`recall.js`, `vectorScores.size === 0`) and means
         "there was nothing to score" — never "everything was filtered". Collapsing
         the two would hide a threshold set too high behind a "fresh space" story.

Two fixture pitfalls found while writing this, both recorded in the test because
each one silently disarmed its own case:

  · `commit` embeds when an embedder is mounted, so the `no_vector_space` case has
    to write its block BEFORE the embedder appears. The first attempt mounted the
    embedder first, the space filled up, and the label came back `hybrid` — the
    assertion then failed for its own precondition rather than for the subject.
  · `StableMem.recall()` forwards only `topK`/`signal`, so a `minScore` passed
    there never reaches the scorer and L11's precondition would have passed on an
    unchanged result. It drives `recallBlocksHybrid` directly instead.

Not asserted, deliberately: `'no_embedder'`, `'aborted'` and `'vector_ready_unused'`
are also in the Set, but their silence is already carried by L1/L5 (no embedder)
and W11e/W12 elsewhere. Adding them here would inflate the group without covering a
new decision.

旁证 (not acceptance): npm test 272/272, npm run check 12/12, npm pack --dry-run
10 files / 75.3 kB. docs/ and README.md untouched.
2026-11-05 00:51:17 +08:00
..