Two events nobody heard, one handoff heard twice

v10 issues #3327 and #3329. Both are about a message that had no listener, or two listeners where one was meant.

#3327 — the events ork never subscribed to

Claude Code emits these. ork's hooks.json had no entry, so they arrived and went nowhere. Both new hooks are observer-only: they record, they never block.

EventWasNowPosture
DirectoryAddedno listenerlifecycle/directory-addedobserve, sanitize path, log
MessageDisplayno listenernotification/message-display-observerobserve only

The trap was not writing the hooks. It was tests/hooks/test-hook-structure.sh, whose VALID_EVENTS allow-list hard-fails on any event it does not know. Adding an event without extending that list turns a green suite red, which is the gate behaving correctly.

Registration is a pair, and half of it is silent

A hook in hooks.json but missing from entries/<event>.ts dispatches to nothing. The reverse is never invoked. Neither half errors. Click a state to see what the runtime does.

RUNTIME
WHAT YOU SEE IN LOGS

#3329 — the handoff that arrived twice

Two independent injectors opened with the identical marker [Previous Session Handoff]. Same session, same prompt, two blocks. Drag the session count to see the cost.

BEFORE — two injectors
AFTER — claim-once

Verified, not asserted

Every new test was run against origin/main's source to confirm it fails without the fix. A test that passes in both states proves nothing.

StateResult
with the fix11 passed
origin/main source, same tests9 failed / 2 passed
restore checkbyte-identical
build, twicestable at 40 files
typecheck / counts / security0 / PASSED / 19 of 19
context-gate.test.ts6 failed — identical on clean pre-merge and post-merge, not ours

Audit your own repo

The pair check generalizes. Copy this into a session pointed at any Claude Code plugin.

Audit hook registration for the dead-hook class.

For every hook in src/hooks/hooks.json, confirm a matching entry exists in
src/hooks/src/entries/<event>.ts, and vice versa. Report each mismatch as:
  hook name | present in hooks.json | present in entries map | consequence

Then check the event allow-list in tests/hooks/test-hook-structure.sh against
the event union in src/hooks/src/types.ts. An event in one and not the other is
either an untested event or a test that cannot pass.

Do not fix anything yet. Show the table first.