# OpenSpec Change: idempotency-spec-conformance - **Change ID**: idempotency-spec-conformance - **Package**: `@suaveplan/idempotency` - **Status**: PROPOSED - **Date**: 2026-04-26 ## Summary Bring `@suaveplan/idempotency` into spec conformance with `openspec/specs/idempotency/spec.md`. The implementation already satisfies every MUST clause; this change closes the documentation and parsing gaps so `bun scripts/openspec-conformance.ts @suaveplan/idempotency` exits 0. No public-API changes. ## Current state `@suaveplan/idempotency` ships a complete enterprise-grade implementation: structured error hierarchy, eight `IDEMPOTENCY.*` codes with metadata, eight Zod boundary schemas, injectable `Clock`, AbortSignal propagation, full OTel meter wiring, `MemoryIdempotencyStore` / `RedisIdempotencyStore` / `DatabaseIdempotencyStore`, `MemoryLockProvider` / `RedisLockProvider`, fast-check property tests, and a mitata benchmark suite. The conformance gaps are mechanical: - `src/error-codes.ts` declared the codes inline (`{ ... } as const`) instead of via `defineCodes("IDEMPOTENCY", [...])`, so the conformance script could not parse the registry. - The folded spec used `### REQ-IDMP-NNN — name` headings, which the parser (`^[A-Z][A-Z0-9]*-\d+`) silently skips, yielding 0 parsed requirements. - Schemas were exported but never invoked outside `src/schemas/` (every consumer composes the underlying Zod object directly), triggering boundary warnings. - 10/10 requirements lacked `**Verified by:**` lines. - Five implicit scenarios were exercised only indirectly: clock injection, AbortSignal mid-flight, OTel no-op + per-instrument labels, structural-adapter acceptance, and benchmark presence. - `tasks.md` of `2026-04-19-enterprise-idempotency/` carries the `retroactively ticked` marker. ## What changes 1. Refactor `src/error-codes.ts` to declare `IDEMPOTENCY_CODES` via `defineCodes("IDEMPOTENCY", [...])` from `@suaveplan/error`. Re-export from `src/errors/idempotency-error.ts` for backwards compat. No public-API change. 2. Add `// schema: boundary-only` marker to `src/schemas/idempotency.schemas.ts` to suppress the (correct) boundary warning — schemas are consumer-facing only. 3. Rewrite the requirement headings in `openspec/specs/idempotency/spec.md` from `REQ-IDMP-NNN — name` to `IDMP-NN — name` so the conformance parser picks them up. Add `**Verified by:**` lines under every requirement. 4. Add five `*.spec-conformance.test.ts` files pinning the implicit scenarios: - `src/errors/idempotency-error.spec-conformance.test.ts` — IDMP-01 (hierarchy + namespace + frozen registry). - `src/schemas/idempotency.schemas.spec-conformance.test.ts` — IDMP-02 (every required schema present and round-trippable). - `src/guard/idempotency-guard.spec-conformance.test.ts` — IDMP-03 (clock-driven timestamps & cleanup) + IDMP-04 (pre-aborted and mid-flight signal). - `src/metrics/idempotency-metrics.spec-conformance.test.ts` — IDMP-05 (no-op without meter, all five instruments, correct outcome / operation / result labels, histogram values). - `tests/structural-adapters.spec-conformance.test.ts` — IDMP-08 (plain-object adapter and lock provider). - `tests/benchmarks-present.spec-conformance.test.ts` — IDMP-07 (suite at canonical path covers all four hot paths). 5. Re-run `bun scripts/openspec-conformance.ts @suaveplan/idempotency` and confirm exit 0. ## Impact - Public API unchanged. - Error-code registry now uses the canonical `defineCodes` helper. - Six new test files (~350 lines combined). - `openspec/specs/idempotency/spec.md` gains 10 `**Verified by:**` lines and parseable headings.