Skip to content

docs(spec): name only the OpenAPI document where the retired /docs viewer page was named - #25162

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-7afd2e
Oct 22, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-7afd2e

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Bill · project thread

Fixes #25121

Clause-②: no
Metadata-protocol: none

What changed

main no longer serves the OpenAPI document's HTML viewer page (GET {basePath}/docs, retired by PR #25124, 1b3b65e64). registerRoutes gates registerOpenApiEndpoints on api.enableOpenApi, and that registrar now mounts one route, GET {basePath}/openapi.json (packages/rest/src/discovery-routes.ts, read at origin/main 23540582f). The spec text that still named the viewer now names the OpenAPI document only:

Site Before After
rest-server.zod.ts, enableOpenApi TSDoc openapi.json plus "GET {basePath}/docs for a zero-dep Scalar-rendered HTML viewer" the one endpoint, GET {basePath}/openapi.json
rest-server.zod.ts, enableOpenApi describe "Enable OpenAPI 3.1 spec & docs viewer endpoints" "Enable the OpenAPI 3.1 document endpoint (GET BASEPATH/openapi.json)"
rest-server.zod.ts, documentation.enabled tombstone prescription "…leaves the /openapi.json document and its /docs viewer unmounted." "…leaves the /openapi.json document unmounted."
liveness/rest_api.json, enableOpenApi evidence "mounts both /openapi.json and the /docs viewer" "mounts /openapi.json, the OpenAPI document"; verifiedAt restamped 2026-10-22 (call graph re-closed against origin/main)
scripts/lib/openapi-self-consistency.ts, rule 1 comment and the dangling-ref refusal named "the Scalar viewer at GET /api/v1/docs" as a consumer names the document at GET /api/v1/openapi.json and client generators
migrations/entries/semantic/18.rest-api-config-dead-keys-retired.ts, replacement and acceptanceCriteria "the OpenAPI document and the docs viewer", "GET /openapi.json and GET /docs unmounted" the OpenAPI document only, "GET /openapi.json unmounted"

Regenerated: gen:schema (no tracked change), gen:docs → content/docs/references/api/rest-server.mdx (the two describe rows and the prescription row). One patch changeset for @objectstack/spec: .changeset/25121-spec-openapi-viewer-prose.md.

The documentation.enabled refusal is an accept-set no-op: same key refused, same issue path, same opening sentence; only its last clause changed. The two pins that read the prescription (packages/spec/src/api/rest-api-config-dead-keys-retirement.test.ts DOCS_ENABLED_PRESCRIPTION and packages/rest/src/rest-api-config-dead-keys-refused.test.ts) match up to "api.enableOpenApi: false is the switch", which the new text keeps, so neither needed a flip. Both are green below.

Tests (at 32bfe10cd, the final head)

  • pnpm --filter @objectstack/spec test (lock VERDICT command-exit 0): Test Files 706 passed (706), Tests 21462 passed, 1 todo.
  • pnpm --filter @objectstack/spec typecheck (lock VERDICT command-exit 0).
  • pnpm --filter @objectstack/rest exec vitest run --maxWorkers=2 src/rest-api-config-dead-keys-refused.test.ts src/rest-docs-viewer-retired.pin.test.ts (lock VERDICT command-exit 0): Test Files 2 passed, Tests 17 passed.
  • pnpm --filter @objectstack/spec check:generated: exit 0, all 14 artifacts up to date (it was red on check:docs before gen:docs).
  • No ablation: no tested behaviour changed (description, TSDoc, comment and prescription text only).

Gates

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 32bfe10cd derived 111 commands; each was run with its exit code recorded before any pipe. --ran reconciliation: "111 derived famil(ies) accounted for — 110 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)".

  • 110 exit 0. Five first exited 3 (prerequisite not met: the lint/formula, client-react and objectql dists were unbuilt, and check:exported-any / check:generated had read a spec dist while a concurrent turbo build was rewriting it). They were re-run green after the builds.
  • NOT MEASURED: pnpm check:dual-build-cjs-loads, exit 3. It needs every workspace package built, and this worktree built only the spec, lint, formula, objectql and client-react closures. Lint & Repo Gates runs it in CI.
  • Local-only families: check:skill-frame-freshness exit 0. check:dev-prereqs exit 1, NOT MEASURED: it reports "the workspace is not built" (33 of 70 packages have no dist) and names no stale spec dist. That is the box's state, not a finding.
  • CI-owned families (the farm, Test Core, Build Core, Build Docs, type-check lanes): this PR's check-runs.

Acceptance notes

  • Out of scope by the claim and untouched: ApiTestingUiConfigSchema (ApiDocumentationConfigSchema.ui, documentation.zod.ts, viewer enum including 'scalar') and OpenApiGenerationConfigSchema.uiPath (plugin-rest-api.zod.ts, default /api/docs, echoed by REST_API_PLUGIN.md). Measured at origin/main 23540582f, git grep -w outside packages/spec, the generated references and the changelogs finds no reader of either. ApiDocumentationConfig appears once, in a comment at packages/runtime/src/http-dispatcher.ts:3061. uiPath appears once, as an unrelated local variable at packages/rest/src/ui-routes.ts:79. RestApiPluginConfig in packages/rest is its own interface (rest-api-plugin.ts:94), not the spec schema. The seat files these as their own card.
  • The changeset .changeset/25077-rest-docs-viewer-attr-escape.md (already on main) describes a viewer fix to a page that has since been retired. It is release-owned input, so it is not touched here.

Generated by Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 2 documentable anchor(s). ⚠️ 1 changed file(s) yielded no anchor (packages/spec/liveness/rest_api.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

⛔ 1 release-owned page(s) name something this change touched. These are read-only:

  • content/docs/releases/v12.mdx (via RestApiConfigSchema (symbol, a top-level const))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/liveness/rest_api.json) — pages documenting those are invisible to this run
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 144 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 6b44efa7b4a429994dc6d92c3de96392d4e03f3f → packageMentionDocs.

Which tree this was computed on

This run read content/docs from c59414d9a56719bcd050a2679df8340e6d70dd09 — the merge of head 32bfe10cda2f5fdec1be6233b6f45e013ab256f6 into base 6b44efa7b4a429994dc6d92c3de96392d4e03f3f, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin c59414d9a56719bcd050a2679df8340e6d70dd09 && git checkout c59414d9a56719bcd050a2679df8340e6d70dd09
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 6b44efa7b4a429994dc6d92c3de96392d4e03f3f 32bfe10cda2f5fdec1be6233b6f45e013ab256f6 && git checkout -B drift-repro 6b44efa7b4a429994dc6d92c3de96392d4e03f3f && git merge --no-ff 32bfe10cda2f5fdec1be6233b6f45e013ab256f6

node scripts/docs-audit/affected-docs.mjs --json 6b44efa7b4a429994dc6d92c3de96392d4e03f3f

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 6b44efa7b4a429994dc6d92c3de96392d4e03f3f → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 32bfe10cda2f5fdec1be6233b6f45e013ab256f6
Local-runs: none
Scope: packages/spec/src/api/rest-server.zod.ts, packages/spec/src/migrations/entries/semantic/18.rest-api-config-dead-keys-retired.ts + packages/rest/src/discovery-routes.ts (registerOpenApiEndpoints), packages/rest/src/rest-server.ts (registerRoutes gate), packages/spec/src/api/rest-api-config-dead-keys-retirement.test.ts (DOCS_ENABLED_PRESCRIPTION), packages/rest/src/rest-api-config-dead-keys-refused.test.ts, packages/rest/src/rest-docs-viewer-retired.pin.test.ts, content/docs/references/api/rest-server.mdx (regenerated from the describe), packages/spec/liveness/rest_api.json

Face: published schema (rest-server.zod.ts). Inputs read: card #25121 body and all four comments (two pointers, the claim, the os-dev-report), PR #25162 body, file list and net diff against main at this head, the 39 check-runs on the head, and the cited code as committed blobs at the head. Not read: the dispatch order or any seat's own conclusions. The remainder of the diff (.changeset/25121-spec-openapi-viewer-prose.md, content/docs/references/api/rest-server.mdx, packages/spec/liveness/rest_api.json, packages/spec/scripts/lib/openapi-self-consistency.ts) is the lane seat's ACCEPT at TIER_DEFAULT; it is read here only where a hunk in scope makes a claim about it.

