# Change: enterprise-error ## Why `@suaveplan/error` is the **foundation error substrate** — every other package in the monorepo extends `SuaveplanError` and uses its stable code registry. On the genesis branch it does not yet exist. It must land **before** any other Layer 1 package (events, crypto, bitpacker, timing, datetime, serialize, mime, env, opentelemetry) because each of them declares its own error subclass against this base. Per the project rule for foundation packages (`memory: foundation-100-coverage`), this ships at **100%** coverage (statements / branches / functions / lines) — not the 95% floor. Anything less puts a long-term ceiling on every consumer. ## What Changes ### New package: `packages/universal/error` Ships a self-contained, zero-dependency (no `@suaveplan/*`, no runtime browser/Node/React APIs) TypeScript library: - **`SuaveplanError`** abstract base class with `{ code, message, cause?, context?, timestamp, traceId? }` shape - **Stable code registry** — namespaced `PACKAGE.DOMAIN.REASON` strings, typed as a const record; each package adds its own leaf registry that extends this one without renumbering - **Typed error discriminants** — generics propagate the code union through `instanceof` checks so consumers get exhaustive switch coverage without casts - **Cause-chain traversal** — `walkCauses(err)` generator, cycle-safe, depth-bounded - **Wire format** — Zod schema for JSON and MessagePack (MessagePack encoder ships as a pure function, no external `msgpack` dep; binary format is documented and versioned) - **Redaction** — `@sensitive` tag on context fields, applied at the serialization boundary; redacted fields become `"[REDACTED]"` in the wire payload but remain accessible on the in-memory instance - **Injectable clock** — `createError({ clock })` takes an optional clock so timestamps are deterministic under test; the module-level default uses `Date.now()` but is never touched at import time - **OTel span event adapter** — `toSpanEvent(err)` returns the payload an OTel span recorder expects (`exception.type`, `exception.message`, `exception.stacktrace`, all attribute values serialized) - **i18n-ready** — every user-visible string is keyed, never literal; the default locale is pass-through (returns the key) ### Why this stays foundation-pure The enterprise brief calls for `@suaveplan/schema-registry`, `@suaveplan/logger`, `@suaveplan/i18n`, and `@suaveplan/opentelemetry` integration. Those are **adapters**, not dependencies — this package exposes the hooks (`toSpanEvent`, i18n-key strings, Zod schemas, logger-compatible `toJSON`) but does not import any of them. Wiring happens in the dependent packages. ### Coverage gate Vitest thresholds set to 100/100/100/100 from day one. No `istanbul ignore` pragmas (empirically stripped by the esbuild transform). Dead defensive branches are either removed or upgraded to `as` assertions with invariant comments. ## Impact - Unblocks every other Layer 1 package (events, crypto, bitpacker, timing, datetime, serialize, mime, env, opentelemetry) which extend `SuaveplanError` - Adds one new spec capability: `error` - No existing code paths affected (genesis branch has no consumers yet)