Skip to content

docs: note that mock-endoify voids guard-refusal assertions - #1059

Draft
ci-belphegor wants to merge 1 commit into
mainfrom
grypez/mock-endoify-guard-assertions
Draft

docs: note that mock-endoify voids guard-refusal assertions#1059
ci-belphegor wants to merge 1 commit into
mainfrom
grypez/mock-endoify-guard-assertions

Conversation

@ci-belphegor

Copy link
Copy Markdown

Explanation

mock-endoify stubs globalThis.assert and its methods with no-op vi.fn()s. @endo/exo rejects a guard violation through assert.Fail, so under the shim such a rejection carries undefined — and vitest treats an undefined rejection as satisfying any rejects.toThrow matcher:

rejection value assertion verdict
undefined .rejects.toThrow(/zzz/u) passes
exo guard violation .rejects.toThrow(/zzz/u) passes
new Error('real') .rejects.toThrow(/zzz/u) fails ✓
'plain string' .rejects.toThrow(/zzz/u) fails ✓

So such an assertion also passes with the guard removed. This adds a testing convention to AGENTS.md and a warning at the shim itself.

This costs test validity, not safety. Enforcement is unaffected — the guard still blocks the call and the guarded method never runs. Nothing here papers over a live bug.

Notes for reviewers

An audit of all 14 mock-endoify packages found no assertion currently relying on the vacuous path. Method: patch assert.Fail to throw a recognizable error, then run every suite — a vacuous assertion cannot survive that. 13 packages stayed green; sheaves produced 4 failures, and those turned out to be a different mock artifact (harden is a no-op, so errors are not frozen, so endo's passability check fires and the no-op swallows it — two lies cancelling). Those 4 assert real messages and are fine. Bare rejects.toThrow() calls, which that method cannot detect, were grepped separately: the only hit is inside a JSDoc comment describing a helper already written to avoid this.

A lint rule is not feasible, which is why this is a convention. Telling a guard rejection from one carrying a real Error is semantic; the only mechanical rule — banning rejects.toThrow in shimmed packages — would reject the 182 legitimate uses there.

Making the stub honest is not the fix either, and the comment records why so nobody repeats the experiment: @endo/patterns calls assert.fail during module initialization, so a throwing stub stops test files from loading entirely.

Independent of the narrowing stack; based on main. No changelog — @ocap/repo-tools is private and neither change is consumer-facing.

`mock-endoify` stubs `assert` with no-ops, so `@endo/exo` rejects a guard
violation with `undefined`, and vitest treats an `undefined` rejection as
matching any `rejects.toThrow` matcher. Such an assertion therefore passes
with the guard removed. Enforcement is unaffected — the guarded method still
never runs — so this costs test validity, not safety.

A lint rule cannot catch it: telling a guard rejection from one carrying a
real `Error` is semantic, and banning `rejects.toThrow` outright would reject
the 182 legitimate uses in shimmed packages. An audit of all 14 found no
assertion currently relying on the vacuous path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant