Skip to content

fix(examples): typecheck example apps clean + gate in CI#2023

Merged
os-zhuang merged 1 commit into
mainfrom
fix/example-apps-spec-subpath-imports
Jun 18, 2026
Merged

fix(examples): typecheck example apps clean + gate in CI#2023
os-zhuang merged 1 commit into
mainfrom
fix/example-apps-spec-subpath-imports

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Problem

The example apps (app-crm, app-showcase, app-todo) failed their own tsc --noEmit, and nothing in CI caught it — the typecheck job only ran tsc on @objectstack/spec.

The task looked like "~12 TS2305 import errors," but those were masking the real damage: app-crm imported types from the root @objectstack/spec, which intentionally exports no types (packages/spec/src/index.ts:8, enforced by ESLint no-restricted-imports). Those imports resolved to any, which silently suppressed all object-literal type checking in those files. Fixing the imports unmasked ~30 real type-conformance errors that had never been checked. tsup transpiles the apps without a full typecheck, so the build stayed green the whole time.

Fix

Import direction — Option B (subpath imports), the canonical one:

  • Repoint all app-crm type imports to subpaths (@objectstack/spec/data, /ui, /security, /integration, ...).

Output-vs-input types (the bulk of the unmasked errors):

  • Examples annotated literals with the Zod output type (z.infer), where every .default() field becomes required and CEL/Expression fields reject bare strings.
  • Follow the spec's existing XInput convention (FieldInput, ActionInput, ReportInput, PortalInput) — add the 9 missing aliases (DatasourceInput, ConnectorInput, SharingRuleInput, JobInput, WebhookInput, EmailTemplateDefinitionInput, RoleInput, PermissionSetInput, ObjectExtensionInput) and type the examples with them. Keeps templates clean instead of padding them with default values.