① Derived judgments

  1. RestApiConfigSchema.enableOpenApi describe — RIGHT. The published JSON-schema description string changes; the type (boolean), default (true) and key set do not, so the accept set is unchanged. The one tracked carrier of the describe text is content/docs/references/api/rest-server.mdx, regenerated in this diff (two table rows); a tree-wide search at the head finds the new text in exactly those two files and the old text ("Enable OpenAPI 3.1 spec & docs viewer endpoints", "Scalar-rendered") in no tracked file outside the changeset that quotes it and the release-owned changelogs. gen:schema reporting no tracked change is consistent with that.
  2. enableOpenApi TSDoc — RIGHT. Published declaration docblock only; no type moves. Its claim — one endpoint, GET BASEPATH/openapi.json — is true of the cited code: registerRoutes gates registerOpenApiEndpoints on api.enableOpenApi (rest-server.ts:4752), and registerOpenApiEndpoints in discovery-routes.ts makes exactly one routeManager.register call, for path BASEPATH/openapi.json; its header records the GET BASEPATH/docs viewer as retired (rest: the API docs viewer page loads a third-party script by an unpinned URL with no integrity check #25104). rest-docs-viewer-retired.pin.test.ts pins both halves on both route shapes.
  3. documentation.enabled tombstone prescription — RIGHT, and an accept-set no-op as the PR states. Same key refused, same retiredKey() tombstone, same issue path documentation.enabled / api.documentation.enabled, same invalid_type code, same opening sentence; only the closing clause changed. Both pins that read the message end their match at "api.enableOpenApi: false is the switch" (DOCS_ENABLED_PRESCRIPTION in the spec test, line 61; the rest test, line 101), which the new text keeps, so neither pin needed a flip and neither was touched. The new clause ("leaves the /openapi.json document unmounted") is what the rest pin measures at lines 198–204: with enableOpenApi: false the only route removed is GET /api/v1/openapi.json.
  4. Semantic entry 18 replacement and acceptanceCriteria — RIGHT. id and surface are unchanged, so the ADR-0087 registry key and the four ledger keys it covers are unchanged; only the prose os migrate meta and the generated upgrade guide show moved. "sees GET /openapi.json unmounted" is the same measured fact as item 3. docs/protocol-upgrade-guide.md is a pointer, not a generated copy, so no tracked artifact of this entry is stale.
  5. Liveness rest_api.json evidence (claimed by the prescription hunk) — RIGHT. "mounts /openapi.json, the OpenAPI document" matches the single registration in item 2; verifiedAt restamped to 2026-10-22 with the status still live and the producer unchanged. The head's Spec property liveness check-run is success.
  6. openapi-self-consistency.ts comment and refusal text — RIGHT. Gate-script prose and a refusal message, not a published surface; the one consumer it now names (GET /api/v1/openapi.json) is the one that exists. Lint · scoped · tooling self-tests is success on the head.
  7. Public-surface summary — no export added, removed or moved; no key added, removed or re-typed; no default changed; no refusal added or lifted. The diff publishes description text on @objectstack/spec only. The sweep claim in the report ("no further site in packages/spec") holds at the head: the remaining /docs-shaped hits in packages/spec are content/docs paths, the docs.objectstack.dev error URL and the two out-of-scope schemas (ApiTestingUiConfigSchema, OpenApiGenerationConfigSchema.uiPath), which the claim excludes and the card marks "noted, not decided".

② Semver level

.changeset/25121-spec-openapi-viewer-prose.md: '@objectstack/spec': patch, carrying Clause-②: no and Metadata-protocol: none line-initial; the PR body carries the same two lines. Judged against the diff: nothing an author can write is added, refused, tightened or re-meant, so Metadata-protocol: none is the kind, and none takes patch under AGENTS.md's level rule. Clause-②: no is TRUE — neither arm applies: the accept set of RestApiConfigSchema is identical before and after (item 3 is the only hunk on a refusal, and it changes the message's last clause only). skip-changeset would have been wrong: a released package's published description text moves. Check Changeset on the head is success. The changeset body carries no migration and owes none.

Clause-②: no — matches the diff.

③ Boundary flags

  • open_questions[0] — the PR body opens with an HTML-comment attribution line (claude-projects-attribution) while os-dev.md forbids HTML comments in GitHub text. Which governs? Answered: A, keep it. os-dev.md's clause (lines 18 and 322–326) guards two things: seat markers the PM scans for, and the sanitizer eating tag-shaped fragments through to the end of the body. Neither bit here. The line is the dispatch relay's platform attribution, not a seat marker; the relay's read-back stored the body byte-identical (5797 sent, 5797 stored); and the two line-initial declarations after it parsed, since Check Changeset and Governed Surface Queue Guard are both success on the head. Nothing in this repo (AGENTS.md, scripts/, .github/) requires or names that line, so the clause's wording is os-dev.md's owner to settle; escalated as a note, not a defect of this PR.
  • out_of_scope_findings ×3 — acknowledged, none blocks. The two ADR-0049 enforce-or-remove candidates (ApiTestingUiConfigSchema as ApiDocumentationConfigSchema.ui; OpenApiGenerationConfigSchema.uiPath) are retirements, a Metadata-protocol: narrowed the claim excluded and the card left undecided; the seat files them as their own card, correctly. .changeset/25077-rest-docs-viewer-attr-escape.md describes a fix to the page feat(rest)!: retire GET {base}/docs, the OpenAPI document's HTML viewer page; /openapi.json stays #25124 retired; release-owned input, correctly untouched here, and the release compiler should read it beside feat(rest)!: retire GET {base}/docs, the OpenAPI document's HTML viewer page; /openapi.json stays #25124.
  • Local NOT MEASURED families — check:dual-build-cjs-loads (exit 3, workspace unbuilt) is CI-owned under the Lint lanes; check:dev-prereqs reports the box's unbuilt state and names no stale spec dist. Both are the head's check-runs' to answer, not a local re-run's.
  • Docs Drift Check (PR comment 6331671865) — content/docs/releases/v12.mdx names RestApiConfigSchema; release-owned, read-only, no edit owed by this PR. packages/spec/liveness/rest_api.json yielded no anchor; that file is item 5 above and the liveness check-run covers it.
  • Check-runs on the head (39): 23 success (among them Check Changeset, Governed Surface Queue Guard, Spec property liveness, Lint · ESLint, Lint · PM dispatch-gates, Lint · scoped · tooling self-tests, Type Check · source gates, No other open PR may claim the same issue, The card this PR closes must claim this branch, Dogfood Regression Gate); 6 skipped (opt-in or conditional: 18.x upgrade harness, Console Pin Gate, Dogfood shards, Dogfood Verify CLI, Packed-tarball smoke, Temporal Conformance); 16 pending at read time (Build Core, Build Docs, Lint · CI, release & engine gates, Lint · docs & code guards, Lint · repo & tooling gates, Lint · scoped · query-options erasure, Lint · scoped · slot lookup & corpus, Test Core 1–6, Type Check · consumer gates, Type Check · debt ledger, Type Check · workspace). Not waited for. This record judges the contract; the queue guard still owes the remaining gates their green before the PR lands, and a red among them is a lane finding, not a contract one, given a diff of description, TSDoc, comment and prescription text only.

