Skip to content

ci(spec): public API-surface snapshot gate to catch silent export drift (#2035)#2092

Merged
xuyushun441-sys merged 1 commit into
mainfrom
spec/api-surface-gate
Jun 21, 2026
Merged

ci(spec): public API-surface snapshot gate to catch silent export drift (#2035)#2092
xuyushun441-sys merged 1 commit into
mainfrom
spec/api-surface-gate

Conversation

@xuyushun441-sys

Copy link
Copy Markdown
Contributor

Follow-up to #2035 / #2088 / #2089. The tightest pure-type backward-compat gate: catch a removed/renamed/kind-changed @objectstack/spec export at PR time, before it breaks a published-spec third party.

Why

For a metadata-driven platform the spec package is the third-party API. A silently dropped export breaks every consumer pinned to a published release the moment they upgrade — the #2023 class of break. No in-repo consumer catches it, because the examples and @objectstack/dogfood co-evolve with the spec in the same commit.

What

scripts/build-api-surface.ts enumerates every exported name (kind) from the built .d.ts of all 16 public entry points (., ./ui, ./data, … — 4251 exports), resolving re-export aliases to their real kind (so definePage reads as function, PageInput as type). The snapshot is committed at packages/spec/api-surface.json.

pnpm --filter @objectstack/spec gen:api-surface     # regenerate + write
pnpm --filter @objectstack/spec check:api-surface   # CI: fail on drift

Wired into lint.yml's TypeScript Type Check job (after the build step that produces the dist). A removed export fails as breaking; an added export still requires regenerating the snapshot — so every change to the public surface is deliberate, never silent.

How it fits the third-party validation strategy

Gate Proves PR
objectstack validate (loader) a third party's own metadata parses exists
downstream-contract (typed fixtures) exercised exports still accept real metadata — depth #2089
api-surface snapshot the whole export set still existsbreadth this

Verification (local)

Notes

  • Dev tooling only — neither the script nor api-surface.json is in the package files, so nothing ships to consumers (no changeset needed; the gate's pending-changeset count is already > 0).

🤖 Generated with Claude Code

…ft (#2035)

For a metadata-driven platform the spec package IS the third-party API surface.
A removed/renamed/kind-changed export silently breaks every consumer pinned to a
published release the moment they upgrade (the #2023 class) — and no in-repo
consumer catches it, because they all co-evolve with the spec in the same commit.

`scripts/build-api-surface.ts` enumerates every exported `name (kind)` from the
built `.d.ts` of each public entry point (`.`, `./ui`, `./data`, … 16 entries,
4251 exports), resolving re-export aliases to their real kind. The result is
committed at `packages/spec/api-surface.json`.

  pnpm --filter @objectstack/spec gen:api-surface     # regenerate + write
  pnpm --filter @objectstack/spec check:api-surface   # CI: fail on any drift

Wired into lint.yml's TypeScript Type Check job (after the build step). A
REMOVED export fails as breaking (bump major); an ADDED export still requires
regenerating the snapshot, so every change to the public surface is deliberate,
never silent. Complements the downstream-contract gate: that proves exercised
exports still ACCEPT real third-party metadata (depth); this proves the whole
export set still EXISTS (breadth).

Dev tooling only — the script and snapshot are not in the package `files`, so
nothing ships to consumers. Sort is code-unit (not locale) for cross-platform
determinism; verified the check passes clean and rejects a simulated removal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 21, 2026 5:27am

Request Review

@github-actions github-actions Bot added ci/cd dependencies Pull requests that update a dependency file tooling size/xl labels Jun 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

89 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/cloud-artifact-api.mdx (via packages/spec)
  • content/docs/concepts/cluster-semantics.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/implementation-status.mdx (via @objectstack/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/concepts/packages.mdx (via @objectstack/spec)
  • content/docs/concepts/setup-app.mdx (via @objectstack/spec)
  • content/docs/concepts/skills.mdx (via @objectstack/spec)
  • content/docs/concepts/webhook-delivery.mdx (via @objectstack/spec)
  • content/docs/getting-started/architecture.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/spec)
  • content/docs/getting-started/core-concepts.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/guides/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/guides/ai-capabilities.mdx (via @objectstack/spec)
  • content/docs/guides/airtable-dashboard-analysis.mdx (via @objectstack/spec)
  • content/docs/guides/analytics-datasets.mdx (via @objectstack/spec)
  • content/docs/guides/api-reference.mdx (via @objectstack/spec)
  • content/docs/guides/business-logic.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/error-catalog.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-type-gallery.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-validation-rules.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/protocol-diagram.mdx (via packages/spec)
  • content/docs/guides/cheatsheets/query-cheat-sheet.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/quick-reference.mdx (via @objectstack/spec)
  • content/docs/guides/client-sdk.mdx (via @objectstack/spec)
  • content/docs/guides/common-patterns.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/auth-service.mdx (via packages/spec)
  • content/docs/guides/contracts/cache-service.mdx (via packages/spec)
  • content/docs/guides/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/index.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/guides/contracts/storage-service.mdx (via packages/spec)
  • content/docs/guides/data-modeling.mdx (via @objectstack/spec)
  • content/docs/guides/deployment-vercel.mdx (via @objectstack/spec)
  • content/docs/guides/driver-configuration.mdx (via @objectstack/spec)
  • content/docs/guides/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/guides/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/guides/formula.mdx (via @objectstack/spec)
  • content/docs/guides/hook-bodies.mdx (via packages/spec)
  • content/docs/guides/kernel-services.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/dashboard.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/field.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/flow.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/index.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/object.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/validation.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/workflow.mdx (via @objectstack/spec)
  • content/docs/guides/packages.mdx (via @objectstack/spec)
  • content/docs/guides/plugin-development.mdx (via @objectstack/spec)
  • content/docs/guides/plugins.mdx (via @objectstack/spec)
  • content/docs/guides/project-scoping.mdx (via @objectstack/spec)
  • content/docs/guides/public-forms.mdx (via @objectstack/spec)
  • content/docs/guides/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/index.mdx (via packages/spec)
  • content/docs/guides/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/guides/security.mdx (via @objectstack/spec)
  • content/docs/guides/seed-data.mdx (via @objectstack/spec)
  • content/docs/guides/skills.mdx (via @objectstack/spec)
  • content/docs/guides/standards.mdx (via @objectstack/spec)
  • content/docs/guides/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via packages/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via packages/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@xuyushun441-sys
xuyushun441-sys merged commit 8545176 into main Jun 21, 2026
18 checks passed
@xuyushun441-sys
xuyushun441-sys deleted the spec/api-surface-gate branch June 21, 2026 06:18
xuyushun441-sys added a commit that referenced this pull request Jun 21, 2026
…ates (#2035) (#2098)

Documents the layered strategy built across #2088/#2089/#2092/#2093/#2095/#2097
in one authoritative place: why in-repo consumers can't witness backward compat
(they co-evolve with the spec), the six gates and each one's job, and — crucially
— the FREEZE CONTRACT: a change that requires editing the fixtures or removing a
snapshot entry is by definition breaking (bump major), never a mechanical
test-update. Also formalizes `objectstack validate` as the third party's
authoritative self-gate.

Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
xuyushun441-sys added a commit that referenced this pull request Jun 21, 2026
…owing (#2035) (#2100)

The api-surface snapshot (#2092) catches add/remove/rename but not NARROWING — a
`.default()` that flips an input field to required, or a `string` tightened to an
enum, keeps the same `name (kind)`. The downstream-contract fixtures catch
narrowing only for the fields they happen to set.

Adds api-surface-signatures.json: a stable hash of each defineX factory's
resolved signature (27 factories). The factory signature embeds the full
accepted authoring shape, so any narrowing of what a domain accepts flips its
hash. Scoped to the factories — the authoring contract — to stay low-noise:
the breadth file (4251 exports) is unchanged, and full per-export signatures
would churn on every internal type tweak.

Rides the existing check:api-surface CI step (one command checks both). Verified:
check clean, deterministic across regens (code-unit/structural, no locale),
breadth snapshot byte-identical to main, and a flipped hash is reported as a
breaking "signature changed" with exit 1.

Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd dependencies Pull requests that update a dependency file size/xl tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants