Files
fusion/packages/engine/src/__tests__/reliability-interactions
gsxdsm bbaa254dc3 test: add the missing debug to 27 logger mocks (206 → 4 failures) (#2573)
**Test-infrastructure fix.** 29 test files. No production code, no
altered assertions, no widened timeouts.

Now **3 commits** (#2584 merged into this branch): the logger-mock
sweep, a cron-runner follow-up from review, and the 4 residual failures
the sweep deliberately deferred.

**Whole branch: 764 tests, 0 failures** across the touched set.

---

## Commit 1 — the missing `debug` on 27 logger mocks

`createLogger`'s real shape is `{ log, debug, warn, error }`. 27 engine
test files mock `../logger.js` with logger-shaped literals that **omit
`debug`**, so any production path reaching `log.debug` threw:

```
TypeError: schedulerLog.debug is not a function
TypeError: runtimeLog.debug is not a function
TypeError: log.debug is not a function      (SelfHealingManager.start)
```

Measured, same commit, same 27 files:

| | Failed | Passed |
|---|---|---|
| before | **206** | 558 |
| after | **4** | 760 |

**202 failures fixed by one missing mock export.** Per-file: `notifier`
36→0, `plugin-runner` 56→0, `grok-runtime-routing` 14→0,
`self-healing-completion-fanout` 1→0. That last one also leaked an
unhandled rejection out of `startMaintenance`, which vitest warns "might
cause false positive tests" elsewhere in the file.

*A note on the number:* a full `engine-default` run went 283 → 106
across my two sessions, but `main` moved in between (U11 landed), so
that spread is **not** attributable here. 206 → 4 is the honest figure:
same commit, same file set, only this diff varying.

## Commit 2 — cron-runner's factory (greptile P1)

My regex required `log: vi.fn()`; `cron-runner.test.ts` uses `log:
cronLoggerSpies.log`, so the `createLogger` factory's returned literal
never matched and the logger production received still lacked `debug`.

**Measured before claiming a live fix, and the numbers don't support
that part:** `cronLoggerSpies.debug.mock.calls.length` is **0** across
all 155 tests, and the suite is 155 passed both before and after. The
described failure mode — `tick()` hitting `log.debug`, throwing, and
being swallowed by its own error handler — is **not reachable today**,
because no test exercises those three branches (`cron-runner.ts:377`,
`:385`, `:410`). The fix is defensive, not curative. The real gap it
surfaced is **missing coverage** for schedule dedupe / scope mismatch /
lost atomic claim, which I did not write blind to close a thread.

## Commit 3 — the 4 residuals

**`notification-service` (3):** messages moved to DEBUG in production
(`:580`, `:846`) while tests asserted `schedulerLog.log`.

The token case needed more than a relocation. It asserted
`expect(schedulerLog.log).not.toHaveBeenCalledWith(containing("new-token"))`.
Moving only the *positive* assertion to `debug` would leave the secrecy
check watching a channel the message no longer uses — a token could leak
through `debug` and the test would still pass. The negative now runs
across all four channels. **Verified it bites:** interpolating the token
into the debug line fails the test.

**`openclaw-runtime-integration` (1):** `../pi.js` mock missing
`wrapToolsWithOutputBudget` (same class as #2547); this suite exercises
a non-pi runtime, exactly where that wrapper applies.

**Not swept repo-wide, and the measurement is why.** 37 `pi.js` mocks
omit that export. Patching 30 moved the set from **11 failed to 10** —
thirty files of churn for one test. Reverted. Commit 1 earned its
27-file diff with 202 fixes; this one earned nothing, and a no-op sweep
is just future merge conflicts for other workers on this program.

---

## Why none of this is appeasement

AGENTS.md forbids making a red test pass by loosening it. This does the
opposite: the mocks were **wrong** — they claimed to stand in for
`createLogger` while missing part of its interface. Nothing was relaxed;
stubs were completed, and the one assertion I did move got **stronger**
(four channels instead of one).

## Also deliberately not done

Extending `scripts/check-mock-completeness.mjs` to catch this class.
Measured first: a naive rule over relative intra-package mocks flags
**147** factories of which **146 are green** — almost pure false
positives. The barrel heuristic works because `cliSrc` gives a tight
import surface; that doesn't transfer. A gate that noisy gets ignored,
which is worse than no gate.

## How this was found

While characterizing U9's review lane. These files were pre-existing
baseline noise under mutation runs — and that noise is exactly what made
my own safeguard baseline (#2511, corrected in #2520) report two false
verdicts. **A red suite does not merely lack coverage; it makes every
nearby measurement untrustworthy.**

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 10:50:46 -07:00
..