Skip to content

feat: spec-level Postel's-Law tolerant readers#36

Merged
caballeto merged 1 commit into
mainfrom
feat/postel-tolerant-readers
May 11, 2026
Merged

feat: spec-level Postel's-Law tolerant readers#36
caballeto merged 1 commit into
mainfrom
feat/postel-tolerant-readers

Conversation

@caballeto
Copy link
Copy Markdown
Member

Summary

CLI now decodes response-DTO multi-value enums as plain strings, so
MonitorDto.type, IncidentDto.status, etc. flow through the Zod
schemas as z.string() and accept future API values added after this
CLI version was built. Authoring schemas (oclif --type flags, YAML
config validation) stay strict — spec-facts.generated.ts reads from
the un-relaxed spec snapshot.

Implementation

scripts/lib/preprocess.mjs is the vendored copy of mono's
@devhelm/openapi-tools preprocessor. It now calls
relaxResponseEnumsInSpec before the spec is handed to
openapi-zod-client, so the relaxation happens at the spec level
(not as a post-processing regex). scripts/generate-zod.mjs clones
the spec before preprocessing so generateSpecFacts operates on the
strict snapshot — request-side authoring DX is preserved.

Cross-surface design: mini/runbooks/api-contract.md § 3.1.

Tests

  • 998 / 998 tests pass.
  • npm run lint clean, npm run typecheck clean.

Test plan

  • CI green.
  • Manual smoke: npm run zodgen produces z.string() on
    response DTOs and preserves z.enum([...]) on request DTOs.

Made with Cursor

Vendored `scripts/lib/preprocess.mjs` is now in lockstep with mono's
`@devhelm/openapi-tools` and runs `relaxResponseEnumsInSpec` before
openapi-zod-client consumes the spec. Response-DTO multi-value enums
are dropped at the spec level, so the generated Zod is `z.string()` for
those fields — `MonitorDto.type` decodes any string, including future
values added by the API after this CLI version was built. Request DTOs
keep their literal unions for strict authoring-time validation.

`scripts/generate-zod.mjs` clones the spec before preprocessing so the
spec-facts emitter (`spec-facts.generated.ts`) keeps reading from the
*un-relaxed* spec — the YAML / oclif flag validators stay strict.

See `mini/runbooks/api-contract.md` § 3.1 for the cross-surface design.

Coverage: 998 / 998 tests pass; lint + tsc clean.
Co-authored-by: Cursor <cursoragent@cursor.com>
@caballeto caballeto merged commit 79c7b63 into main May 11, 2026
3 checks passed
@caballeto caballeto deleted the feat/postel-tolerant-readers branch May 11, 2026 19:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant