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
32 changes: 32 additions & 0 deletions .changeset/references-empty-category-meta.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
---
"@objectstack/spec": patch
---

fix(spec): stop emitting a `meta.json` for a reference category that publishes no page (#7303)

`gen:docs` wrote `content/docs/references/<category>/meta.json` for every category
it iterated, including one whose page list came out empty. The result was a
directory holding a single `{ "title": …, "pages": [] }` and nothing else: no
reference page, no `index.mdx` (§2.5 already skipped that), and no entry in the
root `meta.json`, so the route could not resolve and the link checker never saw
it. Its one measurable effect was on whoever enumerated the tree — human or
agent — who counted one category more than the docs actually publish.

`contracts/` was the standing case. It holds TypeScript service interfaces
rather than `.zod.ts` schemas, so `gen:schema` creates `json-schema/contracts/`
and leaves it empty; `conversions`/`migrations` have no schema directory at all
and are skipped outright, while `contracts` reached the emit with zero pages.
The `meta.json` emit is now guarded on the page list being non-empty, mirroring
the guard the category `index.mdx` emit already carries, so all three behave
alike. `content/docs/references/` goes from 15 category directories to 14.

The guard is on the page count, not on that schema-directory asymmetry, so a
future category in either shape lands the same way.

No published page changes: the emitted file count goes 231 → 230, and the one
file that stops being written is the empty `meta.json`. The Contracts Protocol
prose documentation is unaffected — it lives at `content/docs/kernel/contracts/`
and is not generated from this tree. `contracts` also remains a declared
category in `scripts/lib/category-title.ts`; `resolveCategoryTitles` is total
over the directories in `packages/spec/src/`, so that declaration is mandatory
while the module exists.
5 changes: 2 additions & 3 deletions content/docs/getting-started/quick-reference.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -233,15 +233,14 @@ Testing and quality assurance.

## Categories Without a Section

`content/docs/references/` holds two more category directories that deliberately get no
`content/docs/references/` holds one more category directory that deliberately gets no
section above. Curation happens at the category level as well as inside each table, and
this is where it is stated. The same gate reads this table, so a new category directory —
or a page landing in one of these — goes red until this page is updated.
or a page landing in this one — goes red until this page is updated.

| Category directory | Pages | Why it has no section |
|:---|---:|:---|
| [`studio`](/docs/references/studio) | 3 | Designer-facing metadata (`flow-builder`, `object-designer`, `plugin`) — Studio's own authoring surfaces, not protocols an app declares. Reach them from the [reference index](/docs/references). |
| `contracts` | 0 | Publishes no reference page at all; the directory holds only a `meta.json` left over from an earlier layout. There is nothing to link. |

---

Expand Down
4 changes: 0 additions & 4 deletions content/docs/references/contracts/meta.json

This file was deleted.

20 changes: 19 additions & 1 deletion packages/spec/scripts/build-docs.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -837,9 +837,27 @@ PAGES_BY_CATEGORY.forEach((zodFileSchemas, category) => {

// Generate Category Meta. Group into fumadocs `---Section---` separators when the
// category has a SECTION_GROUPS entry; otherwise a flat sorted list (see #1880).
const pages = buildCategoryPages(category, Array.from(zodFileSchemas.keys()));

// A category that published no page gets no `meta.json` — and so no directory
// at all — the same way §2.5 below skips the `index.mdx` of one. What this
// guard removes is a folder holding a single `{ "pages": [] }`: no page, no
// `index.mdx`, and no entry in the root `meta.json`, so it is unroutable, and
// invisible to the link checker. Its one measurable effect was that anyone
// enumerating the tree counted one category more than exists — which is how
// #7303 came to be filed.
//
// `contracts/` is the case: it holds TypeScript service interfaces rather than
// `.zod.ts` schemas, so `gen:schema` creates `json-schema/contracts/` and
// leaves it empty; unlike `conversions`/`migrations` (no schema directory at
// all, so `groupSchemasByPage` skips them outright) it reaches this loop with
// zero pages. The guard is on the pages, not on that asymmetry, so any future
// category in either shape lands the same way.
if (pages.length === 0) return;

const meta = {
title: CATEGORIES[category],
pages: buildCategoryPages(category, Array.from(zodFileSchemas.keys()))
pages
};
emit(path.join(categoryDir, 'meta.json'), JSON.stringify(meta, null, 2));
});
Expand Down
12 changes: 6 additions & 6 deletions scripts/check-quick-reference-counts.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -77,12 +77,12 @@
*
* ## Curation also happens one level up
*
* `references/studio/` (3 pages) and `references/contracts/` (0 pages) have no
* section on the page at all. Left implicit, that is the same unwatched drift
* one level up, so the page carries a `## Categories Without a Section` table
* and this gate reads it: every category directory under
* `content/docs/references/` must either be a section's derived category or be
* declared there with its real page count — never both, never neither.
* `references/studio/` (3 pages) has no section on the page at all. Left
* implicit, that is the same unwatched drift one level up, so the page carries
* a `## Categories Without a Section` table and this gate reads it: every
* category directory under `content/docs/references/` must either be a
* section's derived category or be declared there with its real page count —
* never both, never neither.
*
* ## Absence must be loud
*
Expand Down
Loading