From 85c0e9e7f1d7a8affeb4a9a9e25a591ff18baa41 Mon Sep 17 00:00:00 2001 From: Caio Pizzol Date: Sat, 23 May 2026 13:45:58 -0300 Subject: [PATCH 1/3] docs(scripts): catalog public-interface validation + standardize command names Documentation-first cleanup of the type-checking system. No behavior change. Existing scripts keep working under their existing names. Adds: - packages/superdoc/scripts/README.md: one place to learn the system. Covers the TL;DR command, vocabulary (SuperDoc package vs Document API), command catalog, per-script gates, consumer-typecheck infrastructure, document-api scripts, dataflow diagram, and the CI-vs-local split. - Six aliased commands in root package.json, following the convention check:* = non-mutating, generate:* = mutates, report:* = read-only: check:types -> pnpm run type-check check:public:superdoc -> pnpm run check:public-contract check:public:docapi -> pnpm run docapi:check check:public -> check:public:superdoc && check:public:docapi generate:docapi -> pnpm run docapi:sync report:public:superdoc -> pnpm run report:public-contract - Rewritten Commands section in AGENTS.md (CLAUDE.md symlinks to it) pointing at pnpm check:public as the canonical pre-merge command and explaining the naming convention. The legacy names stay verbatim per the agreed migration plan: add new names first, switch CI in a later PR, mark old names as legacy after that. No new behavior, no removed behavior, no new gates. Verified: - pnpm run check:types passes (alias of type-check) - pnpm run report:public:superdoc prints the tier report - pnpm run check:public:docapi fails with the same stale-generated- file error as docapi:check (expected, same passthrough) --- AGENTS.md | 14 ++- package.json | 6 + packages/superdoc/scripts/README.md | 189 ++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+), 3 deletions(-) create mode 100644 packages/superdoc/scripts/README.md diff --git a/AGENTS.md b/AGENTS.md index 32de3f1ba7..b9eada3b3b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -71,9 +71,17 @@ Do not hand-edit `COMMAND_CATALOG`, `OPERATION_MEMBER_PATH_MAP`, `OPERATION_REFE - `pnpm build` - build all packages - `pnpm test` - unit tests - `pnpm dev` - dev server from `examples/` -- `pnpm run generate:all` - regenerate schemas, SDK clients, tool catalogs, reference docs -- `pnpm check:public-contract` - validate the published public type contract: wraps build + consumer typecheck matrix + strict supported-root audit. ~3 min. Scoped to the public type surface, not a replacement for `pnpm test` or `pnpm build`. Also the single command CI runs (with `--skip-build` after its own Build step). SD-3256 / SD-673. -- `pnpm report:public-contract` - print the public-contract tier metadata (supported / legacy / legacy-raw / asset / deprecated). Read-only. Source of truth: `packages/superdoc/scripts/type-surface.config.cjs` (`publicContract` export). SD-3256. +- `pnpm check:types` - raw TS compile across all referenced projects (alias of `pnpm run type-check`). Does NOT run the public-interface chain. +- `pnpm check:public` - **canonical pre-merge command for typed public surfaces.** Validates both `superdoc` (vite build + postbuild chain + consumer typecheck matrix + deep-type audit) and Document API (contract parity + output staleness + examples + overview). ~5 min. Non-mutating. Combines `check:public:superdoc` + `check:public:docapi`. +- `pnpm check:public:superdoc` - SuperDoc public package surface only (alias of `check:public-contract`). +- `pnpm check:public:docapi` - Document API public surface only (alias of `docapi:check`). Requires generated artifacts to be current; if it fails on staleness, run `pnpm generate:docapi`. +- `pnpm generate:docapi` - regenerate Document API outputs after editing the contract (alias of `docapi:sync`). Mutates `packages/document-api/generated/**`; commit the changes. +- `pnpm generate:all` - regenerate schemas, SDK clients, tool catalogs, reference docs. +- `pnpm report:public:superdoc` - print public-contract tier metadata (supported / legacy / asset / deprecated). Read-only, not a gate. Source of truth: `packages/superdoc/scripts/type-surface.config.cjs`. + +Full system reference (script catalog, dataflow, CI vs local): `packages/superdoc/scripts/README.md`. + +Naming convention: `check:*` = non-mutating, safe in CI. `generate:*` = mutates files. `report:*` = read-only information, not a gate. Older command names (`check:public-contract`, `docapi:sync`, `report:public-contract`, etc.) remain as aliases. ## Testing diff --git a/package.json b/package.json index a806d24079..c875705e03 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,12 @@ "docapi:sync": "pnpm exec tsx packages/document-api/scripts/generate-contract-outputs.ts", "docapi:check": "pnpm exec tsx packages/document-api/scripts/check-contract-parity.ts && pnpm exec tsx packages/document-api/scripts/check-contract-outputs.ts && pnpm exec tsx packages/document-api/scripts/check-examples.ts && pnpm exec tsx packages/document-api/scripts/check-overview-alignment.ts", "docapi:sync:check": "pnpm run docapi:sync && pnpm run docapi:check", + "check:types": "pnpm run type-check", + "check:public:superdoc": "pnpm run check:public-contract", + "check:public:docapi": "pnpm run docapi:check", + "check:public": "pnpm run check:public:superdoc && pnpm run check:public:docapi", + "generate:docapi": "pnpm run docapi:sync", + "report:public:superdoc": "pnpm run report:public-contract", "test:cli": "pnpm --prefix apps/cli run test", "cli:prepare": "pnpm run test:cli && pnpm --prefix apps/cli run build:prepublish", "cli:publish:raw": "pnpm run cli:prepare && pnpm --prefix apps/cli run publish:platforms", diff --git a/packages/superdoc/scripts/README.md b/packages/superdoc/scripts/README.md new file mode 100644 index 0000000000..322d392bcf --- /dev/null +++ b/packages/superdoc/scripts/README.md @@ -0,0 +1,189 @@ +# SuperDoc public-interface validation scripts + +This directory holds the scripts that validate the published SuperDoc package's +public TypeScript surface. The repository also has a Document API public +interface under `packages/document-api/scripts/`; both are summarized here so +contributors have one place to learn the system. + +If you only have time for one sentence: **run `pnpm check:public` before +opening or merging anything that touches public types.** + +--- + +## TL;DR — what command to run when + +| Question | Command | Speed | Mutates files? | +|---|---|---|---| +| Am I safe to ship a PR? | `pnpm check:public` | ~5 min | no | +| TypeScript compiles cleanly? | `pnpm check:types` | seconds | no | +| Only SuperDoc public surface changed? | `pnpm check:public:superdoc` | ~3 min | no | +| Only Document API contract changed? | `pnpm check:public:docapi` | seconds | no | +| Regenerate Document API artifacts after editing the contract? | `pnpm generate:docapi` | seconds | **yes** | +| Quickly see public-contract tier metadata? | `pnpm report:public:superdoc` | seconds | no | + +`check:*` commands are non-mutating and safe to run anywhere. `generate:*` +commands write to the worktree (commit the changes). `report:*` commands are +read-only and not CI gates. + +--- + +## Vocabulary + +The repo's typed surface is split into two "public interfaces": + +- **SuperDoc** — the `superdoc` npm package. Public types and runtime exports + flow through `packages/superdoc/src/public/index.ts` and the subpath + facades (`./types`, `./ui`, `./ui/react`, `./headless-toolbar`, etc.). +- **Document API** — `editor.doc.*` programmatic API typed in + `packages/document-api/src/`. Built as TypeScript-only; the contract lives + in `operation-definitions.ts` and several artifacts are generated from it. + +Both are validated by the same root-level catch-all (`pnpm check:public`) +but have separate script chains because the validation needs differ. + +--- + +## Command catalog (root `package.json`) + +### Public-interface validation + +| Command | Runs | What it gates | +|---|---|---| +| `check:public` | `check:public:superdoc` + `check:public:docapi` | Both public interfaces. The umbrella to run before merging. | +| `check:public:superdoc` | `check:public-contract` (legacy alias) | SuperDoc package: vite build + postbuild chain, consumer typecheck matrix, deep-type audit. | +| `check:public:docapi` | `docapi:check` (legacy alias) | Document API: contract parity, generated outputs are not stale, examples compile, overview alignment. **Requires generated artifacts to be up-to-date** — if it fails on staleness, run `generate:docapi` to refresh. | +| `report:public:superdoc` | `report:public-contract` (legacy alias) | Read-only tier metadata (supported / legacy / asset / deprecated). Not a gate. | + +### TypeScript compiler + +| Command | Runs | What it gates | +|---|---|---| +| `check:types` | `type-check` (legacy alias) | `tsc -b tsconfig.references.json` — raw TS compile across all referenced projects. Does NOT run the SuperDoc public-contract chain. | +| `type-check:force` | `tsc -b --force` | Same as above but ignores incremental cache. | + +### Generation + +| Command | Runs | Mutates? | +|---|---|---| +| `generate:docapi` | `docapi:sync` (legacy alias) | yes — writes `packages/document-api/generated/**` | +| `generate:all` | schemas, SDK clients, tool catalogs, reference docs | yes — multi-target generator | + +### Legacy aliases + +These names predate the standardized vocabulary and stay as `pnpm` +aliases for back-compat. New CI workflows and docs should use the +canonical names above. + +| Legacy | Canonical | +|---|---| +| `type-check` | `check:types` | +| `check:public-contract` | `check:public:superdoc` | +| `docapi:check` | `check:public:docapi` | +| `docapi:sync` | `generate:docapi` | +| `docapi:sync:check` | `generate:docapi && check:public:docapi` | +| `report:public-contract` | `report:public:superdoc` | + +--- + +## SuperDoc scripts in this directory + +These run as part of `check:public:superdoc` (most via the vite build's +postbuild chain). Each is described by what it gates and what would fail if +it stopped running. + +| Script | Stage | Gates | If removed | +|---|---|---|---| +| `type-surface.config.cjs` | data | Canonical taxonomy: relocations, base includes, shared-common targets, allowlists. Source of truth for 5+ other scripts. | Every consumer becomes independent; drift between vite / tsconfig / audit is invisible. | +| `ensure-types.cjs` | postbuild | Rewrites workspace specifiers in emitted `.d.ts` so consumers can resolve them; copies hand-written `.d.ts` files into dist. | Published declarations contain unresolvable `@superdoc/*` imports. | +| `check-tsconfig-type-surface.cjs` | postbuild | Asserts `tsconfig.json#include` equals the union of base + relocation paths in `type-surface.config.cjs`. | tsconfig and vite drift silently; IDE checks diverge from CI. | +| `audit-bundle.cjs` | postbuild | prosemirror-view single-instance check + bundle size budgets. | Duplicate PM instances break collaboration; no size discipline. | +| `audit-declarations.cjs` | postbuild | Rule 1: bare `@superdoc/*` leaks. Rule 2: pnpm-internal paths. Rule 3: `_internal-shims.d.ts` regression. | Private specifiers ship to consumers; consumers hit unresolvable imports. | +| `check-export-coverage.cjs` | postbuild | Every `package.json#exports` subpath carries a `types` field or is on the runtime-only allowlist. | `TS7016` returns for consumers on runtime-only subpaths. | +| `verify-public-facade-emit.cjs` | postbuild | Per-facade expected symbol set + ESM/CJS parity + legacy command-signature compat. Has a hand-maintained `expectedNames` allowlist per facade (consolidation tracked separately). | Symbol set drift ships silently; CJS shims diverge from ESM. | +| `report-declaration-reachability.cjs` | postbuild | Instrumentation (not a gate): per-bucket reachability ratio of emitted declarations. | Loses visibility into unreachable emit (the SD-2952 trim target). | +| `check-jsdoc.cjs` | CI step | Per-file checkJs gate for files in a hand-curated `CHECKED_FILES` allowlist. Currently 6 files. **Note**: `SuperDoc.js` now has `// @ts-check` but is gated by `check:types`, not this script. The 6-file list is a historical ratchet from before the broader enablement; consolidating with `check:types` is tracked separately. | A targeted regression on one of the 6 ratcheted files ships silently. | + +--- + +## Consumer-typecheck infrastructure (`tests/consumer-typecheck/`) + +These run against the **packed and installed** tarball, so they validate +what an actual consumer would see — not the workspace source. + +| Script | Gates | Notes | +|---|---|---| +| `typecheck-matrix.mjs` | 83 scenarios across module resolution (bundler/node16/nodenext) × strict × skipLibCheck × import path. | Packs the superdoc tarball into `node_modules/` once; later scripts reuse the install. | +| `deep-type-audit.mjs --strict-supported-root` | Walks every type reachable from `superdoc`'s public exports; fails on `any` leaks at any depth. | Compares against a committed allowlist; new findings fail, stale findings fail. | +| `snapshot.mjs --all --check` | No-growth snapshots: super-editor package exports, legacy subpath exports, root facade symbol inventory. | `--write` regenerates snapshots. | +| `check-all-public-types-fixture.mjs` | Asserts every type-only root export has an `AssertNotAny` line in `src/all-public-types.ts`. | Derives the expected set from `superdoc-root-classification.json`. | +| `package-shape-gate.mjs` | External package-shape linters (publint + attw) against the packed tarball. | Catches condition ordering, masquerading exports, missing field declarations. | +| `check-root-classification-closure.mjs` | Asserts no `supported-root` or `legacy-root` export references an `internal-candidate` symbol in its public declared type. | Closure rule from SD-3212. | + +`check:public:superdoc` runs `typecheck-matrix` and `deep-type-audit` +directly. `package-shape-gate`, `snapshot --all --check`, and +`check-root-classification-closure` currently run as separate CI steps — +folding them into `check:public:superdoc` is tracked as a follow-up so +release workflows can call one command without losing coverage. + +--- + +## Document API scripts (`packages/document-api/scripts/`) + +The Document API is contract-first: `operation-definitions.ts` is the +canonical source, and several artifacts are generated from it. + +| Script | Phase | What it does | +|---|---|---| +| `generate-contract-outputs.ts` | generate | Writes `generated/schemas/**` + `generated/agent/**` from the contract. Called by `generate:docapi`. | +| `check-contract-parity.ts` | check | Asserts derived maps (`operation-registry`, `invoke`, etc.) project from `operation-definitions` correctly. | +| `check-contract-outputs.ts` | check | Asserts the committed `generated/**` files match what regeneration would produce. Fails if stale. | +| `check-examples.ts` | check | Asserts contract examples compile. | +| `check-overview-alignment.ts` | check | Asserts the documentation overview reflects the current operation set. | + +The four `check-*` scripts run together via `check:public:docapi`. +Currently they require `generate:docapi` to have run first (the +stale-file check trips otherwise). Making the check self-contained +(in-memory generate and compare) is tracked as a follow-up. + +--- + +## Dataflow + +``` +type-surface.config.cjs (single source of truth) + │ + ├─ vite.config.js ──> emits dist/**/*.d.ts + ├─ tsconfig.json#include ──> typecheck source tree + ├─ ensure-types.cjs ──> rewrites + copies in dist + ├─ check-tsconfig-type-surface ──> tsconfig parity gate + └─ audit-declarations.cjs ──> reads relocationGuardPackages + +src/public/index.ts (declarative root facade) + │ + ├─ vite-plugin-dts ──> emits public/index.d.ts + ├─ verify-public-facade-emit ──> expected names allowlist + ├─ snapshot.mjs (root family) ──> drift snapshot + └─ check-all-public-types-fixture ──> consumer fixture coverage + +packages/document-api/src/contract/operation-definitions.ts + │ + ├─ generate-contract-outputs ──> writes generated/** + ├─ check-contract-parity ──> registry/invoke drift gate + └─ check-contract-outputs ──> committed-vs-fresh gate +``` + +--- + +## CI vs local + +- **`ci-superdoc.yml`** runs `pnpm check:public-contract --skip-build` after + its own Build step. This is the single command for the SuperDoc public + surface in CI. +- **`release-superdoc.yml`** currently runs the consumer-typecheck matrix, + deep-type audit, package-shape gate, snapshot check, and classification + closure as separate steps. Migrating to `check:public:superdoc` once that + command covers all the gates is tracked separately. + +Local pre-commit: just run `pnpm check:public`. If anything fails, the +failure message tells you which script and (for `check:public:docapi`) +which command to run to regenerate stale artifacts. From 8037fc072219cacbadf76f01b5ee6408c7ee87d3 Mon Sep 17 00:00:00 2001 From: Caio Pizzol Date: Sat, 23 May 2026 13:53:21 -0300 Subject: [PATCH 2/3] docs(scripts): tighten preflight wording + correct gitignore claim Review-feedback corrections to the prior docs commit: - "Am I safe to ship a PR?" -> "Are public interfaces safe?" in the scripts README TL;DR. The original framing implied check:public validates full product correctness; it only validates the public type/interface surface. Tests and build are separate concerns. - Add a sentence under the TL;DR clarifying check:public is "the public type/interface preflight" and is not a replacement for test or build. - Fix the generate:docapi wording in both the scripts README and AGENTS.md. Previous text said the command "writes packages/document-api/generated/**; commit the changes." Verified that path is gitignored via the root .gitignore (line "packages/document-api/generated/"), so there is nothing to commit. New wording: "Writes to packages/document-api/generated/ (gitignored). Run before check:public:docapi if it fails on missing files." - Tighten the generate:all wording in the scripts README to distinguish gitignored vs tracked generator targets (e.g. apps/docs/document-api/reference/ stays committed per the .gitignore comment). No alias or behavior change. --- AGENTS.md | 2 +- packages/superdoc/scripts/README.md | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index b9eada3b3b..9bd2dc03bb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -75,7 +75,7 @@ Do not hand-edit `COMMAND_CATALOG`, `OPERATION_MEMBER_PATH_MAP`, `OPERATION_REFE - `pnpm check:public` - **canonical pre-merge command for typed public surfaces.** Validates both `superdoc` (vite build + postbuild chain + consumer typecheck matrix + deep-type audit) and Document API (contract parity + output staleness + examples + overview). ~5 min. Non-mutating. Combines `check:public:superdoc` + `check:public:docapi`. - `pnpm check:public:superdoc` - SuperDoc public package surface only (alias of `check:public-contract`). - `pnpm check:public:docapi` - Document API public surface only (alias of `docapi:check`). Requires generated artifacts to be current; if it fails on staleness, run `pnpm generate:docapi`. -- `pnpm generate:docapi` - regenerate Document API outputs after editing the contract (alias of `docapi:sync`). Mutates `packages/document-api/generated/**`; commit the changes. +- `pnpm generate:docapi` - regenerate Document API outputs after editing the contract (alias of `docapi:sync`). Writes to `packages/document-api/generated/` (gitignored). Run before `check:public:docapi` if it fails on missing files. - `pnpm generate:all` - regenerate schemas, SDK clients, tool catalogs, reference docs. - `pnpm report:public:superdoc` - print public-contract tier metadata (supported / legacy / asset / deprecated). Read-only, not a gate. Source of truth: `packages/superdoc/scripts/type-surface.config.cjs`. diff --git a/packages/superdoc/scripts/README.md b/packages/superdoc/scripts/README.md index 322d392bcf..08354274f0 100644 --- a/packages/superdoc/scripts/README.md +++ b/packages/superdoc/scripts/README.md @@ -6,7 +6,9 @@ interface under `packages/document-api/scripts/`; both are summarized here so contributors have one place to learn the system. If you only have time for one sentence: **run `pnpm check:public` before -opening or merging anything that touches public types.** +opening or merging anything that touches public types.** It's the +public type/interface preflight — it does not replace `pnpm test` or +`pnpm build` for product correctness. --- @@ -14,7 +16,7 @@ opening or merging anything that touches public types.** | Question | Command | Speed | Mutates files? | |---|---|---|---| -| Am I safe to ship a PR? | `pnpm check:public` | ~5 min | no | +| Are public interfaces safe? | `pnpm check:public` | ~5 min | no | | TypeScript compiles cleanly? | `pnpm check:types` | seconds | no | | Only SuperDoc public surface changed? | `pnpm check:public:superdoc` | ~3 min | no | | Only Document API contract changed? | `pnpm check:public:docapi` | seconds | no | @@ -65,8 +67,8 @@ but have separate script chains because the validation needs differ. | Command | Runs | Mutates? | |---|---|---| -| `generate:docapi` | `docapi:sync` (legacy alias) | yes — writes `packages/document-api/generated/**` | -| `generate:all` | schemas, SDK clients, tool catalogs, reference docs | yes — multi-target generator | +| `generate:docapi` | `docapi:sync` (legacy alias) | yes — writes Document API artifacts under `packages/document-api/generated/` (gitignored; run before `check:public:docapi` if it fails on missing files). | +| `generate:all` | schemas, SDK clients, tool catalogs, reference docs | yes — multi-target generator. Some outputs are gitignored (`generated/`), others are committed (e.g. `apps/docs/document-api/reference/`); any tracked generated changes should be committed. | ### Legacy aliases From f979d879fdefb0d23a9821af5cf341f93452b69b Mon Sep 17 00:00:00 2001 From: Caio Pizzol Date: Sat, 23 May 2026 14:02:42 -0300 Subject: [PATCH 3/3] docs: avoid transient generated path in agent docs --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 9bd2dc03bb..cc192d7481 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -75,7 +75,7 @@ Do not hand-edit `COMMAND_CATALOG`, `OPERATION_MEMBER_PATH_MAP`, `OPERATION_REFE - `pnpm check:public` - **canonical pre-merge command for typed public surfaces.** Validates both `superdoc` (vite build + postbuild chain + consumer typecheck matrix + deep-type audit) and Document API (contract parity + output staleness + examples + overview). ~5 min. Non-mutating. Combines `check:public:superdoc` + `check:public:docapi`. - `pnpm check:public:superdoc` - SuperDoc public package surface only (alias of `check:public-contract`). - `pnpm check:public:docapi` - Document API public surface only (alias of `docapi:check`). Requires generated artifacts to be current; if it fails on staleness, run `pnpm generate:docapi`. -- `pnpm generate:docapi` - regenerate Document API outputs after editing the contract (alias of `docapi:sync`). Writes to `packages/document-api/generated/` (gitignored). Run before `check:public:docapi` if it fails on missing files. +- `pnpm generate:docapi` - regenerate Document API outputs after editing the contract (alias of `docapi:sync`). Writes gitignored generated artifacts under the Document API package. Run before `check:public:docapi` if it fails on missing files. - `pnpm generate:all` - regenerate schemas, SDK clients, tool catalogs, reference docs. - `pnpm report:public:superdoc` - print public-contract tier metadata (supported / legacy / asset / deprecated). Read-only, not a gate. Source of truth: `packages/superdoc/scripts/type-surface.config.cjs`.