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
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ Do not hand-edit `COMMAND_CATALOG`, `OPERATION_MEMBER_PATH_MAP`, `OPERATION_REFE
- `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:docapi` - Document API public surface only. Requires generated artifacts to be current; if it fails on missing files, run `pnpm generate:docapi`. Legacy alias: `pnpm run docapi:check`.
- `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 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`.

Expand Down
18 changes: 16 additions & 2 deletions packages/document-api/scripts/check-contract-outputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@
* Caller: Main CI/local gate for generated Document API artifacts.
* Reads: Contract snapshot + generated schemas/agent artifacts/reference docs + overview.
* Writes: None (exit code + console output only).
* Fails when: Any generated output is missing/extra/stale or overview block is out of sync.
* Fails when: A tracked generated output (reference docs, overview block)
* is missing/extra/stale, or any artifact builder throws.
*
* Clean-checkout safe: the schemas/ and agent/ outputs live under
* `packages/document-api/generated/` which is gitignored. Those
* artifacts are built in memory (so any builder error still surfaces)
* but their on-disk presence is not required. Reference docs and the
* overview block ARE committed and continue to be compared
* byte-for-byte against the in-memory build. Run `pnpm generate:docapi`
* to materialize the gitignored artifacts locally before publishing.
*/
import {
buildStableSchemaArtifacts,
Expand All @@ -22,7 +31,12 @@ runScript('contract output artifacts check', async () => {
const files = [...buildStableSchemaArtifacts(), ...buildAgentArtifacts(), ...buildReferenceDocsArtifacts()];

const issues = await checkGeneratedFiles(files, {
roots: [getStableSchemaRoot(), getAgentArtifactRoot(), getReferenceDocsOutputRoot()],
// Tracked output: committed reference docs must match the in-memory
// build (existence, content, and no extras on disk).
roots: [getReferenceDocsOutputRoot()],
// Gitignored: validate the builders produce the artifacts in memory,
// but don't require the files to exist on a clean checkout.
inMemoryRoots: [getStableSchemaRoot(), getAgentArtifactRoot()],
});

await checkReferenceDocsExtras(files, issues);
Expand Down
29 changes: 28 additions & 1 deletion packages/document-api/scripts/lib/generation-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,18 +87,45 @@ async function pathExists(path: string): Promise<boolean> {
}
}

/**
* Compare expected generated files against the on-disk state.
*
* - `roots`: tracked directories whose committed contents must match the
* in-memory build. Files under these roots are checked for existence,
* content equality, and "extras on disk that should not be there."
* Use for outputs that live in the repo (e.g. `apps/docs/.../reference/`).
* - `inMemoryRoots`: directories whose contents are gitignored. Files
* under these roots are NOT checked for existence or extras on disk,
* because a clean checkout has none. The in-memory build is still
* exercised (any error thrown by the builder still propagates),
* confirming the artifacts CAN be produced. Use for outputs that the
* developer regenerates locally with the matching `generate:*` command.
*
* The "content matches when the file is present" check still runs for
* `inMemoryRoots` files — if a developer has a previously-generated
* stale copy on disk, surface it; but a missing file is not an issue.
*/
export async function checkGeneratedFiles(
expectedFiles: GeneratedFile[],
options: {
roots?: string[];
inMemoryRoots?: string[];
} = {},
): Promise<GeneratedCheckIssue[]> {
const issues: GeneratedCheckIssue[] = [];
const expected = new Map<string, GeneratedFile>(expectedFiles.map((file) => [file.path, file]));
const inMemoryRoots = options.inMemoryRoots ?? [];

const isUnderInMemoryRoot = (path: string): boolean =>
inMemoryRoots.some((root) => path === root || path.startsWith(`${root}/`));

for (const [path, file] of expected.entries()) {
const onDiskOptional = isUnderInMemoryRoot(path);
if (!(await pathExists(path))) {
issues.push({ kind: 'missing', path });
// Missing is only an issue when the file is expected to be tracked
// on disk. For in-memory roots, the build succeeded (it produced
// the GeneratedFile entry), which is what we needed to verify.
if (!onDiskOptional) issues.push({ kind: 'missing', path });
continue;
}

Expand Down
16 changes: 9 additions & 7 deletions packages/superdoc/scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,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. **Requires generated artifacts to be up-to-date** — if it fails on staleness, run `generate:docapi` to refresh. |
| `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. |

### TypeScript compiler
Expand All @@ -67,7 +67,7 @@ but have separate script chains because the validation needs differ.

| Command | Runs | Mutates? |
|---|---|---|
| `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:docapi` | `docapi:sync` (legacy alias) | yes — writes Document API artifacts under `packages/document-api/generated/` (gitignored). Run this when you want the artifacts materialized locally (e.g. for SDK builds or before publishing). `check:public:docapi` does NOT require running this first. |
| `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
Expand Down Expand Up @@ -143,14 +143,16 @@ canonical source, and several artifacts are generated from it.
|---|---|---|
| `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-contract-outputs.ts` | check | Builds all artifacts in memory and compares against the on-disk state. For tracked outputs (`apps/docs/document-api/reference/`, overview block) the disk must match exactly. For gitignored outputs (`packages/document-api/generated/`) the in-memory build is verified to succeed, but the files are not required on disk; if they happen to be present, content is still checked. |
| `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.
The four `check-*` scripts run together via `check:public:docapi` and
are **clean-checkout safe**: a fresh `git clone` followed by
`pnpm install && pnpm check:public` succeeds without `generate:docapi`
having run first. `generate:docapi` remains the explicit way to
materialize the gitignored artifacts when you need them locally (SDK
builds, publishing).

---

Expand Down
Loading