docs(adr): stitch gen (selective OpenAPI codegen) + client publishing#328
Open
rejifald wants to merge 10 commits into
Open
docs(adr): stitch gen (selective OpenAPI codegen) + client publishing#328rejifald wants to merge 10 commits into
rejifald wants to merge 10 commits into
Conversation
…blishing ADR 0013 — `stitch gen`: selective, eject-model codegen from OpenAPI. Cherry-pick operations into stitches, co-locate by operation so a stitch directory is the unit of deletion, fan-in-on-condensed-$ref-graph ownership, atomic schemas/types for frontend bundle-frugality, validator tiers skewed for the frontend, and self-owned orphan detection (manifest + zero-dep import scanner). Reserves the seam for a future `stitch audit`/lint command family. ADR 0014 — Publishing stitch-based clients: recipe + scaffold now, with `defineClient` (the declared override-contract) gated on demonstrated demand, per the project's primitive bar (cf. ADR 0011). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Q1 YAML/$ref: JSON native, YAML via lazy optional, local JSON-pointer hand-rolled, remote $ref out. Q2 validator default: types-only (loud notice), valibot recommended runtime tier. Q3 layout: --layout dir default, flat/single escape hatches. Q4 naming: sanitized operationId, else camelCase(method+path), dedupe by doc-order suffix. Q5: ship `stitch gen prune`, reuse scanner in a future `stitch audit` (no `doctor` surface). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… (v1) Implements ADR 0013's first cut: `stitch gen openapi <spec> --out <dir>`. - Selective (--all/--tag/--only/--grep); selective-by-default (a selector is required). - Co-locate by operation (dir layout) or one file per op (flat); fan-in ownership over the transitive $ref closure places component types in _shared/ (≥2 ops) or private to the one op that uses them — which keeps recursive clusters together for free. - types-only tier (ADR 0013 Q2 default): emits TS types + a typed `stitch<T>()`, no runtime validator; a notice says validation/drift are off. - Auth maps securitySchemes → bearer/apiKey/basic with env() placeholders (oauth2 warns). - Emits client.ts seam, per-op stitches, atomic type files, index.ts, and a .stitch-gen.json ownership manifest. JSON specs parse natively; YAML via a lazy optional. Pure planGen in src/gen-openapi.ts (CLI-only; never in the core/browser bundle), wired through cli.ts. Verified end-to-end against the Swagger Petstore spec: generated client typechecks under strict mode against stitchapi and response types flow through calls. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
rejifald
added a commit
that referenced
this pull request
Jun 28, 2026
PR #328 (open) already claims ADR 0013 (gen) and 0014 (publishing). Renumber the schema-anchored drift ADR to 0015 and update all references; the planned expose-raw follow-up becomes 0016. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
rejifald
added a commit
that referenced
this pull request
Jun 28, 2026
…331) * feat(drift)!: schema-anchored, diff-based drift detection (ADR 0013) Replace the snapshot drift mechanism with schema-anchored drift. Validation is the hard contract (throws on a missing-required/incompatible value and returns the validated value — coerced, defaulted, unknown keys stripped); soft drift is the diff of the raw body against that validated value, classified undeclared (info) / coerced (warn) / defaulted (verbose) and never fatal. This eliminates the variance false positives a single snapshot baseline produced (#327): an optional field absent, a nullable null, an empty/heterogeneous array all validate clean and report nothing. - core: new zero-dep diff.ts + classifyDiff; engine returns the validated value and diffs raw-vs-validated into drift events; DriftOptions = { ignore, severity } - remove the snapshot subsystem: snapshotFile / readonly / onMissing / learn, the `stitch drift generate` CLI, and the critical / watch leveling - vendor-neutral: works for any validator returning a parsed value (no Zod codes) - docs: ADR 0013 (supersedes the drift clauses of 0005), READMEs, the drift guide / two recipes / error page, OVERVIEW / DESIGN / FEATURE-LENSES, and the schema-drift blog post BREAKING CHANGE: drift() no longer accepts critical / watch / onNew / snapshotFile / readonly / onMissing; the `stitch drift generate` command is removed; a call now resolves to the validated value (coerced/defaulted/stripped) rather than the raw body; a missing required field surfaces as `invalid` (make a field required to fail, optional to tolerate). Closes #327. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(adr): renumber drift ADR 0013 → 0015 (avoid collision with #328) PR #328 (open) already claims ADR 0013 (gen) and 0014 (publishing). Renumber the schema-anchored drift ADR to 0015 and update all references; the planned expose-raw follow-up becomes 0016. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * style: prettier-format README.md drift table The merge left the rewritten drift table's separator row unaligned; `pnpm check:format` (prettier --check) flagged it. Alignment only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…chapi/openapi The generator was the one codegen tool whose roadmap pulls in dependencies (valibot/zod emitters, a YAML parser, future audit/lint) — unlike from-curl and export --openapi, which are zero-dep, pure-string, and stay in core. Shipping it inside `stitchapi` would grow that package's tarball and dependency surface even though it's tree-shaken out of the runtime bundle. So it now lives in its own package. - new package @stitchapi/openapi (packages/openapi): planGen library export + a `stitch-openapi` bin (`npx @stitchapi/openapi <spec> --out <dir>`). Zero runtime deps; no dependency on stitchapi (it emits stitchapi symbols as text). - removed from core: src/gen-openapi.ts, test/gen-openapi.spec.ts, and the `stitch gen` command + HELP block in cli.ts. Core is back to no gen surface. - ADR 0013 amended (Decision 8, Gates, Status + a packaging addendum) recording the move and the dep-trajectory rationale. Verified: @stitchapi/openapi typechecks + 10 tests pass; core typechecks and its suite is green (1043, the 10 gen tests moved with the package); the generated Petstore client still typechecks under strict mode against stitchapi via the new bin. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Now that the generator is its own package (@stitchapi/openapi), it can take the deps it needs. `yaml` becomes a real dependency (^2.4.2, resolves to 2.9.0 already in the lockfile) instead of a lazily-probed optional — so `stitch-openapi spec.yaml` just works with no extra install. Still imported lazily, so JSON-only runs never load it, and tsup externalizes it (cli.js unchanged at ~13KB). The core's zero-dep gate is untouched (the dep lives in @stitchapi/openapi, never in stitchapi). ADR 0013 Q1 + Decision 8 + addendum reconciled. Verified against the Petstore YAML spec end-to-end; JSON path unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The CI-only `check:release` gate requires every publishable package to ship an Apache-2.0 LICENSE and a README.md (npm always includes them). The new package was missing both — this adds the canonical LICENSE and a usage README. Not caught by the local pre-push gate, which doesn't run check:release. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The CI-only check:readme gate regenerates the root README PACKAGES table and the core README INTEGRATIONS table from the publishable packages; the new package made them stale. Regenerated via `gen:readme` (snapshot-based, no metric recompute) — adds the @stitchapi/openapi row under a new "Other" category. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The core bundle grew to ~24 kB (whole entry, min+gzip) on main, and every advertised quote was updated except apps/docs/lib/source.ts (still ~23 kB) — which the `size` CI job's check:size-docs flags on this branch. Bump it so all 6 advertised quotes match the measured value. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…kstep The merge from main moved all publishable packages to 1.0.0-rc.4; the new package was still at rc.3, which check:release (version lockstep) rejects. Align it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two cross-linked ADRs capturing a design discussion on letting service owners declare an API as stitches, publish it as a package, and generate stitches from an OpenAPI spec.
ADR 0013 —
stitch gen: selective, eject-model codegen from OpenAPIThe ingestion counterpart to the existing
stitch export --openapi/from-curl.--only/--tag/--grep) over operations; you pick what becomes a stitch._shared/.$refgraph — SCC condensation so recursive clusters move as a unit (and getz.lazy/v.lazy).types-only/valibot/zodtiers skewed for frontend bundle size. Consistent with ADR 0011 (emits validator source, no core schema engine).// TODO(auth env var, throttle, pagination) — no required config.knip/ts-prune.stitch audit/lint family (e.g. "every operation must declare input + output").ADR 0014 — Publishing stitch-based clients
seam()already is the client, so publishing is mostly a recipe.create-stitch-packagescaffold now (factory, call-time secrets, typed.d.ts, bundled drift snapshot).defineClient(the declared override-contract:require/allowOverride/lock) on demonstrated demand, per the project's primitive bar (cf. ADR 0011 /inferBearer). The generator may create that demand.Both ADRs are Proposed, docs-only, no code. All verify gates (format, typecheck, test, exports, build-docs) pass.
🤖 Generated with Claude Code