Skip to content

refactor(api)!: contract freeze — hard-break sweep of the entire published surface#470

Open
rejifald wants to merge 4 commits into
mainfrom
claude/public-surface-contract-audit-aa14a1
Open

refactor(api)!: contract freeze — hard-break sweep of the entire published surface#470
rejifald wants to merge 4 commits into
mainfrom
claude/public-surface-contract-audit-aa14a1

Conversation

@rejifald

@rejifald rejifald commented Jul 8, 2026

Copy link
Copy Markdown
Owner

What

The full pre-GA API freeze: every method name, prop name, and returned type across stitchapi core (15 entry points) and all 32 published @stitchapi/* packages now matches docs/CONTRACT.md (P0–P23). Maintainer-sanctioned hard break — no @deprecated aliases added, and every existing shim + alias-parity test deleted (pre-GA, few adopters; P19 amended accordingly).

Driven by a 35-agent audit (17 scoped auditors + adversarial verification + coverage critic) that found ~95 deduplicated violations; all are addressed here.

Highlights

  • P0 restored (load-bearing): __config is strictly JSON again — url thunks, transform, predicates, keyOf, paginate fns, hooks all live on the non-enumerable __rawConfig; RedactedStitchConfig narrowed; runtime regression spec (contract-p0.spec.ts) pins zero fn-paths + lossless JSON round-trip.
  • Renames: querydocument, unwrappick, cache.key()keyOf(), valuedata on every result envelope, scopetenancy (auth), otlpTraceotlpSink, deldelete, dateTimeamzDate, decoderesponseType, all five authoring binders →.bind, StitchQueryStateStitchQueryResult, UseStitchReturnUseStitchResult, svelte standardizes on stitchStore*, hosts converge on streamStitchSse + StitchErrorOptions, plugin/middleware options framework-qualified.
  • Typing: StatusMatch (number | number[] | predicate) on every status field; T | T[] widenings; every config slot is Scalar | AtLeastOne<Options> ({} is a compile error) with new scalar shorthands (stream:'ndjson', multipart:'dot', sse:true, throttle:'2/s', idempotency:true, circuit:[failures,cooldown], inspect(input,true)); StitchStore ttl optional on set/incr; RateLimitError carries the full P10 field set.
  • Fixes found by the audit: elysia SSE no longer leaks raw upstream error messages to clients (generic token + errorData opt-in, matching all hosts); openapi generator emits type-correct apiKey auth; next stitchErrorResponse returns Response | undefined so ?? throw composes; react/angular hooks no longer accept-and-ignore a streaming flag.
  • Hoists: StitchQueryOptions + key-derivation (incl. secret-header redaction) single-sourced in @stitchapi/query-core (was byte-copied in 5 bindings); StitchEventSource owned by core.
  • Blessed carve-outs (recorded in CONTRACT.md): StitchQueryOptions keeps TanStack's own vocabulary; StitchLike rich/minimal tiers; P8 documented default divergences (oauth2/cookie tenancy, pino/sentry lifecycle, RN keyPrefix).
  • Docs: every MDX/blog/playground/sandbox reference respelled (docs build incl. full twoslash passes); unwrap guide → pick with a permanent redirect; completions codegen regenerated.
  • Ratchet hardened: R1 bans *Return/*State, R6 covers nested toggle slots, R5 de-lists documented, new R7 fails on any @deprecated on the surface. Baseline: 0.
  • Core bundle budget 24.80→25.25 KB (documented: intake normalization + P0 redaction outweigh deleted shims by ~0.2 KB).

Verification

All 12 gates green: check:types, check:types-d, check:lint, check:format, check:contract (baseline 0), check:exports(+companions), check:size, check:docs-links, check:release, full workspace tests, and the apps/docs production build (twoslash-compiles every snippet).

media-fresh note: pushed with STITCH_MEDIA_STALE_OK=1. The demo scene's only changes are inside the pick segment, which is not part of the recorded README cut (4-segment loop, verified frame-by-frame); a full gen:media re-render produced byte-identical assets (hash-verified), so the committed media is genuinely fresh — the path-based gate cannot express "regenerated, no diff".

🤖 Generated with Claude Code

rejifald and others added 4 commits July 8, 2026 16:27
… renames, shim purge

Sweep of the entire published surface against docs/CONTRACT.md (P0–P23),
maintainer-sanctioned hard break (no @deprecated aliases; pre-GA, few adopters):

- core P0: __config is strictly JSON again — all function sugar (url thunks,
  transform, predicates, keyOf, paginate fns, hooks) lives on __rawConfig;
  RedactedStitchConfig narrowed; runtime regression spec added
- core renames: query→document, unwrap→pick, cache.key()→keyOf(),
  SurfaceOutcome/CacheHit value→data, timing.ms→elapsed, otlpTrace→otlpSink,
  scope→tenancy, registerSecretKey/isSecretKey, maxBodyChars, serverInfo,
  graphql/sse/stream/download/llm binders → .bind, testing SseFixtureEvent
- typing: StatusMatch (number|number[]|predicate) everywhere; T|T[] widenings;
  Scalar|AtLeastOne on every config slot (stream/multipart/sse/throttle/
  idempotency/hooks/input/retry/timeout/circuit incl. [failures,cooldown]
  tuple + inspect(input,true)); StitchStore ttl optional on set AND incr;
  RateLimitError gains attempts/body/url (P10 parity)
- every existing @deprecated shim + alias-parity test deleted repo-wide
  (rateLimit slot, throttle.scope, key fns, *Ms fields, value co-sets,
  bare queryOptions/RequestSeam/StitchHost, SchemaFingerprint.value, …)
- packages: query-core hoists StitchQueryOptions (blessed TanStack mirror) +
  key derivation for all five bindings; StitchQueryState→StitchQueryResult;
  svelte drops useStitch* for stitchStore*; hosts converge on streamStitchSse
  + StitchErrorOptions with elysia SSE error-leak fix; next stitchErrorResponse
  → Response|undefined; stores del→delete + optional-ttl house contract;
  openapi generator apiKey emission fixed; shell responseType/maxBufferBytes;
  aws-sigv4 amzDate; json-schema AjvLike; fingerprint unwrap→pick
- contract ratchet baseline shrunk to 0

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…CT.md rewrite, ratchet upgrades, SSE parity

- apps/docs: all integration/guide/blog pages respelled to the canonical
  surface (document/pick/pool/tenancy/streamStitchSse/StitchErrorOptions/
  StitchQueryResult/stitchStore/amzDate/…); unwrap guide renamed to pick
  (+ permanent redirect); playground presets, completions codegen, sandbox
  allow-list and demo scene updated; search golden follows the new slug
- docs/CONTRACT.md rewritten to post-sweep reality: violation lists are now
  resolved-history, §6 is a migration record (alias-free hard break under
  maintainer waiver), P19 amended (pre-GA hard breaks sanctioned; deprecation
  cycle from GA), blessed carve-outs recorded (StitchQueryOptions TanStack
  mirror, StitchLike tiers, svelte stitchStore, P8 divergences, shared host
  shapes, redaction sentinels)
- scripts/check-contract.mjs: R1 bans *Return/*State, R6 covers nested
  toggle slots (real finding fixed: mcp serverInfo → AtLeastOne), R5
  watch-list refreshed with de-list rationales, new R7 flags any @deprecated
  on the published surface; baseline stays 0
- hosts: StreamStitchSseOptions widened to the express canonical shape
  (data(chunk, index), event string|fn) in fastify/nest/hono/elysia/next,
  with per-host tests
- from-curl bodyType (last P1 stragglers), mcp tool description respelled

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- eval-harness prebaked snippets respelled (document/pick/pages/baseDelay) —
  the offline scorer was exercising the deleted surface
- core bundle budget 24.80→25.25 / 20.00→20.40 KB, documented: scalar-shorthand
  normalization, StatusMatch matcher and P0 deep redaction outweigh the deleted
  shims by ~0.2 KB and cannot move to a subpath
- README prettier pass

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New normative rule P24 (+ ratchet R8 enforcing it): >=2 flat fields sharing
a leading-word prefix in a house-owned contract fold into one named,
exported, {}-rejecting envelope with a dominant-field scalar. Carve-outs:
foreign mirrors (TanStack queryKey/queryFn, RFC 6749 client*, XHR response*,
RTK lifecycle, Orama-schema DocSearchHit.page* — maintainer-exempted),
single-field collapse per P12, on*/is*/percentile conventions.

Conversions (hard break, per amended P19):
- OAuth2Options.refreshOn/refreshSkew → refresh: StatusMatch | { on, skew }
- CookieSessionOptions.refreshOn/refreshWhen → refresh: StatusMatch | { on, when }
- SentrySinkOptions.captureErrors/captureDrift → capture: boolean | { errors, drift }
- nest StitchFeatureOptions.seamConfig/seamToken → seam: { config, token }
  (R8's first real catch, found during adoption)

Docs/blog/READMEs/AUTHORING respelled; ADR 0006 amended via callout;
contract baseline stays 0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@@ -101,7 +101,7 @@ const me = stitch({
loginInput: () => ({

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a convention for these type of callbacks.
So it can accommodate both function and declaration

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