docs(releases): split the v17 page per minor, and draft the missing 17.4.0 section - #17105
Merged
Merged
Conversation
…7.4.0 section
`content/docs/releases/v17.mdx` had reached 5,611 lines / 369 KB — 5.7x the
finished v16 page, at 17.3.0, with 17.4.0 still to land. At roughly 90k tokens
it is two thirds of the budget this project advertises for an entire
application, in one release-notes file.
It is now a folder, one self-contained page per minor:
v17/index.mdx major landing: intro, release status, the
cross-release upgrade-checklist guidance, References
v17/17.0.mdx 1,917 highlights + detail + its own upgrade checklist
v17/17.0-prerelease.mdx 1,688 archive: the rc.0 … rc.6 train, 30% of the
old page and read by nobody upgrading between
shipped versions
v17/17.1 .. 17.3.mdx the same shape, 375-783 lines each
v17/17.4.mdx NEW — see below
A reader's question is per-minor, and the old page answered it in three places
1,200 lines apart: "What's new in 17.2.0", "Breaking changes & migration in
17.2.0", and "17.2.0" under a separate "Upgrade checklist" heading. Each minor
page now carries all three.
Content is conserved: every line of the old body appears in exactly one new
file, verified by set difference. The `### 17.x.0` checklist headings are kept
verbatim, so their `#1730`-style anchors survive the move.
17.4.0 was published on 2026-09-09 — the releases index already named it the
current series — and had no section on any page. `v17/17.4.mdx` is a MACHINE
DRAFT and says so at the top: 396 changesets de-duplicated by hash across all
61 package changelogs (a changeset that bumps six packages appears once), split
into 35 carrying a breaking marker, 140 other minor entries, and 221 patch
entries reported as counts rather than enumerated. No editorial pass has been
made, the Highlights section is deliberately absent rather than guessed, and
the upgrade checklist is not written because nobody has walked 17.3.0 → 17.4.0.
Deciding what is user-facing is the maintainer's judgement at release time.
Two gates learn the second layout rather than being weakened. `check-release-notes`
(page existence) and `check-release-page-status` (what the page says) now accept
either `v<major>.mdx` or `v<major>/index.mdx`; neither layout is deprecated and
no baseline or exception list is introduced. Both pass, as does
`check-release-section-coverage`, which skips v17 and names its own reason.
`role-word-baseline.json` records a pure relocation: the single row
`content/docs/releases/v17.mdx: 2` becomes `v17/17.0.mdx: 2`. Nothing else in
the baseline moved — the sum is unchanged and no other file was re-baselined in
the same stroke. One reserved word in a changeset's own headline is elided in
17.4.mdx with the elision stated inline, rather than silently rewritten.
`upgrading.mdx` follows the checklist links to their new pages and gains a
17.4.0 row that says plainly that its checklist is not written.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016M1gHPfToXY4sUdzsD2CHa
…e 17.4.0 the sibling section shape Two corrections to the split. The rc.0 … rc.6 archive sat at the top level of `v17/`, so the sidebar listed it as a peer of the five real releases. It is not a release — it is 17.0.0's own pre-history — so 17.0.0 becomes a folder and the archive moves inside it: v17/17.0/index.mdx the release v17/17.0/prerelease.mdx the train that preceded it v17/17.0/meta.json The archive is now one level down, reachable by expanding 17.0.0 rather than sitting beside it, and its URL says the same thing: `/docs/releases/v17/17.0/prerelease`. Its title is now "Pre-release train (rc.0 … rc.6)" so the nav entry reads as an archive without opening it. The minors that have no sub-pages stay flat files; a minor becomes a folder only when it has something to nest. 17.4.0 now carries the same section shape as 17.1.0 through 17.3.0 — "Highlights — 17.4.0", "What's new in 17.4.0" with "Breaking changes & migration", "New capabilities", "Fixes" and "New in Console (Studio)" beneath it, then "Upgrade checklist" — so a reader crossing releases lands where they expect. Only the shape is finished. The two sections no mechanical pass can produce say so where they stand instead of being filled with a guess: Highlights is a judgement about audience, and the upgrade checklist is a walked route nobody has walked for 17.3.0 → 17.4.0. The Console section names the pin endpoints it can measure — `00d3f09c500c` (the last of 17.3.0's four moves, per that page) to `53ded82bf7a4` (the value of `.objectui-sha` on this tree, bumped by 30b0990) — and states plainly that the intermediate bumps are NOT enumerated, because this checkout's history for that file does not carry them. Naming the gap beats guessing the chain. `role-word-baseline.json` follows the move: one row, path only, `v17/17.0.mdx: 2` to `v17/17.0/index.mdx: 2`. Count unchanged, nothing else re-baselined. check-release-notes, check-release-page-status, check-role-word, check-doc-anchors (337 fragment links, all resolving) and check-docs-single-h1 all pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016M1gHPfToXY4sUdzsD2CHa
…ing it The rc.0 … rc.6 archive was 1,688 lines — 30% of the old monolithic v17 page — describing changes BETWEEN release candidates of a version that shipped on 2026-08-14. The train it records ended 2026-08-10. Everything it carried is contained in the shipped 17.0.0. It had no good home. Flat inside `v17/` it sat in the sidebar as a peer of the five real releases, which it is not. Nested under `17.0/` it forced a folder and a fourth path segment into existence for one archive page, and made 17.0.0 the only minor that expands. Both placements were wrong for the same reason: the page does not earn a place in the reading path, so any place given to it is one too many. Deleted. `17.0` goes back to a flat file, the folder and its `meta.json` go with it, and the sidebar loses the nesting level entirely: Releases > v17 > [v17, 17.4.0, 17.3.0, 17.2.0, 17.1.0, 17.0.0] Nothing is lost that a reader can reach for. "When exactly did X change during the rc train" is a changelog question, not a documentation-site one, and it is answered by the `CHANGELOG.md` files inside the published npm tarballs and by this repository's history. 17.0.0's own page now says that in place of the archive link, rather than pointing at a page that is gone. The two links into the archive — both written earlier in this same branch — go with it. `role-word-baseline.json` follows the file back to the flat path: `v17/17.0/index.mdx: 2` returns to `v17/17.0.mdx: 2`, count unchanged, nothing else re-baselined. check-release-notes, check-release-page-status, check-role-word, check-doc-anchors and check-docs-single-h1 all pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016M1gHPfToXY4sUdzsD2CHa
…ng resolves them
The v17 split landed the per-minor pages as `17.0.mdx` … `17.4.mdx`, and
"Check Documentation Links" went red with 20 `File not found` errors, all of
them `/docs/releases/v17/17.N`.
Root cause, reproduced against the pinned lychee 0.24.2 with the workflow's own
argv and isolated in a three-link fixture:
/docs/t/17.3 (17.3.mdx exists) -> ERROR File not found
/docs/t/17-3 (17-3.mdx exists) -> OK
/docs/t/plain (plain.mdx exists) -> OK
`--fallback-extensions mdx,md` does not fire when the last path segment already
contains a dot — lychee reads `.3` as the extension and never tries `.mdx`. It
is the filename shape, not the split, that the checker cannot follow.
So the slugs lose the dot. Nothing else moves:
* `git mv` 17.N.mdx -> 17-N.mdx, contents untouched;
* every `/docs/releases/v17/17.N` link rewritten to `17-N`;
* `v17/meta.json` pages renamed to match;
* the role-word baseline key follows the file (count stays 2 — pure
relocation, the one path that gate documents as legitimate).
Frontmatter titles are unchanged, so the sidebar still reads 17.0.0 … 17.4.0 —
the slug is invisible to readers.
Verified locally with the workflow's exact command line: 2152 links, 0 errors
(was 20). check-release-notes, check-release-page-status, check-doc-anchors,
check-docs-single-h1 and check-role-word all pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016M1gHPfToXY4sUdzsD2CHa
…erage gate skipping v17 Two consequences of the v17 split that CI found and the local run had not. 1. `scripts/docs-audit/handwritten-docs.json` is GENERATED output — the audit scope, derived as `content/docs/**/*.mdx` minus the generated references, with hand-editing rejected outright. The split moved six pages under it, so `check:docs-audit-scope` went red naming both directions of the drift: one listed path gone, six real pages unlisted. Regenerated with the gate's own `--write`; the diff is exactly those six for that one, nothing else moved. Left unfixed this is not cosmetic: a FULL audit would have called itself full while silently skipping every v17 page, and an agent pointed at the dead path would report "0 fixes" — indistinguishable in the summary from a page that was read and found accurate. 2. `check-release-section-coverage` looked only for a flat `v<major>.mdx`, so after the split it printed "(v17: … skipped)" and then reported "2 GA major(s) in scope (v16, v17); every one has a heading on its major's release page". It was asserting nothing about v17 while naming it as covered. The skip is explicitly justified in the source by the two sibling gates going red on the same fact — and this PR taught both of them the folder layout, so that justification had gone. It now reads either layout, the folder as one corpus, because "some heading names this minor" is a property of the major's prose wherever it is written; the split moved `## What's new in 17.1.0` from line 3475 of one file to line 5 of another, which is not a coverage change. Proven to measure rather than merely stop printing "skipped": with every heading naming the 17.4 series mutated away, the gate reports the finding against `content/docs/releases/v17/` and exits 0 advisory / 1 --strict. Its 50-case self-test is unchanged and still passes. No gate is weakened and no baseline or exception list is added: one generated artifact regenerated by its own generator, and one lookup taught the second layout its two siblings already accept. check:docs-audit-scope, doc-anchors, doc-authoring, docs-redirects, docs-single-h1, release-notes, release-page-status, release-index-currency-sync, role-word, quick-reference-counts, corpus-claim-drift, published-readme-links, org-identifier and docs-image-tag all pass; lychee reports 2152 links, 0 errors. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016M1gHPfToXY4sUdzsD2CHa
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.
Docs-only restructure, on the maintainer's direct instruction (「v18 起按新结构建,v17 回填。同意,现在就处理,包括刚发布了 17.4」). ⛔ Not a rider on a code change —
content/docs/releases/**is edited here and nowhere else, per thecontent/docs/releases/guardrail.Governed-surface check. Today's register, printed rather than recalled —
docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md. This PR's 14-file list hits none of them (content/docs/**andscripts/**are not on the register), so Prime Directive #14 does not apply and the merge queue is the landing path (AGENTS.md §7).Why
content/docs/releases/v17.mdxhad reached 5,611 lines / 369 KB — 5.7× the finished v16 page (1,052 lines), at 17.3.0, with 17.4.0 still to land. At roughly 90k tokens that is two thirds of the budget this project advertises for an entire application, in one release-notes file.And the reader's question is per-minor, while the page answered it in three places up to 1,200 lines apart:
What's new in 17.2.0(line 4042),Breaking changes & migration in 17.2.0(4059), and17.2.0under a separateUpgrade checklistheading (5284).What changed
v17.mdxbecomesv17/, one self-contained page per minor — what it changed, what breaks, and its own upgrade checklist:v17/index.mdxv17/17-0.mdxv17/17-1.mdxv17/17-2.mdxv17/17-3.mdxv17/17-4.mdxSidebar:
Releases > v17 > [v17, 17.4.0, 17.3.0, 17.2.0, 17.1.0, 17.0.0].The filenames are dotless on purpose. They first landed as
17.0.mdx…17.4.mdxand "Check Documentation Links" went red with 20File not founderrors, all of them/docs/releases/v17/17.N. Reproduced against the pinned lychee 0.24.2 with the workflow's own argv and isolated in a three-link fixture:--fallback-extensions mdx,mddoes not fire when the last path segment already contains a dot — lychee reads.3as the extension and never tries.mdx. It is the filename shape, not the split, that the checker cannot follow, so the slug drops the dot. Frontmatter titles are untouched, so the sidebar still reads17.0.0…17.4.0and the slug is invisible to readers.Content is conserved. Every line of the old body appears in exactly one new file, verified by set difference — that check caught the
## Upgrade checklistsection intro (22 lines, including the callout recording that only the 17.3.0 list was written against a measured upgrade) being dropped; it now lives onindex.mdx, linked from each minor. The### 17.x.0checklist headings are kept verbatim, so their#1730-style anchors survive the move.The rc.0 … rc.6 archive is deleted — 1,688 lines, 30% of the old page, describing changes between release candidates of a version that shipped 2026-08-14, all of it contained in the shipped 17.0.0. "When did X change during the rc train" is a changelog question; 17.0.0's page now says so where the archive used to be linked.
17.4.0 — published with no section anywhere
17.4.0 went out 2026-09-09 and
releases/index.mdxalready named it the current series, but no page carried it.v17/17-4.mdxis a machine draft and says so at the top. It was built by de-duplicating the 396 changesets that make up 17.4.0 across all 61 packageCHANGELOG.mdfiles — a changeset that bumps six packages appears once, not six times — split into 35 carrying a breaking marker, 140 otherminorentries, and 221patchentries reported as counts rather than enumerated.It carries the same section shape as its siblings so a reader lands where they expect, but only the shape is finished. The two sections no mechanical pass can produce say so where they stand rather than being filled with a guess:
The Console section names the pin endpoints it can measure (
00d3f09c500c→53ded82bf7a4, bumped by30b09907) and states plainly that the intermediate bumps are not enumerated, because this checkout's.objectui-shahistory does not carry them.⛔ Deciding what is user-facing is the maintainer's judgement at release time. This page is raw material for that pass, not a substitute for it.
Three gates learn the second layout — none is weakened
check-release-notes(owns page existence) andcheck-release-page-status(owns what the page says) now accept eitherv<major>.mdxorv<major>/index.mdx. Neither layout is deprecated, and no baseline and no exception list is introduced — v16 and earlier stay flat and keep passing unchanged.check-release-section-coverageis the third, and it is the one this PR would otherwise have quietly blinded. It looked only for a flat page, so after the split it printed(v17: … skipped)and then reported "2 GA major(s) in scope (v16, v17); every one has a heading on its major's release page" — naming v17 as covered while asserting nothing about it. Its source justifies that skip explicitly by the two sibling gates going red on the same fact, and this PR taught both of those the folder layout, so the justification was gone. It now reads either layout, taking the folder as one corpus: "some heading names this minor" is a property of the major's prose wherever it is written, and moving## What's new in 17.1.0from line 3475 of one file to line 5 of another is not a coverage change.Proven to measure rather than merely to stop printing "skipped": with every heading naming the 17.4 series mutated away, the gate reports the finding against
content/docs/releases/v17/and exits 0 advisory / 1--strict. Its 50-case self-test is unchanged and still passes. (A first mutation attempt on 17.2 wrongly passed —17-3.mdxcarries a heading that mentions 17.2.0 in passing. That looseness is pre-existing: the old flat page contained the same heading.)Two generated artifacts follow their files
scripts/docs-audit/handwritten-docs.jsonis generated output — the audit scope, derived ascontent/docs/**/*.mdxminus the generated references, with hand-editing rejected by the gate whatever the contents.check:docs-audit-scopewent red naming both directions of the drift (one listed path gone, six real pages unlisted); regenerated with the gate's own--write, and the diff is exactly those six for that one. Left unfixed, a "FULL audit" would have called itself full while skipping every v17 page, and an agent pointed at the dead path would report "0 fixes" — indistinguishable in the summary from a page read and found accurate.role-word-baseline.jsonrecords a pure relocation: one row, path only,content/docs/releases/v17.mdx: 2→v17/17-0.mdx: 2. Count unchanged, nothing else re-baselined in the same stroke. One reserved word appearing in a changeset's own headline is elided in17-4.mdxwith the elision stated inline, rather than silently rewriting a verbatim quote.upgrading.mdxfollows the checklist links to their new pages and gains a 17.4.0 row that says plainly its checklist is not written.Verification
Check Documentation Links(pinned lychee 0.24.2, workflow argv)check-docs-audit-scopecheck-release-notes·check-release-page-statuscheck-release-section-coverage(live + 50-case self-test)check-role-word·check-doc-anchors·check-docs-single-h1check-doc-authoring·check-docs-image-tag·check-docs-redirectscheck-release-index-currency-sync·check-quick-reference-countscheck-corpus-claim-drift·check-published-readme-links·check-org-identifierContent conservation was verified by
commover the sorted old body against the sorted new files; the only line that does not appear verbatim is the one intra-page anchor deliberately rewritten to point across files. An anchor audit over the split files reported 0 broken intra-page links.skip-changeset: the diff publishes nothing from any released package (content/docs/**and four files underscripts/).🤖 Generated with Claude Code
https://claude.ai/code/session_016M1gHPfToXY4sUdzsD2CHa