Repository navigation
fix(spec): emit the "do not edit" banner on the 14 generated category overviews - #14731
Merged
Merged
Conversation
…erviews `content/docs/references/**` is claimed by `manageDir(DOCS_ROOT, …)`, so `flush()` deletes what it owns before rewriting — a hand edit to any page in that tree is discarded by the next `gen:docs` run with no gate red and no conflict, because `check:docs` re-derives the tree and then reports it current. The banner is the only in-page signal a contributor gets before that happens. 200 of the tree's 214 pages carried it. The 14 that did not were the per-category overviews: the §2.5 template built each page line by line and never emitted the line §2 emits for every schema page. Ownership was never in doubt, only the warning. The banner string now lives in one place — `AUTO_GENERATED_BANNER` in `lib/generated-output.ts`, the sink module whose `manageDir()` claim the banner announces — and all three emission sites use it: §2 (schema pages), §2.5 (category overviews, new) and `lib/root-index.ts` (the root index, which already carried its own identical copy of the literal). One spelling, so a future reword cannot split the tree into two populations of page. The 14 overviews are re-emitted by the generator, not hand-edited; the other 200 pages and the root index come out byte-identical, which `check:generated` proves. `scripts/references-banner.test.ts` asks the question of the TREE rather than of a template: every `.mdx` under `content/docs/references/` carries the banner in its first 25 lines, banner-less set empty, with a page-count floor and a non-empty-banner guard so the walk cannot pass vacuously. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
Contributor
📓 Docs Drift CheckNothing 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): |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #14364
The 14 generated
content/docs/references/CATEGORY/index.mdxoverview pages carried no"do not edit" banner, while the other 200 pages in the same generated tree did. The tree is
claimed by
manageDir(DOCS_ROOT, ...), soflush()deletes what it owns before rewriting: ahand edit to a page without the banner is discarded by the next
gen:docsrun with no gatered and no merge conflict —
check:docsre-derives the tree and then reports it current. Thebanner is the only in-page warning a contributor gets before spending an afternoon on a page
that cannot keep their words.
What changed
One template, one spelling of the banner.
packages/spec/scripts/build-docs.ts§2.5 — theper-category overview emitter — now appends the banner right after the frontmatter, exactly
where §2 puts it on every schema page. The string it appends is the one §2 already emitted,
lifted into a single exported constant
AUTO_GENERATED_BANNERinpackages/spec/scripts/lib/generated-output.ts(the in-page half ofmanageDir()'s claim,next to the claim itself). §2.6's root-index emitter in
scripts/lib/root-index.tscarried asecond byte-identical copy of the same literal; it now reads the constant too, so the
generator holds one spelling rather than three.
git grep -c "AUTO-GENERATED — DO NOT EDIT" packages/spec/scriptsreports the literal once, ingenerated-output.ts.The 14 pages are regenerated output, not hand edits. Running
pnpm --filter @objectstack/spec gen:docson this branch reproduces the committed tree byte for byte(
git status --porcelainempty afterwards). That same empty diff is the proof the sharedconstant is byte-identical to both literals it replaced: the other 200 schema pages and the
root
content/docs/references/index.mdxare untouched — the root index blob is4761aa1d2bc1c9362e36726433fbab56b16f7353onorigin/mainand on this branch alike.A pin that asks the question of the tree, not of a template.
packages/spec/scripts/references-banner.test.tswalks every.mdxundercontent/docs/references/and requires the banner in its first 25 lines. Nothing was redbefore this change because no check had ever asked the question of the tree as a whole; each
template was only ever read against itself. A future template that forgets the line — a new
category shape, a new page kind, a refactor that drops the constant from one call site — now
lands as a red on the first regeneration instead of as a second silent population of pages.
Two guards keep it from degrading into a vacuous green: a floor on the page count (so a glob
that stops matching reads as broken, not as "all zero pages pass") and an assertion that the
banner constant still says something (so emptying it cannot make every page trivially contain
it). The banner text is imported, never re-typed.
Census
origin/mainThe 14 were exactly the per-category overviews (
ai,api,automation,cloud,data,identity,integration,kernel,qa,security,shared,studio,system,ui).Verification
All runs under
scripts/pm/os-verify-lock.sh, exit codes captured before any pipe, oncommit
3e76dd6ca.pnpm --filter @objectstack/spec gen:docsthengit status --porcelain— empty. Generatoroutput reproduces the commit byte for byte.
pnpm --filter @objectstack/spec check:docs—229 generated files in sync with packages/spec.pnpm --filter @objectstack/spec check:generated—All 15 generated artifacts are up to date.pnpm --filter @objectstack/spec check:scripts-typecheck— clean.tsc --listFilesconfirmsthe program actually reads all four edited files, the new test included (1 hit each), so
this is a measurement and not a silent skip.
vitest run scripts/references-banner.test.ts scripts/root-index.test.ts scripts/category-index.test.ts scripts/root-meta.test.ts scripts/check-generated-ledger.test.ts scripts/schema-tree-freshness.test.ts— 6 files, 48 tests passed. The sibling suites are theones that name the edited generator libraries.
pnpm check:nul-bytes—OK (scanned 8038 text files ... no raw ASCII control bytes).pnpm check:doc-authoring— clean on all four legs.pnpm check:published-files/pnpm check:changeset-gate-self-tests— green.mdx += AUTO_GENERATED_BANNER;line was deleted from §2.5 on diskand the mutation proven there before anything was measured (statement count 1 to 0, injected
marker count 1, blob
d59f2e1fetoeabbcb8c1). Regenerating from the mutated generatorstripped the banner from exactly 14 of 214 pages and the pin went RED with
AssertionError: 14 of 214 generated reference page(s) carry no "do not edit" banner in their first 25 lines(exit 1). Restoring withgit checkout HEAD -- ...— pinned toHEAD, not abare checkout, so the index could not hand back the mutation — reproduced the HEAD blob
d59f2e1feexactly, and after regenerationgit diff HEADandgit status --porcelainwereboth empty; the pin returned to 3 of 3 green. The mutation script carried a
trap ... EXIT INT TERMrestoring by absolute path, but the blob comparison is the proof, not the trap.pnpm lint(eslint . --no-inline-config, the whole repo, no narrowing) — exit 0, no findings.check:doc-frontmatter,check:doc-route-spelling,check:docs-section-name,check:section-landing-index,docs-audit/check-affected-docs,docs-audit/check-drift-comment,check:doc-anchors,check:docs-single-h1,check:docs-redirects,check:docs-audit-scope,check:page-declaration-shape,check:quick-reference-counts,check:cross-package-test-inputs,check:comment-mask-adoption,check:keyed-text-bounds,check:test-source-alias,check:type-check-coverage,check:role-word,check:pm-dispatch-gates,check:merge-driver,check:published-readme-links,check:corpus-claim-drift.check-test-completeness(exit 3 — needs a savedturbo run testlog) andcheck:type-check-debt(exit 3,
PREREQUISITE NOT MET— needs the whole workspace build closure). Neither is a finding.The remainder of the derived family runs on CI.
Why
skip-changesetNothing in this PR reaches a published tarball, so it declares no release.
packages/specships
files: ["dist","json-schema","liveness","prompts","llms.txt","README.md", "src/**/*.zod.ts","CHANGELOG.md","api-surface","spec-changes.json"]—scripts/is not inthat whitelist, and
pnpm check:published-filesindependently reports that the 69 publishablepackages "admit no test, test-harness config or build script".
content/sits at the reporoot, outside every
pnpm-workspace.yamlpackage glob, so it cannot be packed by any package.The label is applied to this PR with that reason.
🤖 Generated with Claude Code
https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
Generated by Claude Code