Genuine content bugs (also previously masked):

  • Removed unsupported description on agent / Action / PermissionSet (schemas don't define it; label kept).
  • parentRole -> parent on roles.
  • app-todo: dropped unmodeled Field.color({colorFormat, presetColors}) options; guarded input.subject.includes on an unknown value; added the missing vitest devDep its src/**/*.test.ts needs.

CI gate (.github/workflows/lint.yml):

  • Build workspace packages (examples need built dist for cross-package type resolution), then pnpm --filter './examples/*' run typecheck.
  • Uses the path filter ./examples/*, not @objectstack/example-*app-todo is named @example/app-todo, so the scope glob silently skips it.

Verification

@objectstack/spec       tsc --noEmit: clean
examples/app-crm        typecheck: Done
examples/app-showcase   typecheck: Done
examples/app-todo       typecheck: Done

Note

Follow-up (not in this PR): @example/app-todo should probably be renamed @objectstack/example-todo for scope consistency. The path-based CI filter sidesteps the need for now.

🤖 Generated with Claude Code

The example apps failed their own `tsc --noEmit`. Root cause: app-crm
imported types from the root `@objectstack/spec`, which intentionally
exports no types — those imports resolved to `any` and silently
suppressed all object-literal type checking, masking ~30 real errors.
tsup builds the apps without a full typecheck, so nothing caught it.

- Repoint app-crm type imports to canonical subpaths
  (`@objectstack/spec/data`, `/ui`, `/security`, ...).
- Type authored literals with input types: add the missing `*Input`
  aliases to @objectstack/spec (following the existing FieldInput/
  ActionInput/ReportInput/PortalInput convention) so `.default()`
  fields stay optional and CEL fields accept string shorthands.
- Fix genuine content drift: drop unsupported `description` on
  agent/Action/PermissionSet; `parentRole` -> `parent` on roles.
- app-todo: drop unmodeled `Field.color` options, guard
  `input.subject.includes` on an `unknown` value, add the `vitest`
  devDep its `src/` test needs.
- CI (lint.yml): build workspace packages, then typecheck every
  example via the path filter `./examples/*` (the `@objectstack/example-*`
  scope glob silently skips `@example/app-todo`).

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

vercel Bot commented Jun 18, 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 18, 2026 6:20am

Request Review

@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.

@github-actions github-actions Bot added documentation Improvements or additions to documentation ci/cd dependencies Pull requests that update a dependency file protocol:data protocol:system tooling labels Jun 18, 2026
@os-zhuang
os-zhuang merged commit 641675d into main Jun 18, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the fix/example-apps-spec-subpath-imports branch June 18, 2026 06:26
os-zhuang added a commit that referenced this pull request Jun 18, 2026
#2026)

Scope consistency with the other example apps (@objectstack/example-crm,
@objectstack/example-showcase). The inconsistent scope meant a
`--filter @objectstack/example-*` glob silently skipped app-todo — the
follow-up noted in #2023.

Updates the package name, the root `dev:todo` script, current docs
(root + app-todo READMEs) and the `// Run via:` comments in the test
files. CHANGELOGs are left untouched (historical record).

No lockfile churn — pnpm keys importers by path, not name. Package is
private (not published), so no changeset.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
os-zhuang added a commit that referenced this pull request Jun 18, 2026
…2029)

The repo had an ESLint flat config whose only rule — no-restricted-imports
banning `@objectstack/spec` root namespace imports (the ~1.2GB RSS
regression vector) — was never enforced: eslint wasn't even a devDep, no
`lint` script existed, and the `lint.yml` workflow only ran tsc. The
config's own comment said "To enable: pnpm add -DW eslint". So the guard
that should have caught the root-import drift fixed in #2023 was dormant.

- Add `eslint` + `@typescript-eslint/parser` devDeps; wire the parser into
  the flat config so .ts files parse.
- Add root `lint` script (`eslint . --no-inline-config`). The flag ignores
  orphaned `eslint-disable` directives left over from a richer rule set
  this minimal config no longer registers; the sole active rule should
  never be opted out locally anyway.
- Add a fast `lint` job to lint.yml (syntactic only, no build needed).

Complements the example-app typecheck gate from #2023: typecheck catches
concrete-type root imports, ESLint catches the namespace-name imports and
gives a faster signal.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
xuyushun441-sys added a commit that referenced this pull request Jun 21, 2026
…ritable domains (#2035) (#2088)

* feat(spec): defineX factories + XInput aliases for the 16 remaining writable domains (#2035)

Adds one type-safe authoring entry per writable domain — defineDatasource,
defineConnector, definePolicy, defineSharingRule, defineRole, definePermissionSet,
defineEmailTemplateDefinition, defineReport, defineWebhook, defineObjectExtension,
defineCube, defineMapping, defineTheme, defineTranslationBundle, definePage,
defineAction — mirroring the 19 existing factories (XSchema.parse(z.input)).

Each factory is a *value* export: a broken import hard-errors instead of silently
degrading to `any` (the #2023 failure mode), and authoring errors surface at
.parse() time with field-level messages. Also backfills the six missing input
aliases: PolicyInput, CubeInput, MappingInput, ThemeInput, TranslationBundleInput,
PageInput. Purely additive — no existing exports change.

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

* refactor(examples): author metadata via defineX factories (#2035)

Migrates every example authoring file across crm/showcase/todo from bare
output-type literals (`: Page`, `: UI.ActionInput`, …) to the corresponding
defineX factory. The factory accepts input-shape config and validates each
definition at module load, so a malformed metadata object now fails loudly at
authoring time instead of silently passing as `any` (#2023).

Covers 36 files / 16 domains — including files the *.{domain}.ts filename scan
missed (reports/index.ts, actions/index.ts, security/sales-roles.ts, …), which
the new lint guard surfaced.

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

* feat(lint): guard examples against bare metadata literals (#2035)

Adds an AST-only no-restricted-syntax rule that flags exported consts in
examples/** annotated with a spec domain type (simple `Page` or qualified
`UI.Page`) instead of being wrapped in the defineX factory. Turns the authoring
convention into an invariant so the "pick by history" pattern cannot creep back
into the reference corpus AI learns from — it already caught 15 unmigrated
authoring files in this change. No type info required.

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

---------

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
…2035) (#2089)

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: 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
…ft (#2035) (#2092)

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: 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 documentation Improvements or additions to documentation protocol:data protocol:system size/m tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant