Move src/shared/ipc/errors.ts to src/shared/ipc/errors/index.ts so each migrated domain can host its own error-code map as a sibling errors/<domain>.ts — value-importable by both processes and zod-free. The @shared/ipc/errors barrel path is unchanged, so every importer and test resolves identically (typecheck + IPC tests green).
Document the IpcErrorCode usage convention that previously lived only in code comments: the framework-code single source of truth, the open (string & {}) tail for domain codes, where domain codes belong (errors/, not schemas/, since the renderer may only import type from schemas), and why they are imported directly rather than aggregated through a barrel.
Make the IpcApi docs explicit about three things surfaced in review:
- overview: Why Narrow the Surface (before/after + the type/cheat-sheet/audit wins), Direction Cheat Sheet (IpcRoute vs IpcEventName + out-of-scope), and No One-Way R->M Primitive (every R->M is invoke/handle; void still round-trips).
- migration guide: Escape Hatch criteria (direction gate then frequency) with Tab_MoveWindow as the sole qualifying carve-out, its two hard conditions (still gated, still documented), and scope discipline for the sibling one-off channels; add Tab_MoveWindow to the Not In Scope table.
- README + usage: navigation pointers and the R->M / M->R high-frequency asymmetry (M->R stays via class B, R->M may escape).
The per-domain schemas/__tests__ (window + selection) asserted zod
primitives: that z.boolean() rejects a string, that z.infer yields boolean,
that never-parsed output schemas round-trip — i.e. they tested zod, not our
code. The route inventory they locked is already enforced at compile time by
IpcHandlersFor exhaustiveness plus the global IpcRoute union test.
Remove all four. Document the boundary across the IPC docs (usage /
schema-guide / migration-guide): test the handler (real behavior), not the
schema; business validation lives in the handler/service, so a schema worth
unit-testing effectively never arises.