Implemented-by: claude/project-thread-7afd2e
Reviewed-by: session_01B2EeooonSXrANpkpgUSfFZ

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

CI note: Test Core (3/6)

Test Core (3/6) (run 39714844044, head 32bfe10cd) failed in packages/create-objectstack (pnpm run test). This PR's diff touches no file under packages/create-objectstack, and the same shard is green on main. At this head the suite passes locally: npx vitest run in packages/create-objectstack gives 18 files / 278 tests passed.

I read it as a flake, not this PR's failure, and will re-run the failed job once when the run completes. If it is red again, I will diagnose it as real.

2026-10-22T03:35Z


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

ACCEPT · domain:spec seat 2 (#18549) · os-bill · session session_01B2EeooonSXrANpkpgUSfFZ · 2026-10-22T04:09Z · head 32bfe10cda2f5fdec1be6233b6f45e013ab256f6

  1. Shape: draft, base main, one closing keyword (Fixes #25121, line 4); no other card number sits beside a closing verb. check-governed-merges.mjs --pr 25162: 0 of 6 paths governed, 55 changed lines ≤ 3000, so ordinary queue landing. mergeable_state: clean.
  2. Premise measured: registerOpenApiEndpoints mounts GET {basePath}/openapi.json alone on main; the dev's sweep of packages/spec found no other site naming the retired viewer. The seat's assumption that the prescription edit is no accept-set change held: both message pins end at "api.enableOpenApi: false is the switch", which the new text keeps.
  3. Gates (check-runs on this head): 36 success, 6 skipped, 0 failed or pending. Test Core (3/6) failed on attempt 1 in packages/create-objectstack, which this diff does not touch; the suite passed locally at this head (278 of 278), the failure was noted on this PR, and the one re-run of the failed job went green on attempt 2. Local: 111 dispatch-gates families accounted for (--ran exit 0), 110 run, 1 NOT MEASURED (check:dual-build-cjs-loads, which CI's Lint lanes run, green here).
  4. Contract review: PASS at CONTRACT_REVIEW_TIER on this head, record 6331776073 (published-schema face, Local-runs: none). Its answer to the dev's open question (keep the attribution line) stands.
  5. Accepted deviations: the branch is claude/project-thread-7afd2e, as the claim names it.
  6. Prose faces (the seat's own read, sentence by sentence): the changeset (patch, both declaration lines, three bullets that match the three hunks, and "no schema accepts or refuses anything new" is true); the two regenerated rest-server.mdx rows and the tombstone row; the rest_api.json evidence string and verifiedAt restamp; the openapi-self-consistency.ts rule-1 comment and refusal text. Each matches the code at this head.
  7. Out of scope: the two enforce-or-remove candidates are filed as spec(api): after #25104 retires the docs viewer, api.documentation.ui (ApiTestingUiConfigSchema) and the REST API plugin's uiPath are declared and read by nothing; retire them (ADR-0049 enforce-or-remove) #25159; the 25077 changeset note is release-owned and left for the release compiler.
  8. Landing: pr_ready + automerge_enable through the relay now. The seat follows it to MERGED.

Generated by Claude Code

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/s tooling

Projects

None yet

2 participants