diff --git a/.changeset/6307-bold-version-literals.md b/.changeset/6307-bold-version-literals.md new file mode 100644 index 000000000..9b3e4f62c --- /dev/null +++ b/.changeset/6307-bold-version-literals.md @@ -0,0 +1,35 @@ +--- +--- + +Docs and gate change; no published surface. + +Two consumer-facing guides stated Node/pnpm floors this project neither declares nor +tests: `content/docs/guide/quick-start.md` carried `**Node.js** 20+` / `**pnpm** 9+ or +npm/yarn`, and `content/docs/guide/building-crud-app.md` the same pair on one line. Both +pages address the reader's OWN project, so the root `engines` field never governed them, +and no published package supplies a floor either — of the 46 workspace manifests, zero +declare `engines.node` or `engines.pnpm` (the only `engines` block outside the root is +`packages/vscode-extension`'s `engines.vscode`). The pages now state what is measurable +instead: the packages are built and tested on Node 22.x with pnpm 10.x — 26 of the 27 +`node-version:` declarations in `.github/workflows` read `'22.x'` and the 27th reads +`'22'`; the root `packageManager` field is `pnpm@10.31.0`, which is what `corepack enable` +hands every CI job. Worded as what CI exercises, not as a requirement the project has not +measured. + +The reason nothing objected: `scripts/__tests__/doc-version-claims.test.ts` scans +`content/docs` for exactly this, and the `SEP` character class between a toolchain name +and its version admitted backticks, quotes, whitespace, colons, commas, pipes and brackets +— but not `*`. So `**Node.js** 20+` never matched `TOOLCHAIN + SEP + VERSION`, and the +ratchet reported green over four literals it had never examined. `SEP` now admits `*` and +`_`; measured over the 241 files the three scan roots resolve to, the corpus goes from 33 +matched literals to 37 — exactly those four, none lost. None of the four was ledgered: +they were deleted, which is what the gate's own failure message asks for when a literal +restates no manifest and no lane tests it, and the sentences replacing them are inventoried +as `anchored` entries naming the anchor each can be re-measured against. + +A new fixture test keeps the widening measurable now that the repaired corpus carries no +emphasised claim at all, and pins the one boundary it does not cross: `_Node.js_ 20+` stays +invisible, because `_` is a word character and the `\b` on each side of the toolchain name +therefore fires on neither side of it (measured: zero such spellings in the corpus today). + +objectui#6307. diff --git a/content/docs/guide/building-crud-app.md b/content/docs/guide/building-crud-app.md index 26f028704..534fc67b5 100644 --- a/content/docs/guide/building-crud-app.md +++ b/content/docs/guide/building-crud-app.md @@ -9,7 +9,7 @@ This tutorial walks you through building a **Task Manager** CRUD application wit ## Prerequisites -- **Node.js** 20+ and **pnpm** 9+ +- **Node.js** and **pnpm** (or npm/yarn) — ObjectUI is tested on Node 22.x with pnpm 10.x. - Basic knowledge of **React** and **TypeScript** ## Step 1: Project Setup diff --git a/content/docs/guide/quick-start.md b/content/docs/guide/quick-start.md index 3d4cf4714..89d2a211a 100644 --- a/content/docs/guide/quick-start.md +++ b/content/docs/guide/quick-start.md @@ -9,8 +9,7 @@ Get up and running with ObjectUI in a small Vite app. This guide installs the co ## Prerequisites -- **Node.js** 20+ -- **pnpm** 9+ or npm/yarn +- **Node.js** and **pnpm** (or npm/yarn) — ObjectUI is tested on Node 22.x with pnpm 10.x. - Basic knowledge of **React** and **TypeScript** ## Step 1: Create a React Project diff --git a/scripts/__tests__/doc-version-claims.test.ts b/scripts/__tests__/doc-version-claims.test.ts index ba58f00c3..51dc12f6d 100644 --- a/scripts/__tests__/doc-version-claims.test.ts +++ b/scripts/__tests__/doc-version-claims.test.ts @@ -277,6 +277,46 @@ import { fileURLToPath } from 'node:url'; * manifests (it wires Tailwind 4 through `@tailwindcss/postcss` instead), so there is * nothing here to compare against, whatever the page teaches. * + * ## What objectui#6307 added: the SPELLING the scan could not see + * + * Every widening above added a surface or a name. This one added a SEPARATOR, and it is + * the first whose absence was invisible from inside this gate's own output: a green + * ratchet looks identical whether it examined a line or never matched it at all. + * + * `SEP` admitted backticks, quotes, whitespace, colons, commas, pipes, brackets and a + * dash — and not `*`. So `**Node.js** 20+` never matched `TOOLCHAIN + SEP + VERSION`, + * while markdown emphasis around a toolchain name is one of this corpus's ordinary + * spellings: measured at this cut, six files across the three scan roots write one in + * bold. Two of them were the consumer guides' prerequisite bullets, where the number is + * exactly what a reader acts on. + * + * Measured across the widening, over the 241 files the three roots resolve to: 33 + * matched literals before, 37 after — four new, none lost, all four on the two pages + * objectui#6307 names (`quick-start.md:12-13` and `building-crud-app.md:12`). + * + * NOT ONE of the four earned an inventory entry, and that is the half of this change + * worth carrying forward. They were not a floor this project declares — of the 46 + * workspace manifests, ZERO declare `engines.node` or `engines.pnpm`, the only + * `engines` block outside the root being `packages/vscode-extension`'s `engines.vscode` + * — and not one it tests: 26 of the 27 `node-version:` declarations in + * `.github/workflows` read `'22.x'` and the 27th reads `'22'`, so nothing anywhere runs + * the Node 20 those bullets named. A number a reader will act on, restating no manifest + * and tested by no lane, is precisely what the ratchet's own failure message says to + * DELETE rather than ledger. The pages now state what CI exercises instead, and THOSE + * sentences are the four `anchored` entries below — an entry per literal, each naming + * the anchor it can be re-measured against. + * + * Which leaves the trap this section exists to stop. After that repair the corpus holds + * no emphasised claim at all, so reverting `SEP` would change nothing observable and + * this file would report green over the same blind spot again. + * `it('reads a claim through markdown emphasis…')` is the permanent witness, and it + * also pins the boundary the widening does NOT cross: `_` is in the class, yet + * `_Node.js_ 20+` still cannot match, because `_` is a word character and the `\b` on + * each side of `TOOLCHAIN` therefore fires on neither side of the name. Measured: zero + * underscore-emphasised toolchain names in the corpus today (control, same sweep: six + * files carry the bold spelling), so it is recorded as a boundary rather than repaired + * by widening those boundaries into a lookaround nothing has asked for. + * * ## The census that set the design (measured on d46b40324, the merge of PR #3698) * * The dispatch expected the bare-claim count to be zero, since #3688 and #3698 had just @@ -446,7 +486,7 @@ const TOOLCHAIN = * spelled without the wildcard in the comments here. */ const TICK = '\u0060'; -const SEP = '[' + TICK + '\'"\\s:,|)\\]]{0,6}(?:[-—]\\s*)?[' + TICK + '\'"]?\\s*'; +const SEP = '[' + TICK + '\'"\\s:,|)\\]*_]{0,6}(?:[-—]\\s*)?[' + TICK + '\'"]?\\s*'; /** * Case-insensitive, and the reason is the biggest single class in the corpus: the @@ -686,6 +726,18 @@ const PEER_RESTATEMENT_OK = const KNOWN_CLAIMS: KnownClaim[] = [ // --- content/docs ------------------------------------------------------------ + { + file: 'content/docs/guide/building-crud-app.md', + claim: 'Node 22.x', + kind: 'anchored', + why: "Anchored on the workflows: of the 27 node-version declarations in .github/workflows, 26 read '22.x' and the 27th (half-state-patrol.yml) reads '22'. Written by objectui#6307, which replaced an invented consumer floor (`**Node.js** 20+`) on this page. The sentence around it states what CI EXERCISES, not what a reader's project requires - no manifest in this tree declares a consumer engines.node, so a floor here would be a number nobody measured.", + }, + { + file: 'content/docs/guide/building-crud-app.md', + claim: 'pnpm 10.x', + kind: 'anchored', + why: 'Anchored on the root packageManager field, pnpm@10.31.0: 17 corepack enable steps across 12 workflow files mean the pnpm that installs and builds these packages in CI is the one that field names. Same objectui#6307 rewrite as the Node line above, replacing `**pnpm** 9+` - a floor zero manifests in this workspace declare.', + }, { file: 'content/docs/guide/ci-cd-pipeline.md', claim: 'Node 22.x', @@ -724,6 +776,18 @@ const KNOWN_CLAIMS: KnownClaim[] = [ skeletonDep: 'vite', why: 'Same skeleton, same anchor, same assertion (objectui#3855). This was the worst of the pair: it read ^5.0.0 against a workspace unanimously on ^8.2.1 — three majors — and the entry excusing it said the plugin author picks their own bundler version, which is not what a workspace:* manifest with a vite build script means.', }, + { + file: 'content/docs/guide/quick-start.md', + claim: 'Node 22.x', + kind: 'anchored', + why: "Same anchor and same objectui#6307 rewrite as the building-crud-app.md entry above (26 of 27 node-version declarations read '22.x'); this page carried the same invented floor in two bullets, `**Node.js** 20+` and `**pnpm** 9+`, and both were invisible to this scan until SEP admitted emphasis markers.", + }, + { + file: 'content/docs/guide/quick-start.md', + claim: 'pnpm 10.x', + kind: 'anchored', + why: 'Same anchor as the building-crud-app.md pnpm entry above: the root packageManager field, pnpm@10.31.0, is what corepack hands every CI job that installs this workspace. Written by objectui#6307 in place of `**pnpm** 9+`.', + }, { file: 'content/docs/guide/theming.md', claim: 'Tailwind CSS v3.3', @@ -1374,6 +1438,66 @@ describe('doc version claims - the scan itself', () => { } }); + it('reads a claim through markdown emphasis, so the widened separator is not decorative', () => { + // objectui#6307. `SEP` admitted backticks, quotes, whitespace, colons, commas, + // pipes and brackets — and not `*` — so `**Node.js** 20+` never matched + // `TOOLCHAIN + SEP + VERSION`. Both consumer guides spelled their prerequisite + // floors that way, four literals across two pages, and this gate reported green + // over every one of them: the failure its own header warns about for other + // classes, arriving through the scan instead. + // + // This fixture is the widening's only PERMANENT witness, which is why it is here + // rather than left to the corpus. The four literals that motivated the change + // were DELETED by the same change (they stated a consumer floor this project + // neither declares nor tests, objectui#6307 half 1), and the sentences that + // replaced them put a plain space between each name and its version. So on the + // corpus alone, reverting `SEP` to its pre-#6307 spelling would change nothing + // observable and the blind spot would come back unnoticed. + const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'doc-version-claims-emphasis-')); + try { + const fixture = path.join(dir, 'prerequisites-shaped.md'); + fs.writeFileSync( + fixture, + ['# Prerequisites', '', '- **Node.js** 20+', '- *pnpm* 9+ or npm/yarn', ''].join('\n'), + 'utf8', + ); + + expect( + claimsIn(fixture).map((c) => c.claim), + 'a toolchain name wrapped in markdown emphasis must still produce a claim', + ).toEqual(['Node.js** 20+', 'pnpm* 9+']); + } finally { + fs.rmSync(dir, { recursive: true, force: true }); + } + + // The two spellings pinned side by side, so that "the widening bought something" + // is asserted rather than believed: the pre-#6307 class, rebuilt here, must FAIL + // on the same line the current one matches. + const claimWith = (sep: string): RegExp => + new RegExp('(?:@[a-z0-9-]+/)?\\b' + TOOLCHAIN + '\\b' + sep + '(' + VERSION + ')', 'i'); + const SEP_BEFORE_6307 = '[' + TICK + '\'"\\s:,|)\\]]{0,6}(?:[-—]\\s*)?[' + TICK + '\'"]?\\s*'; + + expect(claimWith(SEP).test('- **Node.js** 20+'), 'the current SEP must match the bold spelling').toBe(true); + expect( + claimWith(SEP_BEFORE_6307).test('- **Node.js** 20+'), + 'the pre-objectui#6307 SEP must be shown NOT to match, or nothing here says what the widening changed', + ).toBe(false); + + // The residual, asserted rather than left for someone to assume away: `_` is in + // the class (it costs nothing between a name and a version) but underscore + // EMPHASIS around the name is still invisible, and no character class can reach + // it. `_` is a word character, so `\b` fires on neither side of `_Node.js_` — + // the match fails before `SEP` is ever consulted. Measured at this cut across the + // three scan roots: ZERO underscore-emphasised toolchain names (control, same + // sweep: six files carry the bold spelling), so this is a documented boundary and + // not a live hole. A corpus that starts spelling it that way needs the BOUNDARIES + // widened, not the class. + expect( + claimWith(SEP).test('- _Node.js_ 20+'), + 'if this ever goes true the boundary was changed too - update this comment with what it now covers', + ).toBe(false); + }); + it('does not treat a numbered section heading as a release section', () => { // The trap that would make this whole file vacuous. `0001-clipboard-paste.md` // numbers 18 of its headings `### N.M`; a loose "heading contains a version"