Skip to content

docs(releases): 17.2.0 and 17.3.0 detail sections, and repair the upgrade entry page that reads a breaking upgrade as a tag swap - #15333

Merged
hotlong merged 1 commit into
mainfrom
claude/issue-15322-v17-upgrade-docs
Sep 4, 2026
Merged

hotlong merged 1 commit into
mainfrom
claude/issue-15322-v17-upgrade-docs

Conversation

@hotlong

@hotlong hotlong commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor

Part of #15322

⚠️ Deliberately Part of, not a closing keyword — and the PM has ruled it necessary rather than merely cautious. This PR is pass 1 of the card's two passes, so merging it must NOT close the card: #15322 stays open and narrows to pass 2 (the consolidated 17.1.0 → 17.3.0 Upgrade checklist), keeping its Blocked-by: hotcrm#1576. ⛔ No new card is opened for pass 2, and no closing keyword appears anywhere in this body — including in prose about one, because GitHub's parser matches the keyword and the number and ignores the surrounding sentence, which is precisely the loss scripts/check-partof-closing-keyword.mjs exists to block.

Two releases shipped with no upgrade guidance, and the page a customer starts from currently reads a breaking upgrade as a tag swap. This is pass 1 of two: everything that does not depend on hotcrm#1576. The consolidated 17.1.0 → 17.3.0 Upgrade checklist is deliberately not here — see "What is NOT in this PR" below.

PM ruling on why pass 1 lands ahead of that checklist: the misleading page is a live, customer-facing defect, and holding its repair behind an in-flight measurement in another repository is the worse trade. The maintainer's own framing of the problem is 「我们最终客户不可能到仓库里来查源码」. Landing pass 1 removes a misleading sentence rather than leaving a hole, because ## Upgrade checklist states plainly that 17.2.0 and 17.3.0 have no consolidated checklist yet and points at the per-change Migration notes.

Docs-only, two files, no code, no content/docs/ drive-bys. skip-changeset is needed: the diff publishes nothing from any package.

1. content/docs/upgrading.mdx — the entry page was misleading, not just incomplete

The measured defect. The per-major checklist table at :197 listed v17 exactly once, pointing at /docs/releases/v17#upgrade-checklist (17.0.0). 17.1 / 17.2 / 17.3 did not exist in it. A deployment pinned at 17.1.0 — objectstack-ai/hotcrm is exactly that — starts here and gets no pointer to either release it has to cross.

