Skip to content

docs(spec): generated reference pages follow the docs title rule, sidebar labels kept via navTitle - #20401

Merged
objectstack-fleet[bot] merged 12 commits into
mainfrom
claude/issue-15403-generator-title-rule
Sep 28, 2026
Merged

objectstack-fleet[bot] merged 12 commits into
mainfrom
claude/issue-15403-generator-title-rule

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #15403
Clause-②: no

Summary

The generated reference pages under content/docs/references/** now carry the docs page-title rule, emitted by the generator itself, and every one keeps its sidebar label byte-identical through navTitle.

  • One pure function holds the rule: packages/spec/scripts/lib/page-title.ts. It builds each title from data the generator already holds (the module display name and the category's declared title) plus fixed words, picks the longest candidate inside the band, and refuses (never truncates) when no candidate fits.
  • Three emission sites use it: module pages and category index pages in packages/spec/scripts/build-docs.ts, and the root index in packages/spec/scripts/lib/root-index.ts.
  • navTitle = the page's previous title, verbatim, so navLabel() in apps/docs/lib/nav-title.ts returns the same string as before. The page tree is unchanged (replayed below, with a control).
  • 211 generated pages regenerated, frontmatter only: each is +2/-1 (the title: line replaced, a navTitle: line added). No description:, no body, no meta.json.

The rule, and how the emitter expresses it

The rule is the maintainer's, recorded on #12237 in comment 5419555720, verbatim 「其他同意」. Its text as landed is the ## The rule section of PR #20170:

  • shape PRIMARY-KEYWORD — QUALIFIER, separator —;
  • frontmatter title is 36–46 characters, so the rendered title with the 14-character | ObjectStack suffix is 50–60, none over 60;
  • ObjectStack never inside a title;
  • short navigation labels go in navTitle, whose fallback to title lives only in navLabel().

The generator holds only the module display name (3–29 characters on this tree), the category's declared title (11–20 for categories with pages) and fixed words. No single template lands every page inside an 11-character band, so each page kind has a short ladder, longest first, and the title is the first candidate inside the band:

page kind candidate (longest first) length
module page NAME schema — CATEGORY property reference, offered only when the page renders a ### Properties table name + category + 29
NAME schema — CATEGORY reference name + category + 20
NAME — CATEGORY reference name + category + 13
NAME — CATEGORY name + category + 3
category index CATEGORY — complete schema reference category + 28
CATEGORY — schema reference category + 19
root index Protocol reference — every schema by module 43

The module rungs overlap end to end and cover every name + category length from 7 to 43; the longest pair on the tree is 41 (Schemaless Node Config in Automation Protocol). The first module rung is conditional: property reference is offered only when at least one of the page's schemas renders a ### Properties table (rendersPropertiesTable in lib/schema-section.ts, built on declaresProperties, the one expression the section renderer itself branches on). A page without one, such as the enum-only data/feed, starts at the second rung; without the first rung the ladder covers name + category lengths 16 to 43, and the shortest property-less pair on the tree is 17 (Feed in Data Protocol). The category rungs cover category titles of 8 to 27 characters; the longest declared title is 25. The category in every module title keeps same-named modules apart (Plugin is both a kernel and a studio page). A page no rung fits stops gen:docs with a message naming the page and every candidate with its length.

Rung usage on this tree: module pages 18 / 103 / 60 / 15 (rungs 1–4), category index pages 11 / 3, root index 1. All 18 rung-1 pages render a ### Properties table; the 14 module pages that render none are all on rungs 2–4.

Measured, before and after

Population re-derived at base 862b6ce8 and at head: content/docs/**/*.mdx = 406; pages carrying the generator's AUTO-GENERATED — DO NOT EDIT banner = 211, all under content/docs/references/** (196 module pages, 14 category index pages, 1 root index). Rendered = title + 14.

pages min median max in 36–46 outside rendered over 60 with — with ObjectStack duplicate titles navTitle
before (origin/main) 211 3 11 29 0 211 0 0 0 6 0
after (this head) 211 37 43 46 211 0 0 211 0 0 211

After: rendered 51–60. Duplicate titles across the whole corpus (406 pages, authored and generated): 0.

The card body's 225 of 405 does not reproduce, and the difference is not generator output. The generated set is 211; the 14 others in that count are content/docs/releases/** pages, which carry no generator banner and are release-owned (compiled by hand at release time). No other emitter writes a title: into content/docs/**: build-skill-docs.ts rewrites only the region between its markers in content/docs/ai/skills-reference.mdx, whose authored title already follows the rule (PR #20170). The only title: emissions in the repo's generators are the three this PR changes (git grep over scripts/, packages/*/scripts/, apps/docs/scripts/).

The page tree is unchanged

Replayed with the site's own machinery: fumadocs-core 16.14.4 loader() (the apps/docs dependency) with the site's i18n settings and the site's navTitlePlugin(), over every .mdx frontmatter and meta.json under content/docs, once from origin/main and once from this head. Serialized page tree (folders, separators, pages, folder index pages): 449 nodes before, 449 after, diff exit 0.

Control, so the replay can see a title change at all: the same replay of this head WITHOUT navTitlePlugin() differs from origin/main in 388 nodes, exactly the 211 generated pages plus the 177 authored pages PR #20170 gave a navTitle.

Folder labels come from each category's meta.json title, which this PR does not touch. The category and root index.mdx pages carry navTitle anyway because the footer previous/next list walks folder index pages.

Examples

page before after chars / rendered
references/ai/mcp.mdx Mcp Mcp schema — AI Protocol property reference 43 / 57
references/ai/agent.mdx Agent Agent schema — AI Protocol property reference 45 / 59
references/data/feed.mdx Feed Feed schema — Data Protocol reference 37 / 51
references/data/object.mdx Object Object schema — Data Protocol reference 39 / 53
references/automation/flow.mdx Flow Flow schema — Automation Protocol reference 43 / 57
references/kernel/plugin.mdx Plugin Plugin schema — Kernel Protocol reference 41 / 55
references/studio/plugin.mdx Plugin Plugin schema — Studio Protocol reference 41 / 55
references/kernel/plugin-registry.mdx Plugin Registry Plugin Registry — Kernel Protocol reference 43 / 57
references/kernel/metadata-protection.mdx Metadata Protection Metadata Protection — Kernel Protocol 37 / 51
references/ui/expression-bindable-text-keys.mdx Expression Bindable Text Keys Expression Bindable Text Keys — UI Protocol 43 / 57
references/automation/schemaless-node-config.mdx Schemaless Node Config Schemaless Node Config — Automation Protocol 44 / 58
references/ai/index.mdx AI Protocol AI Protocol — complete schema reference 39 / 53
references/automation/index.mdx Automation Protocol Automation Protocol — schema reference 38 / 52
references/identity/index.mdx Identity Protocol Identity Protocol — complete schema reference 45 / 59
references/index.mdx Protocol Reference Protocol reference — every schema by module 43 / 57

The complete table is at the end.

Wording for maintainer voice review

The rule is approved; the fixed words the generator adds are new public text and are not in the approved table of PR #12312: schema, property reference, reference, complete schema reference, schema reference, and the root title Protocol reference — every schema by module. Rewording any of them is a one-line change in lib/page-title.ts plus gen:docs; the band, the unit test and check:docs hold the result either way. Non-blocking: the seat answered land-as-shipped in comment 5865474678 on #15403, and property reference is now claimed only by pages that render a property table.

File surface

  • packages/spec/scripts/lib/page-title.ts (new): the rule, the ladders, the refusal, the frontmatter lines.
  • packages/spec/scripts/page-title.test.ts (new): the pin (local vitest project; reads nothing outside the package).
  • packages/spec/scripts/build-docs.ts: the two emission sites (module pages, category index pages), located by symbol.
  • packages/spec/scripts/lib/schema-section.ts: declaresProperties() (an object that declares properties, the one spelling of that condition, now also used by the renderer's root and union-arm branches) and rendersPropertiesTable() (whether a schema renders at least one ### Properties table), read by the module-page title. Rendered output unchanged: regenerating moved exactly one page, data/feed.mdx, and only its title: line.
  • packages/spec/scripts/lib/root-index.ts: one site beyond the two the dispatch named. It is the generator's third title: emission (the root references/index.mdx, previously title: Protocol Reference, 18 characters). Leaving it would have left one generated page outside the rule.
  • content/docs/references/**: 211 pages, regenerated by gen:docs, never hand-edited.
  • Not touched: authored pages, the description: emission, check-generated.ts (it regenerates and compares; nothing in it reads the title line), build-skill-docs.ts (emits no title).

Changeset: skip-changeset

Rule applied: a changeset is owed when a package's published files[] content moves. @objectstack/spec publishes dist, json-schema, liveness, prompts, llms.txt, README.md, src/**/*.zod.ts, CHANGELOG.md, api-surface, spec-changes.json; scripts/ is not among them, and apps/docs (which renders content/docs) is private. Measured after the build: the new symbols (titleFrontmatter, navTitle, property reference) have 0 hits across all ten of those paths, while the positive control ObjectSchema hits in 9 of the 10 (all but json-schema).

Verification

Head 1ba9d84c, REWORK round 1: 41b0f683 (the conditional rung), 0ea42f45 (data/feed.mdx regenerated), then a merge of origin/main at df3ba164 whose two deferred pages, security/{permission,rls}.mdx, were regenerated on the merged tree in 1ba9d84c. Round 0 was head a61335f9.

  • pnpm --filter @objectstack/spec test: 561 files, 16546 passed, 1 todo.
  • pnpm --filter @objectstack/spec test:repo: 35 files, 634 passed.
  • Type check: check:scripts-typecheck (tsc -p tsconfig.scripts.json, the program holding every file this diff edits, page-title.test.ts included) exit 0 at 1ba9d84c. The full spec typecheck was green locally at round 0's pre-merge head 0a241893, and Type Check · workspace ran it green in CI on a61335f9.
  • The new files are in the scripts tsc program (tsc -p tsconfig.scripts.json --listFiles lists lib/page-title.ts and page-title.test.ts).
  • Gates derived by node scripts/pm/dispatch-gates.mjs --commands over this diff at 1ba9d84c (216 paths, the same 89 families as round 0), each exit code recorded, then --ran: 89 derived, 85 run (all exit 0), 4 NOT MEASURED, 0 UNRUN. Among the 85: check:docs, check:generated (all 15 generated artifacts up to date), check:doc-frontmatter, check:docs-single-h1, check:doc-anchors, check:nul-bytes, check:quick-reference-counts.
    • NOT MEASURED, prerequisite refused (exit 3): check:skill-examples (needs the 36-package @objectstack/client-react closure built), check:dual-build-cjs-loads (needs every package built), check:type-check-debt (needs a 30-package closure built).
    • NOT MEASURED, timed out: check:pm-dispatch-gates. Its self-test of scripts/pm/dispatch-gates.mjs, which this diff does not edit, did not finish in a 420 s and then a 560 s window on the shared box. Not re-run in round 1; Lint & Repo Gates ran it green in CI on a61335f9.
  • Ablation 1, the unit test can fail: scripts/ablation-replace.mjs changed TITLE_MAX = 46 to 60 in lib/page-title.ts (anchor 1 to 0, blob 3fe85286f82d to ee55509927c8). page-title.test.ts went 12 failed / 13 passed. Restored under an EXIT/INT/TERM trap to 3fe85286f82d = HEAD blob, git diff HEAD empty.
  • Ablation 2, check:docs sees the emission: the first module rung's property reference changed to field reference (blob 3fe85286f82d to b8f4c6d26269). check:docs exited 1 with 49 pages out of date: the 19 rung-1 pages, plus the pages the shorter word lets onto rung 1. Restored the same way.
  • Ablation 3, the rung condition is pinned: ...(documentsProperties ? [ changed to ...(true ? [ in lib/page-title.ts (anchor 1 to 0, blob 38277b23f728 to 90e0cbe18d3b). page-title.test.ts went 3 failed / 38 passed: the data/feed row, the condition pin, and the short property-less refusal. Restored to 38277b23f728 = HEAD blob, git diff HEAD empty.
  • The predicate agrees with the renderer on every published schema: over all 1523 JSON Schemas under packages/spec/json-schema/, rendersPropertiesTable(name, schema) equals whether renderSchemaSection(name, schema) emits a ### Properties heading: 1219 true, 0 disagreements. The unit pin holds the same agreement shape by shape (11 JSON Schema shapes covering every renderer branch).

Acceptance notes

  • Module display names are title-cased from the file slug, so abbreviations come out wrong: Mcp, Rls, Scim, Odata, Http, I18n, Driver Sql, Cli Extension, Io Node Config, Bpmn Interop, Package Api, Rest Server, Events Dlq, and others. This is the Qa Protocol defect class that lib/category-title.ts fixed for category titles, one level down, and it predates this PR (these strings were the whole title before; they are the navTitle now, and the primary keyword of the new title). Out of scope here: fixing it changes nav labels, which this card keeps byte-identical. Noted, not filed.
  • The card body's 225 / 405 reading included 14 releases/** pages (see Measured); nothing here depends on them.
  • api/protocol.mdx renders 6 ### Properties tables with no rows (object schemas declaring an empty properties). Pre-existing renderer output; that page is on rung 2 and carries non-empty tables as well. Noted, not filed.
  • The optional routing of rootIndexTitle() through pageTitleOrExit was not taken: pageTitleOrExit lives in build-docs.ts, so routing it means passing the title into renderRootIndex (its input type and the root-index.test.ts fixtures), more than one line. The root title is a fixed 43-character string pinned by the unit test.

The complete table

All 211 generated pages. navTitle = before, verbatim, on every row.

page before after chars / rendered navTitle
references/index.mdx Protocol Reference Protocol reference — every schema by module 43 / 57 = before
references/ai/index.mdx AI Protocol AI Protocol — complete schema reference 39 / 53 = before
references/ai/agent.mdx Agent Agent schema — AI Protocol property reference 45 / 59 = before
references/ai/build-progress.mdx Build Progress Build Progress schema — AI Protocol reference 45 / 59 = before
references/ai/conversation.mdx Conversation Conversation schema — AI Protocol reference 43 / 57 = before
references/ai/embedding.mdx Embedding Embedding schema — AI Protocol reference 40 / 54 = before
references/ai/knowledge-document.mdx Knowledge Document Knowledge Document — AI Protocol reference 42 / 56 = before
references/ai/knowledge-source.mdx Knowledge Source Knowledge Source — AI Protocol reference 40 / 54 = before
references/ai/mcp.mdx Mcp Mcp schema — AI Protocol property reference 43 / 57 = before
references/ai/model-registry.mdx Model Registry Model Registry schema — AI Protocol reference 45 / 59 = before
references/ai/skill.mdx Skill Skill schema — AI Protocol property reference 45 / 59 = before
references/ai/solution-blueprint.mdx Solution Blueprint Solution Blueprint — AI Protocol reference 42 / 56 = before
references/ai/tool.mdx Tool Tool schema — AI Protocol property reference 44 / 58 = before
references/ai/usage.mdx Usage Usage schema — AI Protocol property reference 45 / 59 = before
references/api/index.mdx API Protocol API Protocol — complete schema reference 40 / 54 = before
references/api/analytics.mdx Analytics Analytics schema — API Protocol reference 41 / 55 = before
references/api/auth-endpoints.mdx Auth Endpoints Auth Endpoints schema — API Protocol reference 46 / 60 = before
references/api/auth.mdx Auth Auth schema — API Protocol property reference 45 / 59 = before
references/api/automation-api.mdx Automation Api Automation Api schema — API Protocol reference 46 / 60 = before
references/api/batch.mdx Batch Batch schema — API Protocol property reference 46 / 60 = before
references/api/contract.mdx Contract Contract schema — API Protocol reference 40 / 54 = before
references/api/discovery.mdx Discovery Discovery schema — API Protocol reference 41 / 55 = before
references/api/dispatcher.mdx Dispatcher Dispatcher schema — API Protocol reference 42 / 56 = before
references/api/documentation.mdx Documentation Documentation schema — API Protocol reference 45 / 59 = before
references/api/endpoint.mdx Endpoint Endpoint schema — API Protocol reference 40 / 54 = before
references/api/error-code-ledger.mdx Error Code Ledger Error Code Ledger — API Protocol reference 42 / 56 = before
references/api/errors.mdx Errors Errors schema — API Protocol reference 38 / 52 = before
references/api/events.mdx Events Events schema — API Protocol reference 38 / 52 = before
references/api/export.mdx Export Export schema — API Protocol reference 38 / 52 = before
references/api/http-cache.mdx Http Cache Http Cache schema — API Protocol reference 42 / 56 = before
references/api/metadata.mdx Metadata Metadata schema — API Protocol reference 40 / 54 = before
references/api/misc.mdx Misc Misc schema — API Protocol property reference 45 / 59 = before
references/api/odata.mdx Odata Odata schema — API Protocol property reference 46 / 60 = before
references/api/package-api-assembled.mdx Package Api Assembled Package Api Assembled — API Protocol reference 46 / 60 = before
references/api/package-api.mdx Package Api Package Api schema — API Protocol reference 43 / 57 = before
references/api/package-lifecycle.mdx Package Lifecycle Package Lifecycle — API Protocol reference 42 / 56 = before
references/api/plugin-rest-api.mdx Plugin Rest Api Plugin Rest Api — API Protocol reference 40 / 54 = before
references/api/protocol.mdx Protocol Protocol schema — API Protocol reference 40 / 54 = before
references/api/query-adapter.mdx Query Adapter Query Adapter schema — API Protocol reference 45 / 59 = before
references/api/realtime-shared.mdx Realtime Shared Realtime Shared — API Protocol reference 40 / 54 = before
references/api/realtime.mdx Realtime Realtime schema — API Protocol reference 40 / 54 = before
references/api/rest-server.mdx Rest Server Rest Server schema — API Protocol reference 43 / 57 = before
references/api/router.mdx Router Router schema — API Protocol reference 38 / 52 = before
references/api/sortability.mdx Sortability Sortability schema — API Protocol reference 43 / 57 = before
references/api/storage.mdx Storage Storage schema — API Protocol reference 39 / 53 = before
references/api/versioning.mdx Versioning Versioning schema — API Protocol reference 42 / 56 = before
references/api/websocket.mdx Websocket Websocket schema — API Protocol reference 41 / 55 = before
references/automation/index.mdx Automation Protocol Automation Protocol — schema reference 38 / 52 = before
references/automation/approval.mdx Approval Approval — Automation Protocol reference 40 / 54 = before
references/automation/bpmn-interop.mdx Bpmn Interop Bpmn Interop — Automation Protocol reference 44 / 58 = before
references/automation/builtin-node-config.mdx Builtin Node Config Builtin Node Config — Automation Protocol 41 / 55 = before
references/automation/control-flow.mdx Control Flow Control Flow — Automation Protocol reference 44 / 58 = before
references/automation/execution.mdx Execution Execution — Automation Protocol reference 41 / 55 = before
references/automation/flow-function.mdx Flow Function Flow Function — Automation Protocol reference 45 / 59 = before
references/automation/flow.mdx Flow Flow schema — Automation Protocol reference 43 / 57 = before
references/automation/io-node-config.mdx Io Node Config Io Node Config — Automation Protocol reference 46 / 60 = before
references/automation/node-executor.mdx Node Executor Node Executor — Automation Protocol reference 45 / 59 = before
references/automation/schedule-organization.mdx Schedule Organization Schedule Organization — Automation Protocol 43 / 57 = before
references/automation/schemaless-node-config.mdx Schemaless Node Config Schemaless Node Config — Automation Protocol 44 / 58 = before
references/automation/state-machine.mdx State Machine State Machine — Automation Protocol reference 45 / 59 = before
references/automation/time-relative-trigger.mdx Time Relative Trigger Time Relative Trigger — Automation Protocol 43 / 57 = before
references/automation/webhook.mdx Webhook Webhook schema — Automation Protocol reference 46 / 60 = before
references/data/index.mdx Data Protocol Data Protocol — complete schema reference 41 / 55 = before
references/data/analytics.mdx Analytics Analytics schema — Data Protocol reference 42 / 56 = before
references/data/context-tokens.mdx Context Tokens Context Tokens — Data Protocol reference 40 / 54 = before
references/data/data-engine.mdx Data Engine Data Engine schema — Data Protocol reference 44 / 58 = before
references/data/datasource.mdx Datasource Datasource schema — Data Protocol reference 43 / 57 = before
references/data/date-macros.mdx Date Macros Date Macros schema — Data Protocol reference 44 / 58 = before
references/data/document.mdx Document Document schema — Data Protocol reference 41 / 55 = before
references/data/driver-common.mdx Driver Common Driver Common schema — Data Protocol reference 46 / 60 = before
references/data/driver-memory.mdx Driver Memory Driver Memory schema — Data Protocol reference 46 / 60 = before
references/data/driver-mongo.mdx Driver Mongo Driver Mongo schema — Data Protocol reference 45 / 59 = before
references/data/driver-mysql.mdx Driver Mysql Driver Mysql schema — Data Protocol reference 45 / 59 = before
references/data/driver-nosql.mdx Driver Nosql Driver Nosql schema — Data Protocol reference 45 / 59 = before
references/data/driver-postgres.mdx Driver Postgres Driver Postgres — Data Protocol reference 41 / 55 = before
references/data/driver-sql.mdx Driver Sql Driver Sql schema — Data Protocol reference 43 / 57 = before
references/data/driver-sqlite.mdx Driver Sqlite Driver Sqlite schema — Data Protocol reference 46 / 60 = before
references/data/driver-turso.mdx Driver Turso Driver Turso schema — Data Protocol reference 45 / 59 = before
references/data/driver.mdx Driver Driver schema — Data Protocol reference 39 / 53 = before
references/data/external-catalog.mdx External Catalog External Catalog — Data Protocol reference 42 / 56 = before
references/data/feed.mdx Feed Feed schema — Data Protocol reference 37 / 51 = before
references/data/field-value.mdx Field Value Field Value schema — Data Protocol reference 44 / 58 = before
references/data/field.mdx Field Field schema — Data Protocol reference 38 / 52 = before
references/data/filter.mdx Filter Filter schema — Data Protocol reference 39 / 53 = before
references/data/hook-body.mdx Hook Body Hook Body schema — Data Protocol reference 42 / 56 = before
references/data/hook.mdx Hook Hook schema — Data Protocol property reference 46 / 60 = before
references/data/mapping.mdx Mapping Mapping schema — Data Protocol reference 40 / 54 = before
references/data/object.mdx Object Object schema — Data Protocol reference 39 / 53 = before
references/data/query.mdx Query Query schema — Data Protocol reference 38 / 52 = before
references/data/seed-loader.mdx Seed Loader Seed Loader schema — Data Protocol reference 44 / 58 = before
references/data/seed.mdx Seed Seed schema — Data Protocol property reference 46 / 60 = before
references/data/validation.mdx Validation Validation schema — Data Protocol reference 43 / 57 = before
references/identity/index.mdx Identity Protocol Identity Protocol — complete schema reference 45 / 59 = before
references/identity/eval-user.mdx Eval User Eval User schema — Identity Protocol reference 46 / 60 = before
references/identity/identity.mdx Identity Identity schema — Identity Protocol reference 45 / 59 = before
references/identity/organization.mdx Organization Organization — Identity Protocol reference 42 / 56 = before
references/identity/position.mdx Position Position schema — Identity Protocol reference 45 / 59 = before
references/identity/scim.mdx Scim Scim schema — Identity Protocol reference 41 / 55 = before
references/integration/index.mdx Integration Protocol Integration Protocol — schema reference 39 / 53 = before
references/integration/connector.mdx Connector Connector — Integration Protocol reference 42 / 56 = before
references/kernel/index.mdx Kernel Protocol Kernel Protocol — complete schema reference 43 / 57 = before
references/kernel/cli-extension.mdx Cli Extension Cli Extension — Kernel Protocol reference 41 / 55 = before
references/kernel/cluster.mdx Cluster Cluster schema — Kernel Protocol reference 42 / 56 = before
references/kernel/context.mdx Context Context schema — Kernel Protocol reference 42 / 56 = before
references/kernel/dependency-resolution.mdx Dependency Resolution Dependency Resolution — Kernel Protocol 39 / 53 = before
references/kernel/events-bus.mdx Events Bus Events Bus schema — Kernel Protocol reference 45 / 59 = before
references/kernel/events-core.mdx Events Core Events Core schema — Kernel Protocol reference 46 / 60 = before
references/kernel/events-dlq.mdx Events Dlq Events Dlq schema — Kernel Protocol reference 45 / 59 = before
references/kernel/events-handlers.mdx Events Handlers Events Handlers — Kernel Protocol reference 43 / 57 = before
references/kernel/events-integrations.mdx Events Integrations Events Integrations — Kernel Protocol 37 / 51 = before
references/kernel/events-queue.mdx Events Queue Events Queue — Kernel Protocol reference 40 / 54 = before
references/kernel/execution-context.mdx Execution Context Execution Context — Kernel Protocol reference 45 / 59 = before
references/kernel/manifest.mdx Manifest Manifest schema — Kernel Protocol reference 43 / 57 = before
references/kernel/metadata-loader.mdx Metadata Loader Metadata Loader — Kernel Protocol reference 43 / 57 = before
references/kernel/metadata-plugin.mdx Metadata Plugin Metadata Plugin — Kernel Protocol reference 43 / 57 = before
references/kernel/metadata-protection.mdx Metadata Protection Metadata Protection — Kernel Protocol 37 / 51 = before
references/kernel/package-artifact.mdx Package Artifact Package Artifact — Kernel Protocol reference 44 / 58 = before
references/kernel/package-registry.mdx Package Registry Package Registry — Kernel Protocol reference 44 / 58 = before
references/kernel/package-upgrade.mdx Package Upgrade Package Upgrade — Kernel Protocol reference 43 / 57 = before
references/kernel/plugin-capability.mdx Plugin Capability Plugin Capability — Kernel Protocol reference 45 / 59 = before
references/kernel/plugin-lifecycle-advanced.mdx Plugin Lifecycle Advanced Plugin Lifecycle Advanced — Kernel Protocol 43 / 57 = before
references/kernel/plugin-loading.mdx Plugin Loading Plugin Loading — Kernel Protocol reference 42 / 56 = before
references/kernel/plugin-registry.mdx Plugin Registry Plugin Registry — Kernel Protocol reference 43 / 57 = before
references/kernel/plugin-security-advanced.mdx Plugin Security Advanced Plugin Security Advanced — Kernel Protocol 42 / 56 = before
references/kernel/plugin-security.mdx Plugin Security Plugin Security — Kernel Protocol reference 43 / 57 = before
references/kernel/plugin-structure.mdx Plugin Structure Plugin Structure — Kernel Protocol reference 44 / 58 = before
references/kernel/plugin-validator.mdx Plugin Validator Plugin Validator — Kernel Protocol reference 44 / 58 = before
references/kernel/plugin-versioning.mdx Plugin Versioning Plugin Versioning — Kernel Protocol reference 45 / 59 = before
references/kernel/plugin.mdx Plugin Plugin schema — Kernel Protocol reference 41 / 55 = before
references/kernel/service-registry.mdx Service Registry Service Registry — Kernel Protocol reference 44 / 58 = before
references/kernel/startup-orchestrator.mdx Startup Orchestrator Startup Orchestrator — Kernel Protocol 38 / 52 = before
references/marketplace/index.mdx Marketplace Protocol Marketplace Protocol — schema reference 39 / 53 = before
references/marketplace/marketplace.mdx Marketplace Marketplace — Marketplace Protocol reference 44 / 58 = before
references/marketplace/package-version.mdx Package Version Package Version — Marketplace Protocol 38 / 52 = before
references/marketplace/package.mdx Package Package — Marketplace Protocol reference 40 / 54 = before
references/marketplace/template-manifest.mdx Template Manifest Template Manifest — Marketplace Protocol 40 / 54 = before
references/qa/index.mdx QA Protocol QA Protocol — complete schema reference 39 / 53 = before
references/qa/testing.mdx Testing Testing schema — QA Protocol reference 38 / 52 = before
references/security/index.mdx Security Protocol Security Protocol — complete schema reference 45 / 59 = before
references/security/explain.mdx Explain Explain schema — Security Protocol reference 44 / 58 = before
references/security/misc.mdx Misc Misc schema — Security Protocol reference 41 / 55 = before
references/security/permission.mdx Permission Permission — Security Protocol reference 40 / 54 = before
references/security/rls.mdx Rls Rls schema — Security Protocol reference 40 / 54 = before
references/security/sharing.mdx Sharing Sharing schema — Security Protocol reference 44 / 58 = before
references/shared/index.mdx Shared Protocol Shared Protocol — complete schema reference 43 / 57 = before
references/shared/duration.mdx Duration Duration schema — Shared Protocol reference 43 / 57 = before
references/shared/enums.mdx Enums Enums schema — Shared Protocol reference 40 / 54 = before
references/shared/epoch.mdx Epoch Epoch schema — Shared Protocol reference 40 / 54 = before
references/shared/expression.mdx Expression Expression schema — Shared Protocol reference 45 / 59 = before
references/shared/http.mdx Http Http schema — Shared Protocol reference 39 / 53 = before
references/shared/identifiers.mdx Identifiers Identifiers schema — Shared Protocol reference 46 / 60 = before
references/shared/mapping.mdx Mapping Mapping schema — Shared Protocol reference 42 / 56 = before
references/shared/metadata-types.mdx Metadata Types Metadata Types — Shared Protocol reference 42 / 56 = before
references/shared/protection.mdx Protection Protection schema — Shared Protocol reference 45 / 59 = before
references/shared/value-domain.mdx Value Domain Value Domain — Shared Protocol reference 40 / 54 = before
references/studio/index.mdx Studio Protocol Studio Protocol — complete schema reference 43 / 57 = before
references/studio/flow-builder.mdx Flow Builder Flow Builder — Studio Protocol reference 40 / 54 = before
references/studio/object-designer.mdx Object Designer Object Designer — Studio Protocol reference 43 / 57 = before
references/studio/plugin.mdx Plugin Plugin schema — Studio Protocol reference 41 / 55 = before
references/system/index.mdx System Protocol System Protocol — complete schema reference 43 / 57 = before
references/system/app-install.mdx App Install App Install schema — System Protocol reference 46 / 60 = before
references/system/auth-config.mdx Auth Config Auth Config schema — System Protocol reference 46 / 60 = before
references/system/book.mdx Book Book schema — System Protocol reference 39 / 53 = before
references/system/cache.mdx Cache Cache schema — System Protocol reference 40 / 54 = before
references/system/collaboration.mdx Collaboration Collaboration — System Protocol reference 41 / 55 = before
references/system/core-services.mdx Core Services Core Services — System Protocol reference 41 / 55 = before
references/system/deploy-bundle.mdx Deploy Bundle Deploy Bundle — System Protocol reference 41 / 55 = before
references/system/dev-login.mdx Dev Login Dev Login schema — System Protocol reference 44 / 58 = before
references/system/disaster-recovery.mdx Disaster Recovery Disaster Recovery — System Protocol reference 45 / 59 = before
references/system/doc.mdx Doc Doc schema — System Protocol reference 38 / 52 = before
references/system/email-config.mdx Email Config Email Config — System Protocol reference 40 / 54 = before
references/system/email-template.mdx Email Template Email Template — System Protocol reference 42 / 56 = before
references/system/encryption.mdx Encryption Encryption schema — System Protocol reference 45 / 59 = before
references/system/environment-artifact.mdx Environment Artifact Environment Artifact — System Protocol 38 / 52 = before
references/system/http-server.mdx Http Server Http Server schema — System Protocol reference 46 / 60 = before
references/system/job.mdx Job Job schema — System Protocol reference 38 / 52 = before
references/system/license.mdx License License schema — System Protocol reference 42 / 56 = before
references/system/logging.mdx Logging Logging schema — System Protocol reference 42 / 56 = before
references/system/metadata-persistence.mdx Metadata Persistence Metadata Persistence — System Protocol 38 / 52 = before
references/system/metrics.mdx Metrics Metrics schema — System Protocol reference 42 / 56 = before
references/system/migration.mdx Migration Migration schema — System Protocol reference 44 / 58 = before
references/system/notification.mdx Notification Notification — System Protocol reference 40 / 54 = before
references/system/object-storage.mdx Object Storage Object Storage — System Protocol reference 42 / 56 = before
references/system/registry-config.mdx Registry Config Registry Config — System Protocol reference 43 / 57 = before
references/system/search-engine.mdx Search Engine Search Engine — System Protocol reference 41 / 55 = before
references/system/security-context.mdx Security Context Security Context — System Protocol reference 44 / 58 = before
references/system/settings-client.mdx Settings Client Settings Client — System Protocol reference 43 / 57 = before
references/system/settings-manifest.mdx Settings Manifest Settings Manifest — System Protocol reference 45 / 59 = before
references/system/stack-server.mdx Stack Server Stack Server — System Protocol reference 40 / 54 = before
references/system/supplier-security.mdx Supplier Security Supplier Security — System Protocol reference 45 / 59 = before
references/system/tenant.mdx Tenant Tenant schema — System Protocol reference 41 / 55 = before
references/system/tracing.mdx Tracing Tracing schema — System Protocol reference 42 / 56 = before
references/system/translation.mdx Translation Translation schema — System Protocol reference 46 / 60 = before
references/system/worker.mdx Worker Worker schema — System Protocol reference 41 / 55 = before
references/ui/index.mdx UI Protocol UI Protocol — complete schema reference 39 / 53 = before
references/ui/action-params.mdx Action Params Action Params schema — UI Protocol reference 44 / 58 = before
references/ui/action.mdx Action Action schema — UI Protocol property reference 46 / 60 = before
references/ui/app.mdx App App schema — UI Protocol property reference 43 / 57 = before
references/ui/bulk-action.mdx Bulk Action Bulk Action schema — UI Protocol reference 42 / 56 = before
references/ui/chart.mdx Chart Chart schema — UI Protocol property reference 45 / 59 = before
references/ui/component.mdx Component Component schema — UI Protocol reference 40 / 54 = before
references/ui/dashboard.mdx Dashboard Dashboard schema — UI Protocol reference 40 / 54 = before
references/ui/dataset.mdx Dataset Dataset schema — UI Protocol reference 38 / 52 = before
references/ui/expression-bindable-text-keys.mdx Expression Bindable Text Keys Expression Bindable Text Keys — UI Protocol 43 / 57 = before
references/ui/i18n.mdx I18n I18n schema — UI Protocol property reference 44 / 58 = before
references/ui/notification.mdx Notification Notification schema — UI Protocol reference 43 / 57 = before
references/ui/page.mdx Page Page schema — UI Protocol property reference 44 / 58 = before
references/ui/report.mdx Report Report schema — UI Protocol property reference 46 / 60 = before
references/ui/responsive.mdx Responsive Responsive schema — UI Protocol reference 41 / 55 = before
references/ui/sharing.mdx Sharing Sharing schema — UI Protocol reference 38 / 52 = before
references/ui/view.mdx View View schema — UI Protocol property reference 44 / 58 = before

Generated by Claude Code

Generated reference pages get a PRIMARY-KEYWORD — QUALIFIER title in the
36-46 character band from one ladder per page kind (lib/page-title.ts), and
keep their previous title as navTitle so the page tree is unchanged.

Claude-Session: https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH
Co-authored-by: Claude <noreply@anthropic.com>
gen:docs output only: every generated reference page's title line is
replaced by the rule-shaped title and a navTitle carrying the previous
title, so the page tree is unchanged.

Claude-Session: https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH
Co-authored-by: Claude <noreply@anthropic.com>
…ed tree

The merge of origin/main deferred content/docs/references/{data/field,
data/object,shared/value-domain,system/migration}.mdx to regeneration.
Regenerated with gen:schema + gen:docs on the merged sources: main's body
changes plus this branch's title/navTitle lines.

Claude-Session: https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 0283cb924a5e29f22fdf0db60bcaedeab3ead3f3 → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: a61335f93f40294f85d645e4efe8255b5ae589b8
Local-runs: none

Inputs read: card #15403 body and all 4 comments (serial note 5857122314, unlock 5862577206, claim 5863183456, os-dev-report 5865099529); PR #20401 body and its REST file listing (three pages, 215 files, served without refusal; the git three-dot diff against the merge base ab946560f names the same 215); the maintainer ruling 5419555720 on #12237 and the ## The rule section of PR #20170; the 39 check-runs on the head. Everything below is git show / git diff / git grep against fetched refs and REST GETs — nothing built, run or re-run.

① Derived judgments

  • Surface — right. 215 files: packages/spec/scripts/build-docs.ts (+40/−2), packages/spec/scripts/lib/root-index.ts (+4/−1), new packages/spec/scripts/lib/page-title.ts (+172), new packages/spec/scripts/page-title.test.ts (+170), and 211 pages under content/docs/references/**. No packages/spec/src/**, no meta.json, no authored page, no description: line, no check-generated.ts, no build-skill-docs.ts. Every one of the 211 content hunks is a single @@ -2 +2,2 @@ hunk: one title: line removed, a title: and a navTitle: line added.
  • The rule, on every regenerated title — right. Checked all 211 against the rule as landed in PR docs(content): apply the approved search-intent title rule to 169 authored pages, short nav labels kept via navTitle #20170 and ruled in 5419555720: length 37–46 (rendered with the 14-character suffix 51–60, none over 60), exactly one — separator, no ObjectStack in any title. Before: 0 of 211 in band (3–29 characters, median 11), 6 duplicate titles; after: 211 of 211, 0 duplicates. Rung tally reproduces the PR body exactly (module pages 19 / 102 / 60 / 15, category indexes 11 / 3, root 1). The rule's one declared exception (getting-started/index.mdx) is an authored page this diff does not reach.
  • navTitle keeps every sidebar label — right. On all 211 pages navTitle equals the removed title byte for byte. navLabel() in apps/docs/lib/nav-title.ts returns a non-blank navTitle unchanged, so every page-tree entry resolves to the string it showed before; folder labels come from meta.json, untouched. The dev's fumadocs replay (449 nodes, diff exit 0) is consistent with this and is not re-run.
  • Population — right, and the card's count corrected correctly. At the head content/docs/**/*.mdx = 406; pages carrying the generator's AUTO-GENERATED — DO NOT EDIT banner = 211, all under references/** (196 module, 14 category index, 1 root), every one in the diff and every one now carrying navTitle. The 14 content/docs/releases/** pages carry no banner. A looser marker regex also matches api/index.mdx and automation/approvals.mdx, but only on prose ("Auto-generated from the protocol", "they do not edit") — both are authored pages already in rule shape. 225/405 → 211/406 stands on this tree.
  • No other emitter writes a title into content/docs/** — right. The only other generator title: emission in the repo is build-react-blocks-contract.ts, which writes to skills/objectstack-ui/references/react-blocks.md. build-skill-docs.ts splices a marked body region of content/docs/ai/skills-reference.mdx and emits no title.
  • Refusal, not truncation — right. firstTitleInBand throws naming the page and every candidate; build-docs.ts wraps both of its sites in pageTitleOrExit (named exit-1). Observed, not a defect: root-index.ts calls rootIndexTitle() bare, so a future out-of-band root title would surface as a thrown error rather than the named exit — the root string is fixed at 43 characters and pinned by the unit test.
  • Gate verdicts, from the head's check-runs — all green. 39 runs, all completed: 33 success, 6 skipped. The skipped six are the two opt-in Packed-tarball smoke jobs, Console Pin Gate, and the three jobs of a duplicate PR Automation run (36389460863) whose sibling run on the same head (36389404418) has Check Changeset, Check PR Size and Auto Label success. Mapped by workflow line: the drift gate check:docs runs in Type Check · source gates (success); check-doc-frontmatter and check-docs-nav-label in Lint & Repo Gates (success); turbo run typecheck (spec's typecheck = tsc --noEmit + check:scripts-typecheck + check:test-typecheck) in Type Check · workspace (success); the spec local vitest project includes scripts/**/*.test.ts, so page-title.test.ts ran under Test Core 6/6 (success).
  • Fixed-word accuracy (the dev's open question, judged as fact). schema (121 rung-1/2 pages): every page documents Zod schemas from a .zod.ts with a TypeScript Usage block and per-schema sections — accurate. reference: all under references/ — accurate. complete schema reference (11) / schema reference (3): each category index enumerates every module page of its category as cards — accurate. Root Protocol reference — every schema by module: a module table with page and schema counts — accurate. property reference (19 rung-1 pages): 18 carry ### Properties tables; content/docs/references/data/feed.mdx does not — it documents two enums (FeedFilterMode, FeedItemType, "Allowed Values" only) and a const tuple, so Feed schema — Data Protocol property reference names a property reference the page is not. One title of 211 misdescribes its page; the remedy is a rung condition or a different rung-1 word in lib/page-title.ts plus gen:docs, never a hand edit. Escalated in ③.
  • Concurrency fact, not a head defect. origin/main (df3ba164) is 10 commits past the merge base and regenerated content/docs/references/security/{permission,rls}.mdx; GitHub reports the PR mergeable and clean. The merged tree's check:docs is the queue's; the later lander re-merges with scripts/pm/os-regen-merge.sh, as the claim comment anticipated.

② Semver level

  • skip-changeset — right. AGENTS.md reserves the label for a diff that publishes nothing from any released package. @objectstack/spec publishes dist, json-schema, liveness, prompts, llms.txt, README.md, src/**/*.zod.ts, CHANGELOG.md, api-surface, spec-changes.json; this diff touches packages/spec/scripts/** (a tsx-run generator and its test, not published) and content/docs/** (rendered by the private apps/docs). llms.txt is hand-kept and not in the diff. No packages/spec/src/** change. Check Changeset is success on the head.
  • Clause-②: no — right. No authorable key, export or schema is widened or narrowed; the PR body carries the line.

③ Boundary flags

  • Extra emitter site lib/root-index.ts — accepted. It is the generator's third title: emission (references/index.mdx, previously 18 characters); leaving it would leave one generated page outside the rule. Same package, same generator run.
  • New module lib/page-title.ts and page-title.test.ts — accepted. The claim named "the emitter's tests"; the module is the one pure function the suggested route asked for, and the test runs in the spec local project (Test Core green on the head). The test pins the band, the separator, no site name, longest-first ladder order, totality over every declared category, same-name disambiguation and the named refusal.
  • Count corrected 225/405 → 211/406 — verified independently (see ①).
  • skip-changeset — right (see ②).
  • Typecheck narrowed locally to check:scripts-typecheck at the final head — discharged by CI. Type Check · workspace ran the full per-package typecheck on a61335f9 (success); the narrowing was local only and declared.
  • Four derived gates NOT MEASURED locally — each answered by a head check-run: check:skill-examples → Type Check · consumer gates success; check:dual-build-cjs-loads → Build Core success; check:type-check-debt → Type Check · debt ledger success; check:pm-dispatch-gates → Lint & Repo Gates success.
  • Commit trailers — right. The three authored commits end with the AGENTS.md model-free pair (session URL plus co-author line). The merge commit 9da41cee carries the git merge --no-edit default that os-regen-merge.sh step 1 produces — the repo's own tool shape. No model identifier in the PR title, body or dev report; the PR footer is the session-URL form.
  • Out-of-scope finding (abbreviation casing Mcp, Odata, I18n, Scim, …) — not a breach here. Pre-existing from zodTitle; the card keeps those strings byte-identical as navTitle. It now also heads the search-facing title on those pages. Carrier none; a follow-up card is the seat's call.
  • Open question (fixed words: land as shipped vs hold for rewording) — answered as fact, decision escalated to the seat. The words are accurate for 210 of 211 pages; the one exception is data/feed.mdx (property reference on an enum-only page). Option A as shipped lands that one misnomer; either a rung fix on this PR before enqueue (one condition in lib/page-title.ts plus gen:docs, held by the unit pin and check:docs) or a follow-up under option A closes it. Option B holds all 211 out of band meanwhile. The landing choice is the seat's.

Implemented-by: claude/issue-15403-generator-title-rule
Reviewed-by: session_01ARcDurZ5j34RdqsGgc4jgH

VERDICT: PASS


Generated by Claude Code

…th a Properties table

An enum-only module (data/feed) rendered no Properties table yet took the
'property reference' rung. The rung now reads rendersPropertiesTable(), the
section renderer's own condition, shared through declaresProperties(); a
page without a table starts at the next rung. Pinned in page-title.test.ts,
including agreement with renderSchemaSection per schema shape.

Claude-Session: https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH
Co-authored-by: Claude <noreply@anthropic.com>
…reference rung

gen:docs output only: data/feed renders two enums and no Properties
table, so its title drops to the next rung. No other page moves.

Claude-Session: https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH
Co-authored-by: Claude <noreply@anthropic.com>
…tree

The merge of origin/main deferred these two generated pages. Regenerated
with gen:schema + gen:docs on the merged sources: main's retired-key rows
plus this branch's title/navTitle lines.

Claude-Session: https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 1ba9d84cead7a7158e655d6abcc715f49b1042c0
Local-runs: none

Inputs read: card #15403 body and all 6 comments (serial note 5857122314, unlock 5862577206, claim 5863183456, round-0 os-dev-report 5865099529, REWORK round 1 5865474678, round-1 os-dev-report 5866083524); PR #20401 body; its REST file listing (three pages, 100 + 100 + 16 = 216, served without refusal — the git three-dot diff from base df3ba164 to the head names the same 216, no file either way); the net diff; the 42 check-runs on the head. The round-0 PASS record 5865465586 on the PR was read for what it measured at a61335f9, not adopted. Everything below is git show / git diff / git grep against fetched refs and REST GETs — nothing built, run or re-run.

① Derived judgments

  • Surface — right. 216 files: five under packages/spec/scripts/ (build-docs.ts +48/−3, lib/page-title.ts new +191, lib/root-index.ts +4/−1, lib/schema-section.ts +36/−5, page-title.test.ts new +256) and 211 pages under content/docs/references/**. Every one of the 211 page diffs is the single hunk @@ -2 +2,2 @@: one title: line removed, a title: and a navTitle: line added — checked line by line, no other removal or addition on any page. No packages/spec/src/**, no meta.json, no authored page, no description: line, no .changeset/ entry, no check-generated.ts, no build-skill-docs.ts.
  • The owed item — held on every regenerated page. property reference now lands on 18 pages and each of the 18 renders at least one ### Properties heading. content/docs/references/data/feed.mdx (two string enums, ### Allowed Values only, no ### Properties) reads Feed schema — Data Protocol reference (37, rendered 51). It is the only title that moved between a61335f9 and this head; no navTitle moved. Rung tally a61335f9 to 1ba9d84c: module pages 19 / 102 / 60 / 15 to 18 / 103 / 60 / 15, category index 11 / 3, root 1 — the report's and the PR body's numbers reproduce. The 14 module pages rendering no Properties table sit on rungs 2–4 (7 / 3 / 4). Replaying the ladders from each page's navTitle, its category's declared title and the Properties fact read off the page reproduces all 196 module titles, all 14 category-index titles and the root with zero mismatches; on the 19 pages where rung 1 fits the band, rung 1 taken equals Properties table present on all 19.
  • The rule on all 211 — holds. Lengths 37–46 (min 37 / median 43 / max 46; rendered with the 14-character suffix 51–60, none over 60); exactly one — on every title; ObjectStack in none; 0 duplicates among the 211 and 406 distinct titles across all 406 content/docs pages. navTitle equals the base tree's title byte for byte on all 211 (the base carried no navTitle anywhere); navLabel() in apps/docs/lib/nav-title.ts returns a non-blank navTitle unchanged, so every page-tree label is the string it was. The dev's fumadocs replay (449 nodes, diff exit 0) is consistent with this and not re-run. Before, at the base: 0 of 211 in band (3–29, median 11), 0 with the separator, 6 duplicate titles (Analytics, Mapping, Misc, Notification, Plugin, Sharing) — the PR body's before row reproduces.
  • The predicate is the renderer's own condition — right, and rendered output is unchanged. rendersPropertiesTable walks renderSchemaSection's branches in the renderer's order on the same selectRootDef root: an object root that declares properties renders the table; a string enum renders Allowed Values only (tested before the union, as the renderer does); a union renders a ### Properties table for each arm that declaresProperties; every other root renders one type line. The renderer emits ### Properties from exactly those two positions (the nested-shape table passes an empty heading), so the predicate cannot miss a table a page renders. selectRootDef never returns undefined (coded to fall back to the document). build-docs.ts asks the predicate of the same {name, content} pairs the section loop renders (schemas.some(...) at :529, schemas.forEach at :579). The three renderer checks rewritten to declaresProperties() are the same truth test (type === 'object' and truthy properties), so the report's claim that regeneration moved only feed.mdx's title line is borne out by the diff itself: no body line moved on any of the 211 pages, and check:docs is green on the head. The 1523-schema, 0-disagreement sweep is the dev's measurement and is not re-run; the page-level agreement above is its read-only equivalent.
  • Population — right. Pages carrying the exact generator banner AUTO-GENERATED — DO NOT EDIT: 211 at the base and at the head, all under references/, all in the diff, all now carrying navTitle. content/docs/**/*.mdx = 406; the 14 releases/** pages carry no banner. (A loose "generated" prose match reaches 222; the banner is the fact.) 225/405 to 211/406 stands on this tree.
  • Fixed-word accuracy — right, with the round-0 exception closed. schema (18 + 103 pages): each page documents the Zod schemas of one .zod.ts with a TypeScript Usage block and per-schema ## sections, the property-less ones included (spot-checked data/date-macros.mdx). reference: all under references/. complete schema reference (11) / schema reference (3): each category index enumerates every module page of its category as cards (ai/: 12 cards, 12 module pages). Root Protocol reference — every schema by module: a module table with page and schema counts. property reference (18): every page renders a Properties table.
  • Gate verdicts from the head's check-runs — all green. 42 runs, all completed: 36 success, 6 skipped, 0 failure. The skipped six: Console Pin Gate (the path filter reports no console path), Packed-tarball smoke (opt-in), Check Changeset in both PR Automation runs (the job's if excludes a PR carrying skip-changeset), and Check PR Size / Auto Label in the second PR Automation run (created 08:16:35Z on the same head by a non-synchronize action, which both jobs exclude by if; the sibling run at 07:47:50Z has both success). Mapped by workflow line: check:docs runs in Type Check · source gates (lint.yml :5564, success); check-doc-frontmatter and check:docs-single-h1 in Lint & Repo Gates (success); the spec local vitest project includes scripts/**/*.test.ts, so page-title.test.ts ran under Test Core 6/6 (success); turbo run typecheck (spec's tsc --noEmit plus check:scripts-typecheck plus check:test-typecheck) in Type Check · workspace (success). Also success: TypeScript Type Check, Build Core, Build Docs, the three Dogfood Regression Gate shards and Dogfood Verify CLI, Temporal Conformance, Governed Surface Queue Guard, Spec property liveness, Check Documentation Links, Flag docs affected, and the four claim guards.
  • Concurrency fact, not a head defect. origin/main is one commit past the merge base (dcd3bcea, feat(spec)!: retire action.aria — no action renderer ever applied it (ADR-0049) #20398), touching body lines of three generated pages (data/object, kernel/metadata-plugin, ui/action); GitHub reports the PR mergeable and clean. The two pages main regenerated before this round's merge (security/{permission,rls}) carry main's body rows plus this branch's two frontmatter lines — their net hunk is the same -2 +2,2. The merged tree's check:docs is the queue's; the later lander re-merges with scripts/pm/os-regen-merge.sh, as the claim anticipated.

② Semver level

  • skip-changeset — right. AGENTS.md reserves the label for a diff that publishes nothing from any released package. @objectstack/spec (17.4.0) publishes dist, json-schema, liveness, prompts, llms.txt, README.md, src/**/*.zod.ts, CHANGELOG.md, api-surface, spec-changes.json; this diff touches only packages/spec/scripts/** (the tsx-run generator, its lib and its test, outside files[]) and content/docs/** (rendered by @objectstack/docs, private: true). No file under any published path is in the diff, and there is no .changeset/ entry. The label is on the PR; Check Changeset is skipped by that label, which is the gate honouring the declaration rather than judging it — the judgment here is independent of it.
  • Clause-②: no — right. The PR body carries the line. No authorable key, export, schema or src/** surface is widened or narrowed; the new exports (declaresProperties, rendersPropertiesTable, the page-title module) live in unpublished scripts.

③ Boundary flags

  • Round-1 open_questions — none declared. The round-0 question (fixed words: land as shipped or hold) was answered A by the seat in 5865474678; the wording is judged accurate above and stays listed in the PR as non-blocking.
  • File surface +1 this round, lib/schema-section.ts — accepted. The seat's order asked for a condition the generator can check; the renderer's own predicate is the one place that answers it, and the rendered bytes are unchanged (① above). Round 0's surface additions (lib/root-index.ts as the third emission site, lib/page-title.ts, page-title.test.ts) stand as accepted in 5865465586 and are re-verified on this head.
  • Ladder coverage without the first rung is 16–43, not 7–43 — accepted, fact stated. The shortest property-less pair on the tree is 17 (Feed plus Data Protocol). A future property-less module whose name plus category is 15 or less stops gen:docs with a named refusal (pinned in the test) rather than a truncated or padded title — the refusal-not-truncation design round 0 accepted. No current page is affected.
  • Optional rootIndexTitle() routing through pageTitleOrExit not taken — accepted. The seat made it conditional on being one line; it is not (the title would have to be threaded into renderRootIndex's input and its fixtures). The root title is a fixed 43-character string pinned by the test.
  • Not merged a second time after dcd3bcea — accepted as the concurrency fact in ①; the PR is mergeable and clean.
  • Full spec typecheck not re-run locally — discharged by CI. Type Check · workspace and TypeScript Type Check are success on 1ba9d84c.
  • Four derived gates NOT MEASURED locally — each answered by a head check-run: check:skill-examples by Type Check · consumer gates, check:dual-build-cjs-loads by Build Core, check:type-check-debt by Type Check · debt ledger, check:pm-dispatch-gates by Lint & Repo Gates — all success.
  • Merge commit 23f0d0b5 carries git's default message — accepted, the shape os-regen-merge.sh step 1 produces, as in round 0.
  • Commit trailers — right. The three authored commits this round (41b0f683, 0ea42f45, 1ba9d84c) end with the AGENTS.md model-free pair. No model identifier in any of the eight commit messages, the PR title or body, or either dev report. No control bytes in the five source files.
  • Out-of-scope finding (api/protocol.mdx renders 6 header-only Properties tables) — not a breach. 132 tables and 6 header-only at the base and at the head alike: pre-existing renderer output, and that page is on rung 2 with non-empty tables too. Carrier none; a follow-up card is the seat's call. The round-0 abbreviation-casing finding (Mcp, Odata, I18n, Scim, …) is unchanged and remains out of scope, those strings being the byte-identical navTitle.
  • navTitle plumbing unchanged and sufficient. The key is declared optional string on the docs schema (source.config.ts:44), typed by check-doc-frontmatter.mjs, and read only by navLabel(); the generator writes it as a plain scalar on every page.

Implemented-by: claude/issue-15403-generator-title-rule
Reviewed-by: session_01ARcDurZ5j34RdqsGgc4jgH

VERDICT: PASS


Generated by Claude Code

…action on the merged tree

The merge of origin/main deferred these three generated pages. Regenerated
with gen:schema + gen:docs on the merged sources: main's body changes plus
this branch's unchanged title/navTitle lines.

Claude-Session: https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Regen-provenance: 5866297461 · 1ba9d84c → 2da3e239 · diff <(git diff df3ba164...1ba9d84c -- . ':!content/docs/references') <(git diff 2c310705...2da3e239 -- . ':!content/docs/references') → (empty)

domain:spec seat 4 (session_01ARcDurZ5j34RdqsGgc4jgH) · 2026-09-28T09:19Z. One pure-regeneration hop: ce03af2c merges origin/main 2c310705 through scripts/pm/os-regen-merge.sh, and 2da3e239 regenerates three reference pages on the merged tree (dev report on #15403). The command above was run by this seat on the committed trees. The five packages/spec/scripts/** files are byte-identical in the PR's diff before and after the hop; only generated pages under content/docs/references/** moved. CI at 2da3e239: 32 success, 3 skipped.

⚠️ Not landing yet. PR #20344 (in the merge queue) also changes content/docs/references/automation/schemaless-node-config.mdx. Once it is MERGED, this PR gets one more regeneration lap before the queue (landing rule A), and that lap adds a second hop line here.

domain:spec seat 4 · #18917 · session_01ARcDurZ5j34RdqsGgc4jgH


Generated by Claude Code

The merge of origin/main deferred automation/schemaless-node-config,
data/analytics, index, integration/connector and system/auth-config.
Regenerated with gen:schema + gen:docs on the merged sources: main's body
changes plus this branch's unchanged title/navTitle lines.

Claude-Session: https://claude.ai/code/session_01ARcDurZ5j34RdqsGgc4jgH
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Regen-provenance: 5866297461 · 2da3e239 → 1773c29a · diff <(git diff 2c310705...2da3e239 -- . ':!content/docs/references') <(git diff 0283cb92...1773c29a -- . ':!content/docs/references') → (empty)

domain:spec seat 4 (session_01ARcDurZ5j34RdqsGgc4jgH) · 2026-09-28T11:15Z. This is the second pure-regeneration hop, continuing 5867040613 (1ba9d84c → 2da3e239). a0e8590e merges origin/main 0283cb92 (#20344 among it) through scripts/pm/os-regen-merge.sh, and 1773c29a regenerates the five deferred reference pages on the merged tree (dev report on #15403). The command above was run by this seat on the committed trees. The five packages/spec/scripts/** files are byte-identical in the PR's diff; only generated pages under content/docs/references/** moved, and no title or navTitle changed. git merge-tree --write-tree origin/main 1773c29a is clean at dbddf02c.

domain:spec seat 4 · #18917 · session_01ARcDurZ5j34RdqsGgc4jgH


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 28, 2026 11:27
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 28, 2026
Merged via the queue into main with commit e4d3f2c Sep 28, 2026
37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xl skip-changeset PR has no user-facing published change; bypasses the changeset gate tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs(spec): carry the page-title rule into the docs GENERATOR — 225 of 405 pages are emitted, so a hand edit is reverted (split (b) of #12237)

2 participants