Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@ Do not hand-edit `COMMAND_CATALOG`, `OPERATION_MEMBER_PATH_MAP`, `OPERATION_REFE
- `pnpm test` - unit tests
- `pnpm dev` - dev server from `examples/`
- `pnpm check:types` - raw TS compile across all referenced projects (`tsc -b tsconfig.references.json`). Does NOT run the public-interface chain. Legacy alias: `pnpm run type-check`.
- `pnpm check:public` - **canonical pre-merge command for typed public surfaces.** Validates both `superdoc` (vite build + postbuild chain + consumer typecheck matrix + deep-type audit + package-shape + snapshots + classification closure) 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. Wraps six stages: build + matrix + deep-type audit + package-shape + snapshots + closure. Legacy alias: `pnpm run check:public-contract`.
- `pnpm check:public` - **canonical pre-merge command for typed public surfaces.** Validates both `superdoc` (tier discipline + vite build + postbuild chain + consumer typecheck matrix + deep-type audit + package-shape + snapshots + classification closure) 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. Wraps eight stages: tier-discipline:test + tier-discipline (fast-fail), build, matrix, deep-type audit, package-shape, snapshots, closure. Legacy alias: `pnpm run check:public-contract`.
- `pnpm check:public:docapi` - Document API public surface only. Clean-checkout safe: gitignored generated artifacts are built in memory; tracked outputs (reference docs, overview block) are compared byte-for-byte. No mutation. Legacy alias: `pnpm run docapi:check`.
- `pnpm generate:docapi` - regenerate Document API outputs after editing the contract (alias of `docapi:sync`). Writes gitignored Document API generated artifacts. Run only when you need the artifacts materialized locally (SDK builds, publishing); `check:public:docapi` does not require it.
- `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`.
- `pnpm report:public:superdoc` - print public-contract tier metadata (supported / legacy / legacy-raw / asset / deprecated). Read-only, not a gate. Use `check:public:superdoc` (or its `tier-discipline` stage) to enforce. Source of truth: `packages/superdoc/scripts/type-surface.config.cjs`.

Full system reference (script catalog, dataflow, CI vs local): `packages/superdoc/scripts/README.md`.

Expand Down
28 changes: 26 additions & 2 deletions packages/superdoc/scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ but have separate script chains because the validation needs differ.
| `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. Clean-checkout safe: gitignored outputs (`packages/document-api/generated/`) are built in memory; tracked outputs (`apps/docs/document-api/reference/`, overview block) are still compared byte-for-byte. |
| `report:public:superdoc` | `report:public-contract` (legacy alias) | Read-only tier metadata (supported / legacy / asset / deprecated). Not a gate. |
| `report:public:superdoc` | `report:public-contract` (legacy alias) | Read-only tier metadata (supported / legacy / legacy-raw / asset / deprecated). Not a gate. |

### TypeScript compiler

Expand Down Expand Up @@ -105,6 +105,29 @@ it stopped running.
| `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. |

The repo also has a top-level tier-discipline gate. One script,
`scripts/report-public-contract.mjs`, with two modes:

- default (read-only report) - what `pnpm report:public:superdoc` runs.
Prints the tiers + a validator status block. Exit 0 always.
- `--check` (gate) - runs as stage 2 of `check:public:superdoc` after
the validator's unit tests. Fails the build on any invariant
violation.

Both modes share the pure `validatePublicContract` exported from the
same file (unit-tested in `scripts/report-public-contract.test.mjs`).

Invariants enforced in `--check` mode against the `publicContract`
taxonomy in `type-surface.config.cjs`:

- every `package.json#exports` subpath has a tier entry
- every tier entry exists in `package.json#exports`
- no subpath appears in more than one tier
- each entry's `tier` field matches its bucket
- `supported` subpaths route through `dist/superdoc/src/public/**` (excluding the `legacy/` subtree)
- `legacy` subpaths route through `dist/superdoc/src/public/legacy/**`
- `legacyRaw` is restricted to the explicitly accepted set (currently only `./super-editor`)

---

## Consumer-typecheck infrastructure (`tests/consumer-typecheck/`)
Expand All @@ -121,7 +144,8 @@ what an actual consumer would see — not the workspace source.
| `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 all six in order. `typecheck-matrix` packs
`check:public:superdoc` runs all six in order (after the cheap
tier-discipline stage at the top of the wrapper). `typecheck-matrix` packs
`superdoc.tgz` and installs it into the consumer fixture. The rest
reuse what matrix produced: `deep-type-audit`, `snapshot --all
--check`, and `check-root-classification-closure` read from the
Expand Down
77 changes: 53 additions & 24 deletions scripts/check-public-contract.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,40 @@
* TypeScript surface end-to-end.
*
* Stages:
* 1. build:superdoc - vite build + the postbuild validator chain
* (check-tsconfig-type-surface, ensure-types,
* audit-bundle, audit-declarations,
* check-export-coverage, verify-public-facade-emit,
* report-declaration-reachability).
* Skipped when `--skip-build` is passed (CI calls
* `pnpm run build` separately in its own step).
* 2. typecheck-matrix - packs superdoc + installs the tarball into
* tests/consumer-typecheck/node_modules/, then
* runs every consumer scenario.
* 3. deep-type-audit - strict gate on the supported-root public
* surface (must be 0 findings). Reuses the
* install that stage 2 produced (no `--pack`).
* 4. package-shape - publint + attw against the packed manifest
* (reuses the install from stage 2).
* 5. snapshots - super-editor / legacy / root no-growth
* snapshots (reuses the install).
* 6. closure - root-classification closure gate:
* no supported-root/legacy-root export
* references an internal-candidate type.
* 1. tier-discipline:test - unit tests for the pure tier validator.
* Cheap (~50ms). Verifies the validator
* catches every failure class before the
* next stage trusts its verdict.
* 2. tier-discipline - package.json#exports vs publicContract
* tier coverage, routing, and legacy-raw
* allowlist. Cheap (~10ms); runs early so
* tier drift fails fast before the slow
* build/matrix work.
* 3. build:superdoc - vite build + the postbuild validator chain
* (check-tsconfig-type-surface, ensure-types,
* audit-bundle, audit-declarations,
* check-export-coverage, verify-public-facade-emit,
* report-declaration-reachability).
* Skipped when `--skip-build` is passed (CI calls
* `pnpm run build` separately in its own step).
* 4. typecheck-matrix - packs superdoc + installs the tarball into
* tests/consumer-typecheck/node_modules/, then
* runs every consumer scenario.
* 5. deep-type-audit - strict gate on the supported-root public
* surface (must be 0 findings). Reuses the
* install that stage 4 produced (no `--pack`).
* 6. package-shape - publint + attw against the packed manifest
* (reuses the tarball from stage 4).
* 7. snapshots - super-editor / legacy / root no-growth
* snapshots (reuses the install).
* 8. closure - root-classification closure gate:
* no supported-root/legacy-root export
* references an internal-candidate type.
*
* Matrix runs BEFORE stages 3-6 on purpose: it packs `superdoc.tgz`
* and installs the tarball into the consumer fixture once. Stages 3,
* 5, and 6 (deep-type-audit, snapshots, closure) reuse the installed
* fixture; stage 4 (package-shape-gate) reuses the packed tarball
* Matrix runs BEFORE stages 5-8 on purpose: it packs `superdoc.tgz`
* and installs the tarball into the consumer fixture once. Stages 5,
* 7, and 8 (deep-type-audit, snapshots, closure) reuse the installed
* fixture; stage 6 (package-shape-gate) reuses the packed tarball
* directly. Without this ordering each downstream stage would
* `--pack` separately and multiply the work.
*
Expand All @@ -55,6 +64,26 @@ const flags = new Set(process.argv.slice(2));
const skipBuild = flags.has('--skip-build');

const stages = [
{
name: 'tier-discipline:test',
cwd: REPO_ROOT,
cmd: 'node',
args: ['--test', 'scripts/report-public-contract.test.mjs'],
blurb:
'Unit tests for the pure tier validator. Cheap (~50ms); verifies ' +
'the validator catches every failure class before the next stage ' +
'trusts its verdict.',
},
{
name: 'tier-discipline',
cwd: REPO_ROOT,
cmd: 'node',
args: ['scripts/report-public-contract.mjs', '--check'],
blurb:
'Public-contract tier discipline: package.json#exports vs publicContract ' +
'(tier coverage, routing, legacy-raw allowlist). Cheap; fast-fails before ' +
'the slow build/matrix stages.',
},
{
name: 'build:superdoc',
cwd: REPO_ROOT,
Expand Down
Loading
Loading