Skip to content

chore: rename residual framework→objectstack dir/pin references #9436

chore: rename residual framework→objectstack dir/pin references

chore: rename residual framework→objectstack dir/pin references #9436

Workflow file for this run

name: Lint & Type Check
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
lint:
name: ESLint
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "20"
- name: Enable Corepack
run: corepack enable
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- name: Setup pnpm cache
uses: actions/cache@v6
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-v3-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-v3-
- name: Install dependencies
run: pnpm install --frozen-lockfile
# Enforces the no-restricted-imports guard against @objectstack/spec root
# namespace imports (the dormant rule was never run in CI). Syntactic
# only, so no build step needed.
- name: ESLint
run: pnpm lint
# Raw NUL guard (#3127): one literal U+0000 byte makes grep/ripgrep treat
# the whole file as binary and silently return ZERO matches — the file drops
# out of code search and out of every grep-based lint, with no error saying
# so. Nothing else catches it: git sniffs only the first 8000 bytes to decide
# binary-ness, and protocol.ts carried its NUL at offset 147230, so it kept
# diffing as ordinary text through review. That blind spot let six files
# accumulate the same defect. Authors must write the unicode escape instead.
- name: Raw NUL byte guard
run: pnpm check:nul-bytes
# Docs/skills authoring guard (#2035 / ADR-0059): TS code blocks in
# Markdown/MDX are not type-checked or ESLinted, so skills/ and
# content/docs/ can drift back to teaching the bare `: Page = {}` literal
# while the examples (which ARE linted) stay clean. This fails on any bare
# metadata literal for the 16 factory domains in a doc code block.
- name: Doc/skill authoring guard
run: pnpm check:doc-authoring
# ADR-0090 D3 vocabulary ratchet: "role" is reserved-forbidden in docs
# and skills. Existing occurrences are frozen in the baseline (better-auth
# boundary, ARIA samples, educational mentions); NEW occurrences fail.
# Improvements ratchet the baseline down via --update.
- name: Reserved-word ("role") docs ratchet
run: pnpm check:role-word
# #3280/#3290 org-identifier guard: `organizationId` is the blessed
# developer-facing name for the caller's active org in hook/action bodies;
# the `session.tenantId` alias was REMOVED in v11 (#3290). Keeps our own
# reference code (examples/, apps/, AND packages/) — which authors and AIs
# copy from — off the removed name. Hard-fail (surfaces carry zero
# occurrences today); tests, comments, skills/ and docs/ are excluded, and
# driver-layer `execCtx.tenantId` is never matched.
- name: Org-identifier authoring guard
run: pnpm check:org-identifier
# Authorization resolution must stay single-sourced (resolveAuthzContext,
# @objectstack/core). Guards against a duplicate resolver copy drifting on a
# security path (the REST-vs-dispatcher sys_user_role drift) and against an
# entry point silently dropping the delegation.
- name: Single authz resolver guard
run: pnpm check:authz-resolver
# Release-notes drift guard: the platform is one version-locked train, so
# every released @objectstack/spec major must have a curated, navigable
# release page at content/docs/releases/v<major>.mdx. Catches the gap that
# let v10–v14 ship with no page while spec was already at 14.x.
- name: Release-notes drift guard
run: pnpm check:release-notes
typecheck:
name: TypeScript Type Check
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
- name: Enable Corepack
run: corepack enable
- name: Verify pnpm version
run: pnpm --version
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- name: Setup pnpm cache
uses: actions/cache@v6
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-v3-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-v3-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Type check (@objectstack/spec)
run: pnpm --filter @objectstack/spec exec tsc --noEmit
# Generated-docs gate: content/docs/references/** is generated from the spec
# by `gen:schema && gen:docs` and committed. Nothing regenerated it in CI, so
# it drifted silently — #3076 added RowCrudActionOverride to the spec and the
# public reference docs never learned the type existed. Regenerates and fails
# on any difference.
#
# Deliberately lives in this job, not in ci.yml's "Build Docs": that job is
# gated on a `docs` paths-filter that does not include packages/spec/**, so it
# skips exactly the spec-only PRs that cause this drift (#3076 was one). This
# job has no paths filter and is a required status check, so the gate cannot go
# dormant. It reads src/ + json-schema/ via tsx and needs no build, so it runs
# before the workspace build and fails in ~2s.
- name: Check generated reference docs are in sync with the spec
run: pnpm --filter @objectstack/spec check:docs
# Same class, same reasoning, different surface: skills/*/references/_index.md
# and the objectstack-ui react-blocks contract are generated from
# packages/spec/src and committed, and nothing regenerated them either. These
# ship to third parties via `npx skills add objectstack-ai/objectstack`, so the
# drift is served straight to consumers' agents — 6 of 113 schema pointers named
# files the spec had already deleted or renamed.
#
# Not in ci.yml's `check-generated` job for the reason above: its `generated`
# filter lists specific spec paths (migrations/, conversions/, protocol-version)
# but no schema dirs, so a PR touching src/data/** or src/ui/** — exactly what
# drives these two artifacts — never triggers it. It is not required, either.
#
# Both read packages/spec/src via tsx and need no build (verified with every
# workspace dist/ removed), so they run before the workspace build. check:skill-refs
# additionally fails on a SKILL_MAP entry naming a file the spec no longer has:
# that silent skip is what let the map keep pointing at data/dataset.zod.ts for a
# year after #1620 renamed it to data/seed.zod.ts.
- name: Check generated skill references are in sync with the spec
run: pnpm --filter @objectstack/spec check:skill-refs
- name: Check the react-blocks contract is in sync with the spec
run: pnpm --filter @objectstack/spec check:react-blocks
# Example apps are AI-authoring reference templates; a red typecheck is a
# bad signal to copy from. tsup transpiles them without a full typecheck,
# so build alone will not catch type drift — typecheck them explicitly.
# They import from built workspace packages, so the packages must be built
# first for cross-package type resolution to succeed. The examples'
# dependency closure is requested EXPLICITLY (`./examples/*^...` = deps
# of the examples, not the examples themselves): the bare `./packages/*`
# glob only matches direct children, and the connector packages the
# showcase imports were previously built only by accident — through
# dogfood's dependency chain, which broke when dogfood moved to
# packages/qa/ (#3037).
- name: Build workspace packages
run: pnpm exec turbo run build --filter='./packages/*' --filter='./examples/*^...'
- name: Type check example apps
run: pnpm --filter './examples/*' run typecheck
# Backward-compatibility gate: a frozen third-party-style consumer
# (#2035). Unlike the examples it must NOT be migrated to accommodate a
# spec change — a red typecheck here means the spec dropped/narrowed an
# export a published-spec third party already uses. See the package README.
- name: Type check downstream consumer contract
run: pnpm --filter @objectstack/downstream-contract run typecheck
# Public API-surface gate (#2035): the spec package IS the third-party API.
# A removed/renamed export silently breaks every consumer pinned to a
# published release. This diffs the built export surface against the
# committed snapshot; intentional changes regenerate it via
# `pnpm --filter @objectstack/spec gen:api-surface`. Runs after the build
# step above (reads the built dist).
- name: Check @objectstack/spec public API surface
run: pnpm --filter @objectstack/spec run check:api-surface
# Anti-drift for the skill EXAMPLES, not just the skill reference indexes
# (#3094). The TypeScript in skills/ is the first thing an AI copies when
# authoring metadata, yet nothing type-checked it — so it rotted silently
# (`ObjectSchema`/`Data`/`Field` imported from the wrong entry point, a
# `defineStack` key that no longer exists). Each block tagged with an
# `<!-- os:check -->` comment is extracted and run through `tsc --noEmit`
# against the built `@objectstack/spec` declarations — the exact surface a
# consumer's import resolves to — so a renamed export or tightened union
# fails here instead of in a third party's editor. Reads the built dist,
# so it runs after the build step alongside the other consumer gates.
- name: Check skills TypeScript examples compile
run: pnpm --filter @objectstack/spec run check:skill-examples