# `validateErrorStatusMapShape` ## Purpose Defence-in-depth re-check of the `errors.statusMap` shape. The Zod schema already rejects malformed entries; this validator collects every offender (rather than fail-fast on the first) so admin tooling can render the full diagnostic in one pass — operators get a complete fix list instead of fix-one-rerun-find-next. ## Features - Walks every map entry — no early exit - Surfaces code-format violations separately from status-range violations - Empty / absent map is a no-op success - Reuses `errorCodeRegex` from the schema layer to avoid drift ## Basic Example ```ts import { validateErrorStatusMapShape, parseManifest } from "@suaveplan/api-manifest"; validateErrorStatusMapShape(parseManifest(raw)); ``` ## Advanced Example ```ts import { validateErrorStatusMapShape } from "@suaveplan/api-manifest/validators"; import { parseManifest } from "@suaveplan/api-manifest/parse"; const manifest = parseManifest(raw); const check = validateErrorStatusMapShape(manifest); if (!check.ok) { for (const o of (check.error.context?.offenders as { code: string; status: number; reason: string }[])) { console.error(o.code, o.status, o.reason); } } ``` ## API Reference - `validateErrorStatusMapShape(manifest: PluginManifest): ValidationResult` - Failure code: `MANIFEST.INVALID_ERROR_STATUS_MAP` with `context.offenders: { code, status, reason }[]`. ## Implementation Notes Because the Zod schema rejects ill-shaped entries up front, the only way this validator ever finds an offender is via direct programmatic construction (skipping `parseManifest`) — but that path is real (the host builds plugin manifests in tests, the registry seeds them, etc.). The validator's batch-mode contract means it remains the canonical check at the install gate even when the schema has already run. ## Cross-package Notes This module is part of the `@suaveplan/api-manifest` Stage-1 contract package. It sits beneath every Stage-2 consumer (`api-host`, `api-loader`, the admin CLI, the IDE plugin) and above the foundation packages (`@suaveplan/error`, `@suaveplan/types`). The strict-mode top-level rejection of unknown keys means upgrading from manifest v1 to v2 is an OpenSpec-driven event: a new key landing in a consumer manifest is a parse failure rather than a silent drift, which is exactly the contract this stage exists to guarantee. When the host reloads a plugin without a full restart, every manifest field this module validates is compared against the install-time `manifestHash`. A mismatch triggers a hard rollback via the `RollbackJournal` because the host's invariants (route mounts, registered capabilities, declared scopes) are derived from these exact bytes. Treat the schemas and validators here as the contract surface, not just an input filter — downstream code reads `manifest.foo.bar` and relies on those keys being present, well-typed, and non-undefined in the documented optionality regions.