test(spec): downstream-consumer contract — backward-compat gate for third parties (#2035)#2089
Merged
Merged
Conversation
…2035) Adds `@objectstack/downstream-contract` — a frozen, representative third-party consumer of `@objectstack/spec`, and the CI gate that runs it. Why: every other spec consumer the framework tests (example apps, `@objectstack/dogfood`) lives in this repo and co-evolves with the spec in the same commit, so none can catch a change that breaks a *real* third party (e.g. hotcrm) pinned to a published release. This fixture is authored the way an external project does — builder + `defineX` factories + bare metadata literals (the pre-#2035 pattern) — and is FROZEN: a spec change that requires editing it to stay green is, by definition, breaking. Two signals, both wired into existing CI jobs (no new workflow): • typecheck — fixtures are typed with real spec types (`ActionInput`, `ReportInput`, `PageInput`, …); a removed/narrowed export fails (the #2023 class). Added to lint.yml's TypeScript Type Check job. • test — each bare-literal fixture is run through its schema's `.parse()`, and everything is assembled via `defineStack` (schema + cross-reference validation, the metadata core of `objectstack validate`). Rides `turbo run test` (Test Core). Verified locally: typecheck + test green; confirmed the schema parse has teeth (rejects a broken action `type`). README documents the freeze contract. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckNo hand-written docs reference the 1 changed package(s). ✅ |
This was referenced Jun 21, 2026
xuyushun441-sys
added a commit
that referenced
this pull request
Jun 21, 2026
…2035) (#2093) The last layer of the third-party validation strategy from #2035: a live ceiling above the deterministic in-repo floor (@objectstack/downstream-contract, #2089). `scripts/downstream-smoke.sh` clones objectstack-ai/hotcrm at a pinned tag (v1.2.0), installs it against the PUBLISHED @objectstack/* packages, overlays the freshly-built — unreleased — @objectstack/spec dist, and runs hotcrm's own `typecheck` + `objectstack validate`. If the about-to-publish spec breaks a real, independently-authored third-party consumer, the release is blocked. Wired into release.yml between the build and the changesets publish step, so it runs only in the release pipeline (never reddens a feature PR). Mirrors the existing console-SPA step that already clones an external repo at a pinned ref. Verified end-to-end locally: clone hotcrm@v1.2.0 → install → overlay current spec → typecheck + validate both pass (15 objects / 15 pages / 10 reports / 11 actions / 17 flows). Override the pinned ref with HOTCRM_REF. Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jun 21, 2026
xuyushun441-sys
added a commit
that referenced
this pull request
Jun 21, 2026
) (#2095) The depth gate (#2089) only exercised object/view/action/report/page. Adds a frozen bare-literal fixture for the remaining domains — datasource, connector, policy, sharing rule, role, permission set, email template, webhook, object extension, cube, mapping, theme, translation bundle — typed with the spec's own input aliases and parsed against each domain's schema. Now a narrowed/removed schema property on ANY writable domain breaks the contract (authoring it surfaced two already: EmailTemplate requires `bodyHtml`, Cube requires `dimensions`). 15 cases, typecheck + test green. 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
…2097) The #2088 guard only covered examples/**. Broadens it to the platform's own apps (account/setup/studio) so the "author metadata via defineX, never a bare `: DomainType` literal" convention holds across every authoring surface, not just the example corpus. Explicitly excludes packages/downstream-contract, whose bare literals are an intentional frozen backward-compat fixture (#2089). No migrations — apps author no bare-literal metadata today; this is future- proofing. Verified the guard fires on a probe under packages/apps and that `pnpm lint` is green. 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
…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>
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.
Follow-up to #2035 / #2088. Builds recommendation #1 from that discussion: the missing gate that catches a spec change breaking a lagging third-party consumer before release.
The gap this closes
Every spec consumer the framework currently tests — the example apps,
@objectstack/dogfood— lives in this monorepo and co-evolves with the spec in the same commit. When a spec change would break them, the same PR just fixes them. So none of them can catch a change that breaks a real third party (e.g. hotcrm) that is pinned to a published release and authors metadata independently.grep hotcrm .github/→ 0 hits today.What this adds
@objectstack/downstream-contract— a frozen fixture authored the way an external consumer does: theObjectSchema.createbuilder, thedefineXfactories, and bare metadata literals (: ActionInput/: ReportInput/: PageInput— the pre-#2035 pattern real third parties used). It is governed by a freeze contract (see the package README):Two signals, both riding existing CI jobs (no new workflow):
typechecklint.yml→ TypeScript Type Checktestturbo run test→ Test CoreThe test runs each bare-literal fixture through its schema's
.parse()and assembles all metadata viadefineStack(schema + cross-reference validation — the metadata core ofobjectstack validate).Grounding (done for real, not theory)
Before writing this I overlaid the merged spec build into a local checkout of hotcrm (real external consumer on published 9.11.0) and ran its own gates:
tsc --noEmit→ 0 errors,objectstack validate→ ✓ passed (15 objects / 15 pages / 10 reports / 11 actions / 17 flows). hotcrm also proved the original thesis — it usesdefineView()but authors pages/reports/actions/flows as bare literals (incl.: Action, the output-type footgun), exactly because the factories were missing. This package is the deterministic, in-CI floor under that manual check.Verification (local)
pnpm --filter @objectstack/downstream-contract typecheck→ exit 0pnpm --filter @objectstack/downstream-contract test→ 2 passedturbo run test --filter=@objectstack/downstream-contract→ picked up ✓ActionSchema.parserejects a broken actiontype(not a no-op)Follow-ups (not in this PR)
specpublic-API surface snapshot (api-extractor) for an even tighter type-break signal.validate && typecheck && buildagainst the unreleased spec.🤖 Generated with Claude Code