# `runManifestConformance` and fixtures _(no submodules)_ ## Purpose Reusable conformance harness for downstream tooling (admin CLI, IDE plugin) that ships its own `parseManifest` implementation. The harness drives any parser through four fixture buckets — minimal-valid, maximal-valid, missing-name-invalid, unknown-key-invalid — and returns a per-bucket boolean report. ## Features - Two valid fixtures: minimal (the smallest legal manifest) and maximal (every documented field) - Two invalid fixtures: missing-name and unknown-key (the strict-mode rejection case) - `runManifestConformance` returns a discriminated `ConformanceReport` - Fixtures exported individually so tests can build variants without copy/paste ## Basic Example ```ts import { runManifestConformance } from "@suaveplan/api-manifest/testing"; import { parseManifest } from "@suaveplan/api-manifest/parse"; const report = runManifestConformance(parseManifest); ``` ## Advanced Example ```ts import { runManifestConformance, MAXIMAL_FIXTURE, type ConformanceFixtures } from "@suaveplan/api-manifest/testing"; const fixtures: ConformanceFixtures = { minimal: { name: "x", version: "0.1.0", apiHost: "^2", isolation: "trusted", trustLevel: "first-party" }, maximal: MAXIMAL_FIXTURE, invalidMissingName: {}, invalidUnknownKey: { ...MAXIMAL_FIXTURE, badKey: 1 }, }; const report = runManifestConformance(parseManifest, fixtures); ``` ## API Reference - `runManifestConformance(parse, fixtures?): ConformanceReport` - `MINIMAL_FIXTURE`, `MAXIMAL_FIXTURE`, `DEFAULT_FIXTURES`. - `ConformanceFixtures`, `ConformanceReport`. ## Implementation Notes The harness deliberately returns a structured report rather than throwing — downstream consumers may want to render the report into their own CI surface (a custom matcher, a JUnit emitter, etc.) without coupling to a specific assertion library. The `MAXIMAL_FIXTURE` is the same shape used in the package's own integration tests so any downstream parser that passes the harness is checked against the same canonical example. ## 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.