Worse than the omission: the page's framing. The runtime half's upgrade action is "move the image tag, restart", and the Callout under it says a major move keeps working with metadata authored against the previous major. Read together, 17.1 → 17.3 reads as a tag swap (and :41's example already reads objectstack:17.3.0). It is not: those two releases carry an alias-free client.projects.* rename, drivers that start enforcing declared unique / indexes[], a self-registration default flipping to invite_only, a permission-store outage that starts failing loudly, and sys_record_share becoming tenant-scoped.

What changed:

  • A second Callout type="warn" immediately after the existing one, scoping it: the major boundary promises metadata compatibility and nothing else, so read the checklist for every release you cross, not every major. ⛔ The page's main argument — two upgrades on two clocks — is untouched; so is the os migrate meta section and every other claim on the page.
  • ## Per-major specifics → ## Per-release specifics, with the lead rewritten to say why a minor still needs reading (os migrate meta has nothing to replay for a minor, so the release page is the only channel its tightenings have), and one row per v17 release. The v16-and-earlier rows are unchanged.
  • No inbound link pointed at #per-major-specifics (grepped content/**), and check:doc-anchors is green on the rename.

2. content/docs/releases/v17.mdx — 17.2.0 and 17.3.0 detail sections

New ## Highlights — 17.3.0, ## What's new in 17.2.0 and ## What's new in 17.3.0, in the shape 17.0.0 / 17.1.0 already establish. The release-status blockquote now says 17.3.0 is current and names what makes these minors minors by number only.

Content provenance. Every entry is reused from the packages' own CHANGELOG.md — the release process already compiled it, and it was written by the change's author. Entries carrying a Migration table (87042b5's method/response-key tables, 914c413's metric FROM → TO, 266436a's status matrix, db16b94's per-method rewrite table, 9a1ed7a's route/capability table) are reused, not paraphrased. Every entry is cited by changeset short hash so a reader can find the original.

⛔ The published 17.0.0 and 17.1.0 sections are not rewritten or tidied. Their prose is byte-identical.

The one structural edit to published headings, declared

### Upgrade checklist → ## Upgrade checklist, its #### 17.0.0 / #### 17.1.0 → ### 17.0.0 / ### 17.1.0, and ### References → ## References. Four lines, no prose touched.

Why: both sections span all releases but sat inside ## What's new in 17.1.0. Appending two more release sections without this would have filed the published 17.0.0 and 17.1.0 checklists under "What's new in 17.3.0" — a worse corruption of the record than the promotion. Anchors are preserved — github-slugger keys on heading text, not level — so #upgrade-checklist, #1700 and #1710 all still resolve; check:doc-anchors verifies it across 302 fragment links. The promoted shape is also the one check-release-section-coverage.mjs names as correct: "the shape both current pages use is # What's new in 17.3.0 plus ### 17.3.0 in the upgrade checklist".

How the BREAKING entries were triaged

The rule, stated on the page itself: an entry is written up when the change can be reached from something an application ships or operates — its metadata, its data, its own code calling the SDK / REST / CLI, its deployment config, or a plugin it authors. Everything else is left to the per-package changelogs.

Measured against the changelogs (distinct entries across all 69 package CHANGELOG.md files; an entry landing in several packages counted once). Two units are counted below and they are not interchangeable — the reconciliation is stated under the table, because 94 + 6 = 100 while the coverage check reads 98:

unit 17.2.0 17.3.0
distinct changelog entries entry 204 862
entries marking themselves BREAKING entry 19 100
written up in the body entry 19 94
left to the per-package changelogs entry 0 6
distinct short hashes carrying those BREAKING entries hash 19 98
hashes appearing anywhere in the new prose hash 19/19 98/98

Why 98 and not 100, and why 98 and not 94. The triage split (94 in / 6 out) counts entries — one changelog bullet. The coverage check counts short hashes, and differs from it for two independent reasons:

  1. 100 entries collapse to 98 hashes. Two changesets carry a different entry text in different packages, so hash-only dedup is lossy and is not what the split uses: 93940d4 is "IDataDriver.update() declares its not-found arm" in spec and "update() and upsert() publish their honest types" in driver-memory; be21955 is the nine dead contributes members in one text and contributes.kinds[].globs in another. Both texts of both are written up.
  2. The 6 excluded entries' hashes still appear in the prose, because they are named as exclusions rather than silently dropped — so "written up" (94) and "mentioned at all" (98) are deliberately different populations.

So: 94 of 100 BREAKING entries are written up with migration prose; 6 are named only as exclusions; and 98 of 98 distinct hashes appear somewhere in the new sections, which is the check that nothing went unmentioned. The four Console pin refreshes are inside the 94 — written up once under their own heading rather than enumerated as four breaking entries.

Those four Console pin refreshes are summarized rather than enumerated because their per-commit content is objectui's changelog, and four pin bodies inline would be transcription. The host-facing half of that range (retired @object-ui/types exports, the options.actor / X-Actor removal) is called out explicitly.

The six left out of 17.3.0 are named on the page rather than silently dropped, and none is reachable from an application: the six branded identifier schemas and EventNameSchema (45b9051), MetadataChangedEventPayloadSchema — a payload nothing ever emitted or consumed (50d6c92), RestApiEndpoint.handlerStatus with the Route Coverage Report shapes (53d3689), the orphan CLICommandContributionSchema export (7a25e7d), SendTemplateInput.org (8619f95), and FilesystemLoader.list() reporting only the names its siblings can resolve (4b4d5a3).

Ordering inside the section is by blast radius, not by package: the three entries that change behaviour on a running deployment with nothing to parse-fail on lead — the audience-posture default, sys_record_share tenant-scoping, and the newly-enforced driver-memory uniqueness — followed by the alias-free SDK rename, then author-time refusals, then smaller changes.

What is NOT in this PR, and why

The consolidated 17.1.0 → 17.3.0 Upgrade checklist, which #15322 narrows to after this merges. hotcrm#1576 is running a real 17.1.0 app through the upgrade as a customer, using only published documentation, and its deliverable is the log of where the docs stop carrying you. That log is the checklist's spine. At the time this PR opened, hotcrm#1576 is open with a claim comment and a method-correction comment and no log delivered — its branch claude/issue-1576-objectstack-17.3.0 is still at its base commit.

⛔ Writing the checklist now would mean inventing steps, and a step nobody has run is worse than a missing step: it sends upgraders to do work whose effect nobody has verified. So ## Upgrade checklist gains a lead paragraph saying plainly that 17.2.0 and 17.3.0 have no consolidated checklist yet and pointing at their per-change Migration notes, which is also where upgrading.mdx points for those two releases. Pass 2 adds ### 17.2.0 and ### 17.3.0 once that log lands.

content/docs/releases/index.mdx. Its v17 entry still reads "current series: 17.2.0, released 2026-08-23". Real, gated, and out of this PR's declared scope — filed as #15332 with the measurement, including that the arm which catches it (--strict) runs only in the standing patrol, not in lint.yml.

Verification

All 42 runnable gate commands derived at the final commit c13400b5f by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (36 families; the 3 value-bearing CI-only invocations are excluded by the script itself). Exit codes captured before any pipe, one log per gate.

41 of 42 green. The single non-zero is node scripts/check-release-section-coverage.mjs --strict, and it is a pre-existing finding in a file this PR does not touch — measured on both trees:

tree strict findings
BASE eb40a7210 (dedicated compare worktree) 2 — v17.mdx has no 17.3 section; index.mdx names a superseded current series
this branch c13400b5f 1 — index.mdx only

So this PR clears one of the two strict findings and inherits the other, which is #15332. The PR-blocking lint.yml form runs the gate without --strict and is green here.

Citation coverage was measured, not asserted: every 7-hex hash in the three new sections was extracted and diffed against the changelog-derived BREAKING set — 19/19 distinct 17.2.0 hashes and 98/98 distinct 17.3.0 hashes appear in the new prose. That 98 is the hash unit; see the reconciliation under the triage table.

Also green and worth naming: check:doc-anchors (302 fragment links, including the six new ones), check:release-notes, check:release-page-status, check-release-section-coverage.mjs (non-strict), check:docs-image-tag, check:docs-single-h1, check:doc-authoring, check:nul-bytes, pnpm --filter @objectstack/spec run check:docs and check:skill-examples (257 prose examples type-check).

⚠️ Four gates first answered PREREQUISITE NOT MET / exit 3 rather than a finding, because @objectstack/spec, @objectstack/lint, @objectstack/formula and @objectstack/client-react were unbuilt in a fresh worktree. Those runs measured nothing and are not reported as passes: the packages were built and all four re-run green.

⛔ No auto-merge armed, and it will not be armed from here — the PM arms it after CI converges.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UHvF5hyiZjnCyExFnfQB8m

…rade entry page (#15322)

Two releases shipped with no upgrade guidance, and the customer's entry page
reads a breaking upgrade as a tag swap.

content/docs/upgrading.mdx
- The per-major checklist table listed v17 once, pointing at 17.0.0. A
  deployment on 17.1.0 got no pointer to either release it has to cross. The
  section becomes "Per-release specifics" and carries a row per v17 release.
- The page's framing ("move the tag, restart") plus the metadata-compatibility
  Callout read together as "a minor is a no-op". A second Callout scopes the
  first: the major boundary promises metadata compatibility and nothing else.
  The two-upgrades-two-clocks argument is untouched.

content/docs/releases/v17.mdx
- New "What's new in 17.2.0" and "What's new in 17.3.0" detail sections, in the
  shape 17.0.0/17.1.0 establish. Content is reused from the packages' own
  CHANGELOG entries rather than paraphrased; every entry is cited by changeset
  hash.
- Release-status blockquote now says 17.3.0 is current, and names what makes
  17.3.0 a minor by number only.
- "Upgrade checklist" and "References" are promoted from h3 to h2 so they stay
  page-level sections after two more release sections are appended. No published
  prose in the 17.0.0 / 17.1.0 sections is changed; the #upgrade-checklist,
  #1700 and #1710 anchors are preserved.

The consolidated 17.1.0 -> 17.3.0 upgrade checklist is deliberately NOT in this
commit: it is blocked on hotcrm#1576's documentation-first upgrade log, and a
checklist step nobody has run is worse than a missing one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UHvF5hyiZjnCyExFnfQB8m
@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation labels Sep 4, 2026
@hotlong hotlong added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 4, 2026 — with Claude

hotlong commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

第一趟复核:PASS,两个 open question 已裁 —— 其中一个不按你的推荐

⚠️ 同会话自审声明:本复核由派发本卡的同一 PM 席位做出,与 dev 席同会话,不是独立第二意见。下列「已核」均为我自己在 head c13400b5f 上跑的 diff 层面读数。

skip-changeset 我已打上 —— 那条红是我欠的(派发单里写的是「标签我打」),不是你的。

已核

  • 改动面就两个文件,与卡面一致,没有 content/docs/ 顺手修。
  • 已发布的 17.0.0 / 17.1.0 正文一行没删。 v17.mdx 的删除行只有:frontmatter 的 description、发布状态块、那条「minor 不代表小」的 Callout,以及标题层级提升的四行(### Upgrade checklist、#### 17.0.0、#### 17.1.0、### References)。⛔ 那条「不重写已发布段落」的约束成立。
  • 标题提升的理由站得住,而且锚点是验过的不是假设的。 两个跨版本的段落原本嵌在 ## What's new in 17.1.0 里面;不提升就会把已发布的 17.0/17.1 清单归到「What's new in 17.3.0」名下 —— 那比提升更严重地损坏记录。github-slugger 按标题文本而非层级算 slug,check:doc-anchors 在 302 条片段链接上验过。

Q1 —— 裁 B(修正版),不按你推荐的 A

你的 A 是「压住 #15322 等 hotcrm#1576」。我裁 B:第一趟 CI 绿了就落地,理由是你自己在 B 那条里写出来的:

B is acceptable if the maintainer wants the misleading upgrading.mdx framing off the site immediately — the two halves are independent and pass 1 stands on its own.

维护者提出这件事时的原话是:「我们最终客户不可能到仓库里来查源码,然后再决定他们的项目怎么升级。」 现在站上那一页正在把一次带破坏性变更的升级读成换 tag —— 这是活着的、面向客户的缺陷,而 hotcrm#1576 连日志都还没开始产出(分支停在基线提交)。把一个活缺陷的修复压在另一个仓库的在飞测量后面,这笔交易不划算。

⚠️ 关键前提我核过了,否则 B 不成立:第一趟落地不会制造新的误导。## Upgrade checklist 加了那段说明白「17.2.0 与 17.3.0 暂无合并清单、请看各改动自己的 Migration 说明」的引言,upgrading.mdx 也指向同一处。所以它是移走一个误导,而不是留下一个空洞。

修正的地方:⛔ 不另开卡。#15322 保持开着,收窄成第二趟(合并清单)那张卡,Blocked-by: hotcrm#1576 不变。你提的「另开一张 docs-only 卡」会多一次卡面搬迁,而 Part of 已经让这条路走得通。

Q2 —— 裁 A,确认 Part of,而且在我上面的裁决下它更必要

你的判断对,理由也对。补一层:正因为第一趟现在要落地,Part of 从「谨慎」变成了必需 —— 合并它绝不能关掉那张现在承载第二趟的卡。

你连在散文里提那个词都避开这一点做得对:GitHub 的解析器只认关键词 + 编号、无视上下文措辞,scripts/check-partof-closing-keyword.mjs 存在的原因正是一张半交付的卡在 PR 合并两秒后被自动关掉。

⛔ 你提的 C(只凭 changeset 的 Migration 段写清单)任何情况下都不采纳,理由与卡面一致:没人跑过的步骤比缺失的步骤更糟。

一处要你收口的数字打架

PR 正文的分流表写 17.3.0:100 条 BREAKING、写了 94 条、留下 6 条。而结构化报告里写的是「98/98 distinct hashes for 17.3.0 are named」。94 + 6 = 100 对得上,98 对不上其中任何一个。

大概率是「条目数」与「被点名的 hash 数」两种口径(四条 Console pin 合并成一处叙述,但各自的 hash 仍被点名),但我不猜 —— 正文是要发布的记录。请把这两个数字用同一口径重述,或写明它们分别在数什么。这是本轮唯一要改的东西。

落地

改完这处数字、CI 绿之后翻 ready 并告诉我,由我武装 auto-merge。⛔ 你不要自己武装。

你把 releases/index.mdx 的陈旧状态另立 #15332 而不是顺手改,并且在基线与本分支两棵树上都测了 strict 门禁(基线 2 条发现、本分支 1 条,清掉一条、继承一条)—— 这是对的做法,继承的那条正是 #15332。


Generated by Claude Code

@hotlong
hotlong marked this pull request as ready for review September 4, 2026 12:31
@hotlong
hotlong added this pull request to the merge queue Sep 4, 2026
Merged via the queue into main with commit 19be9df Sep 4, 2026
39 of 40 checks passed
@hotlong
hotlong deleted the claude/issue-15322-v17-upgrade-docs branch September 4, 2026 12:52
hotlong pushed a commit that referenced this pull request Sep 4, 2026
…ured upgrade

Pass 2 of #15322. Pass 1 (#15333) wrote the 17.2.0 / 17.3.0 detail sections and
repaired the upgrade entry page's per-release table; this pass writes the two
Upgrade checklists that were left open, and answers the structural defects the
upgrade drill found in `upgrading.mdx`.

The spine is a real upgrade of an application repository across one minor,
17.2.0 -> 17.3.0, driven as a customer using only published artifacts: the docs
site, the CHANGELOG.md inside each npm tarball, and the CLI's own output. Its
headline reading was that the documentation covered zero of the eleven breakages
that run hit.

content/docs/releases/v17.mdx
- `## Upgrade checklist` gains `### 17.2.0` and `### 17.3.0`; pass 1's interim
  paragraph is removed.
- Provenance is marked per line. The drill covered ONE hop. Nobody has walked
  17.1.0 -> 17.3.0, so every 17.2.0 line is marked "not exercised" and kept in
  its own list rather than blended with measured steps.
- Two operational hard requirements are written in: deduplicating autonumber
  columns before the new unique indexes can build on an existing database, and
  `OS_PLATFORM_OWNER_EMAIL` on walled deployments.
- #15337 (the dev-admin lockout) is written as a known issue with no workaround,
  not as a step.

content/docs/upgrading.mdx
- New "Moving the dependency pins": the npm-consumer upgrade path the page did
  not have at all, which is the shape create-objectstack scaffolds.
- New "A runtime move can still force metadata edits": the page's "move the tag,
  restart" framing, narrowed by measurement rather than by assertion.
- "Nothing to migrate" is qualified next to the command it comes from.
- The per-package CHANGELOG.md files are authorised for every upgrader, not only
  for v10/v11, with the reason the release pages cannot replace them.
- The v17.3.0 / v17.2.0 rows repoint at the new checklists.

Transcript drift: four pages printed `author-time rules (41)`; the registry
resolves 42 for both `validate` and `build`. Number only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UHvF5hyiZjnCyExFnfQB8m
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 9, 2026
…m a measured upgrade (objectstack-ai#15369)

* docs(releases): the 17.2.0 and 17.3.0 upgrade checklists, from a measured upgrade

Pass 2 of objectstack-ai#15322. Pass 1 (objectstack-ai#15333) wrote the 17.2.0 / 17.3.0 detail sections and
repaired the upgrade entry page's per-release table; this pass writes the two
Upgrade checklists that were left open, and answers the structural defects the
upgrade drill found in `upgrading.mdx`.

The spine is a real upgrade of an application repository across one minor,
17.2.0 -> 17.3.0, driven as a customer using only published artifacts: the docs
site, the CHANGELOG.md inside each npm tarball, and the CLI's own output. Its
headline reading was that the documentation covered zero of the eleven breakages
that run hit.

content/docs/releases/v17.mdx
- `## Upgrade checklist` gains `### 17.2.0` and `### 17.3.0`; pass 1's interim
  paragraph is removed.
- Provenance is marked per line. The drill covered ONE hop. Nobody has walked
  17.1.0 -> 17.3.0, so every 17.2.0 line is marked "not exercised" and kept in
  its own list rather than blended with measured steps.
- Two operational hard requirements are written in: deduplicating autonumber
  columns before the new unique indexes can build on an existing database, and
  `OS_PLATFORM_OWNER_EMAIL` on walled deployments.
- objectstack-ai#15337 (the dev-admin lockout) is written as a known issue with no workaround,
  not as a step.

content/docs/upgrading.mdx
- New "Moving the dependency pins": the npm-consumer upgrade path the page did
  not have at all, which is the shape create-objectstack scaffolds.
- New "A runtime move can still force metadata edits": the page's "move the tag,
  restart" framing, narrowed by measurement rather than by assertion.
- "Nothing to migrate" is qualified next to the command it comes from.
- The per-package CHANGELOG.md files are authorised for every upgrader, not only
  for v10/v11, with the reason the release pages cannot replace them.
- The v17.3.0 / v17.2.0 rows repoint at the new checklists.

Transcript drift: four pages printed `author-time rules (41)`; the registry
resolves 42 for both `validate` and `build`. Number only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UHvF5hyiZjnCyExFnfQB8m

* docs(releases): retract the 17.3.0 dev-admin known issue — it was misattributed

The Callout claimed 17.3.0 shipped an unrecoverable sign-in lockout. That is
false, and it was a false alarm on a customer-facing page.

Root cause of the misattribution: the server that produced the reading was
started as `objectstack serve --ui` under NODE_ENV=production, not `objectstack
dev`. The dev-admin seed is by design not armed in that shape --
`isDevAdminSeedArmed()` returns false whenever NODE_ENV is not 'development' --
so the account was never created and the 401 was correct behaviour. An ablation
holding tree, published install and database path fixed and varying only the
start mode reproduced the 401 on the serve/production leg and answered 200 on
the dev leg; three further independent shapes all answered 200. The two readings
that made it look like a platform defect (a transplanted hash having no effect,
an authenticating user missing from the database) were measurement artefacts of
`rm -rf .objectstack/data` run against a live server, which left the process
holding deleted file descriptors.

Two sites removed, both introduced by this branch:

- the "Known issue" Callout at the head of the 17.3.0 checklist, in full;
- the trailing half of the audience-posture bullet, which existed only to
  explain why the lockout was total and carried a now-dangling back-reference.
  The bullet keeps its changelog-sourced first half and is marked "not
  exercised"; the "measured only as a non-change" claim came from the same
  retracted run and goes with it.

Nothing is added in their place. Whether the `os dev` / `os serve` difference in
dev-admin seeding deserves a sentence anywhere is referred to the maintainer; it
is not a 17.3.0 change and would not belong in an upgrade checklist.

check:doc-anchors still reports 305 internal fragment links across 410 files,
unchanged -- the deleted block's only link was an absolute URL, not an anchor.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UHvF5hyiZjnCyExFnfQB8m

---------

Co-authored-by: Claude <noreply@anthropic.com>
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/l skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants