Repository navigation
Commit 713f231
skills(objectstack-upgrade, catalog READMEs): the upgrade preflight re-installs the catalog from @objectstack/skills on a 17.x to 18 move; both READMEs give the scaffolder's pinned --copy sync (#23366)
Fixes #23276
Clause-②: no
Ruling A on #22649 (record 6096124407), the upgrade-playbook half: the
skills catalog ships as the versioned npm package `@objectstack/skills`,
installed and upgraded with the other `@objectstack/*` packages, and the
GitHub path is the `next` channel only.
`skills/objectstack-upgrade/SKILL.md` §0 Preflight gains one step that
re-installs the catalog from the package when a 17.x project moves to
18, and the two READMEs the package ships (`skills/README.md`, published
as `dist/skills/README.md`, and `packages/skills/README.md`, the npm
page) replace the unpinned linked sync with the scaffolder's pinned
`--copy` spelling. One `patch` changeset for `@objectstack/skills`. Four
files; nothing under `content/docs/**` or
`packages/create-objectstack/**` is touched (the first is the devx
lane's landed sibling, the second is read as the source of the
spelling).
## The step (`skills/objectstack-upgrade/SKILL.md`, §0 Preflight, after
the upgrade branch and `.upgrade/` exist)
Placed after "Make the work reviewable", so the re-install lands on the
`upgrade/protocol-17` branch beside the rest of the upgrade. The one
"why" sentence: a 17.x project's skills came from `skills add`; their
`skills-lock.json` entries read `sourceType: github`, so the sync skips
them (exit 0) and the agent keeps reading 17.x skill text. The three
commands:
```bash
npx skills remove objectstack-ai objectstack-api objectstack-automation \
objectstack-data objectstack-formula objectstack-i18n objectstack-platform \
objectstack-pm-dispatch objectstack-query objectstack-ui objectstack-upgrade -y
npm install --save-dev "@objectstack/skills@$(node -p "require('@objectstack/spec/package.json').version")"
npx skills@1.7.2 experimental_sync --agent claude-code --copy -y
```
- **The remove list is the devx seat's eleven names** (pointer comment
6148721272: `objectstack-pm-dispatch` was in the catalog through the
`@objectstack/spec` 17.0.0–17.4.0 trees; a ten-name remove on a 17.4.0
project printed `Found 11 / removed 10`), copied byte for byte from
`content/docs/upgrading.mdx` lines 108–110 at this tree, so the skill
and the site read the same. The prose names the two facts the site
states beside it: a missing name is skipped (exit 0), and `--all` does
the same when these are the project's only skills.
- **The sync spelling is the scaffolder's**, read from
`packages/create-objectstack/src/skills-install.ts` at `441106662a`
(unchanged since the dispatch tree `228357ab69`): line 102 `export const
SKILLS_CLI = 'skills@1.7.2';`, line 119 `` return `${SKILLS_CLI}
experimental_sync --agent ${agent} --copy -y`; ``, line 127 `` export
const SKILLS_INSTALL_COMMAND = `npx -y
${skillsSyncArgs(DEFAULT_SKILLS_AGENT)}`; `` — so what the scaffolder
RUNS is `npx -y skills@1.7.2 experimental_sync --agent claude-code
--copy -y`, and what it PRINTS for a user to run later (line 131,
`skillsInstallHint`) is `npx skills@1.7.2 experimental_sync --agent
AGENT --copy -y`. The skill and both READMEs carry the printed form, as
`content/docs/upgrading.mdx:97,112` and `skills-reference.mdx:24` do;
the `-y` after `npx` only suppresses npx's own install prompt for the
pinned CLI, and the trailing `-y` is the CLI's.
## Paying for it under the token ratchet (`ceil(utf8 bytes / 4)`, the
release-stamp line excluded)
The step costs 815 bytes (about 204 tokens, 16 lines) — more than the
card's 60–100 estimate, because the eleven-name list alone is 234 bytes.
It is paid by six deletions in the same file, each a sentence the file
states elsewhere; no re-wrap and no ceiling move. Every deleted sentence
and its home:
| # | deleted (section) | home in the same file |
|:--|:--|:--|
| 1 | "Everything below is the long form of those four steps." (under
Quickstart) | the Quickstart's four `# N ·` comments and the four `## N
·` section headings |
| 2 | "Below the floor, upgrade to it by the older route first, then run
the chain." (§0, FROM major) | Failure modes row `MigrationFloorError`:
"Upgrade to the floor by an older route first; the floor is a
release-policy boundary, not an oversight." |
| 3 | "Porting the edits left unwritten is yours, one `conversionId` at
a time; use `--out` as the oracle you diff against, never as the file
you ship." (§1) | Failure modes row 1 ("Pass `--write`, or port the
printed edits by hand; then replay from the target major to confirm 0
changes"), row 2 ("Diff against `--out`"), and the boundary section's
"One `conversionId` per commit" |
| 4 | the first R2 trap bullet, "A renamed context field keeps
compiling. … assert the value observed under the canonical key." (§2.5)
| §2.2's R2 definition ("or worse, keeps compiling while reading
`undefined`") and Failure modes row 3 ("An R2 residue item: code reading
a renamed key now reads `undefined`. Exercise the path for real."). The
intro "Two traps…" becomes "One trap…" with the surviving bullet folded
into the sentence. |
| 5 | "Fixing the project's standing lint debt may be a welcome
side-effect, but it is not this upgrade, and it must not be reported as
part of it." (§3.3) | the same paragraph ("a **pre-existing**
project-quality issue, not upgrade residue") and Failure modes row 5
("Pre-existing findings are not this upgrade's scope") |
| 6 | "Run both. A report that cites only `validate` cannot see this
class at all." (§3.3 call-out) | the call-out's own "`validate` green is
necessary and not sufficient, and the criterion that closes the gap is
the replay", the Quickstart's "# 3 · acceptance — all four, not three",
and the §3.5 outcome table's third row |
No eval or reference file names any deleted sentence (`grep` over
`skills/objectstack-upgrade/evals/` and `references/` for the deleted
phrases: 0 hits), and `git grep` repo-wide outside the file: 0 hits.
## Readings — before (`origin/main` `e790cfc503` = the branch base) and
after (this head `441106662a`)
| surface | before | after | net |
|:--|:--|:--|:--|
| `skills/objectstack-upgrade/SKILL.md` | 24746 bytes / 485 lines /
**6180 tokens** (ceiling 6188, headroom 8) | 24715 bytes / 484 lines /
**6172 tokens** (ceiling 6188, headroom 16) | −31 bytes, −1 line, −8
tokens |
| `skills/README.md` (outside the ratchet's population; ships as
`dist/skills/README.md`) | 8322 bytes / 128 lines / 2081 tokens | 8506
bytes / 130 lines / 2127 tokens | +184 bytes, +2 lines |
| `packages/skills/README.md` (not under `skills/**`; the npm page) |
4024 bytes / 74 lines / 1006 tokens | 4224 bytes / 76 lines / 1056
tokens | +200 bytes, +2 lines |
| whole package — `check-skills-token-ratchet`'s "ratcheted (authored)"
sum, 54 files | 144089 / 154888 | 144081 / 154888 | −8 tokens |
| whole package — "bundle total (whole shipped tree)", 64 files | 155052
| 155044 | −8 tokens |
| every `skills/*/SKILL.md`, 10 files | 210600 bytes / 4409 lines |
210569 bytes / 4408 lines | −31 bytes, −1 line |
Line budget from the claim: SKILL.md net lines ≤ +6 (actual −1); each
README ≤ +2 (actual +2 and +2). The generated index block of
`skills/README.md` is byte-identical (`check:skill-docs` ✓
`skills/README.md`, and the diff touches lines 5–21 only).
## The READMEs
- `skills/README.md`: "sync it" → "copy it"; the command line becomes
`npx skills@1.7.2 experimental_sync --agent claude-code --copy -y`; the
paragraph below opens with why `--copy` (real files in
`.claude/skills/`, to commit with the project; without it, links into
`node_modules`, which a clone does not have) and points the move from a
`skills add` install at the Skills reference, whose `#installing-skills`
section carries it. The linked form is dropped, not kept: the
one-sentence explanation of what it does is the whole mention. The
`next` channel paragraph is unchanged.
- `packages/skills/README.md`: step 2 becomes "copy it …" with the same
command; the paragraph below says the sync copies real files and records
the source in `skills-lock.json`, why to keep `--copy`, and that the CLI
is pinned to the version `create-objectstack` runs. The "Projects
scaffolded by `create-objectstack`" paragraph (remove first — `npx
skills remove --all`, or name the `objectstack-*` skills — then steps 1
and 2) already matches the pointer's `--all` alternative and is
unchanged; "Through `18.0.0-next.0`" is still true of every published
`create-objectstack` (the package is at `18.0.0-next.0` on this tree).
## Verification (every exit captured before any pipe: `cmd > log 2>&1;
EXIT=$?`; logs under the session scratchpad `issue-23276/gates/`)
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` (no paths: the change set from the merge
base) derived **68** commands from the tree at `441106662a` (the same 68
on `f88e80d981`; `origin/main` had moved 3 commits, so `origin/main` was
merged first and the list re-derived). Each ran in the foreground,
sequentially; `--ran` reconciliation: `✓ dispatch-gates --ran: 68
derived famil(ies) accounted for — 66 run, 2 NOT-MEASURED (2 DERIVED
from a recorded exit 3).` 0 UNRUN. All 66 exit 0.
- **NOT MEASURED locally (exit 3, PREREQUISITE NOT MET), declared to
CI:** `pnpm check:dts-closure` and `pnpm check:dual-build-cjs-loads`
read every package's built `dist/`; a turbo dry run on this tree reads
82 of 83 build tasks as cache MISS, and the full build does not fit a
foreground call on the shared box. This diff changes three markdown
files and a changeset — no source, `exports` or type entry — so their
population is unreachable by it. `Lint & Repo Gates` runs both on the
PR. The two other exit-3 refusals of the first pass
(`check:doc-formula-expressions`, `check:lean-entry-closure`) were
re-run to exit 0 after `pnpm turbo run build
--filter='@objectstack/lint...' --filter='@objectstack/objectql...'
--concurrency=2` under the verify lock (14 tasks, 2m18s, `VERDICT
command-exit 0`).
- **The card's named gates:** `check:skill-compatibility` 0 (`11 pinned
major(s) all match the workspace`), `pnpm --filter @objectstack/spec run
check:skill-docs` 0 (`✓ skills/README.md`, `✅ Skill docs in sync`),
`check:skill-refs` 0 (`9 generated files in sync`),
`check:skills-token-ratchet` 0 (the readings above, from the sweep on
this head), `check:published-readme-links` 0 (`226 outbound link(s)
across 104 published markdown file(s) … 2 anchor(s) verified`),
`check:published-readme-exports` **3 — NOT MEASURED**: `48 package(s)
whose built type entry this run would read are not built` (same
prerequisite as above; neither README carries an import, their fenced
blocks are `sh`/`bash` commands). `git status` clean after the two spec
checks.
- **Changeset gates:** `check-empty-changeset --base origin/main` 0 (`1
declaring changeset(s) added`, no base changeset modified),
`check-changeset-no-major --base origin/main` 0,
`check-adr-0087-registration --base origin/main` 0 (`this PR adds no
declared-breaking changeset`), `check:changeset-gate-self-tests` 0,
`check:pm-changeset-deadline-census` 0, `check:published-files` 0. ⛔ No
`skip-changeset`: both READMEs and the skill text ship in the
`@objectstack/skills` tarball (`files`: `dist`, `README.md`,
`CHANGELOG.md`).
- **The package itself:** `@objectstack/skills` has no workspace
dependencies (step ① closure empty) and declares `build` and
`prepublishOnly` only (no `test`/`typecheck` to run; a zero-match
`--filter` run would exit 0 having run nothing, so none is cited). `pnpm
--filter @objectstack/skills build` under the verify lock: `VERDICT
command-exit 0`, `65 file(s) across 10 skill(s) copied from skills/**
into dist/skills and read back byte-identical`; `cmp skills/README.md
packages/skills/dist/skills/README.md` and `cmp` of the SKILL.md against
its dist copy both identical.
- **`pnpm lint`, narrowed and measured:** `eslint --no-inline-config
--format json` over the four files answers 4 results, 0 errors, one
warning each — `File ignored because no matching configuration was
supplied` (eslint's own config, not a guess); `eslint.config.mjs:328`
states no type-aware linting is enabled, so no untouched file's verdict
can move. Population reachable by this diff: 0 files.
- **Bytes:** control-character grep (`[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]`,
`-naP`) over the four files: exit 1, 0 hits; `check:nul-bytes` 0; no
HTML comment added (0 added lines carry one); `check:pm-governed-merges`
0.
- No reverse verification or ablation applies: the diff is prose and a
changeset, with no gate, test or runtime path whose verdict it could
move.
## Acceptance notes
- Tier H (`skills/**`): this PR stays a draft until an authorized
APPROVED review; no seat readies it or arms auto-merge. The seat
requests the review.
- The Quickstart block (`# 0 · preflight`) does not name the skills
step; the long-form §0 does. Adding a comment line there costs about 15
tokens and was not spent — a reviewer who wants it there can ask and the
seat pays it with one more same-file deletion.
- Eleven names versus `--all`: the step carries the eleven-name list as
its primary spelling (the card's and the site's), with `--all` as the
stated alternative. Swapping to `--all` as primary would return about
150 bytes to the ratchet; the maintainer's preference decides, not this
PR.
- Observation, noted, not filed (no class a/b/c evidence): §0 of the
skill still says "down to the chain's support floor, 16 today", a pinned
number the same skill tells its reader never to carry (§2.1), while
`spec-changes.json` carries `supportFloor` and the §2.1 snippet already
prints it. Carrier: the next PR that edits this file; this one did not
spend the ratchet on it.
- Observation, noted, not filed: `packages/skills/README.md`'s "Through
`18.0.0-next.0` the scaffolder installs the skills from the `next`
channel" and `skills-reference.mdx:31`'s matching sentence go stale when
`create-objectstack` publishes a version above `18.0.0-next.0` with the
package-based scaffolder (PR #23248, on `main`, unreleased). Carrier:
the Version Packages release that bumps it; the sentence is true of
every published scaffolder today.
- The two NOT MEASURED families above are the only narrowing; it is
declared here and in the report, and CI measures them.
- #23275 is not addressed here (the devx lane's docs pass, landed as PR
#23295); `content/docs/**` is untouched.
- Commit trailers are the model-free pair AGENTS.md requires; no card
relation rides a commit — this body is the one carrier.
## 维护者速读(草稿)
**改了什么。** 对外发布的升级技能 `objectstack-upgrade` 的「0 · 预检」多了一步:17.x 项目的 AI 技能是用
`skills add` 从仓库 `main` 装的,`skills-lock.json` 里记为 `sourceType:
github`,新的同步命令会静默跳过它们(退出码 0),于是只升包不升技能的项目,`.claude/skills/` 里仍是 17.x
的技能文本。这一步先删掉 17.x 目录曾含的十一个 `objectstack-*`
技能(与官网升级页同一份名单;名单里没装的会被跳过;只装了这些技能的项目可用 `--all`),再按已装 `@objectstack/spec`
的版本安装 `@objectstack/skills`,最后用脚手架同一条钉版本、带 `--copy` 的命令复制进代理目录。同时,随
`@objectstack/skills` 发布的两份 README(目录首页与 npm
页面)把未钉版本、生成软链接的同步命令换成脚手架这条拼写,并说明为何要 `--copy`(软链接指向
`node_modules`,克隆后是悬空链接)。附一个 `@objectstack/skills` 的 patch
changeset。`content/docs/**` 与脚手架源码一字未动。
**为什么改。** #22649 裁决 A:技能目录随 `@objectstack/*` 一起装、一起升,GitHub 路径只是 `next`
渠道。升级手册此前对技能只字未提(实测 `grep` 为 0 行),升级者按手册走完,技能文本停在 17.x 且同步静默跳过——这是 devx
席位在 17.4.0 项目上实测到的(十个名字删了十个、找到十一个,`objectstack-pm-dispatch`
留在原地),所以名单是十一个。
**风险与代价(含回滚)。** 纯文本改动,无行为变化。代价全在技能文件的 token 棘轮:该文件此前只剩 8 个 token 余量,这一步要
815 字节(约 204 token),比卡上估的 60–100 多,因为十一个名字本身就 234
字节;用同文件六处「别处已有原话」的句子抵掉(每句与其落点见上表),未折行、未抬上限,落地后余量 16。两份 README 各净增 2
行,恰在认领给的预算上。回滚即 revert 本 PR 的单个 squash 提交;changeset
未被消费前删除即无痕。本地未测到的两族门禁(`dts-closure`、`dual-build-cjs-loads`)要全仓构建,本次改动触不到它们的判定面,交
CI 测。
**席位意见。** (留空,席位定稿成评论。)
**你要做的。** 本 PR 含 `skills/**`,属 Tier H:只需您在 PR 上给一个 APPROVED
review(任一提交上、不撤回即可),席位随后负责排队落地;不需要您合并。两处可一句话定的措辞:① 删除名单以十一个名字为主、`--all`
为备(与官网一致),若您更想以 `--all` 为主,席位代改并把省下的约 150 字节退还棘轮;② Quickstart 的 `# 0 ·
preflight` 块未点名技能这一步(长文 §0 有),要加约 15 个 token,席位可再删一句同文件复述来付。
---
_Generated by [Claude
Code](https://claude.ai/code/session_013zGKMG1cRedVzWtqGGGZW9)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent f24574a commit 713f231
4 files changed
Lines changed: 50 additions & 36 deletions
File tree
- .changeset
- packages/skills
- skills
- objectstack-upgrade
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
30 | | - | |
31 | | - | |
| 30 | + | |
| 31 | + | |
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
35 | | - | |
36 | | - | |
37 | | - | |
38 | | - | |
39 | | - | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
40 | 42 | | |
41 | 43 | | |
42 | 44 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
| 8 | + | |
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
12 | | - | |
| 12 | + | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
16 | | - | |
17 | | - | |
18 | | - | |
19 | | - | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
20 | 22 | | |
21 | 23 | | |
22 | 24 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
78 | | - | |
79 | | - | |
80 | 78 | | |
81 | 79 | | |
82 | 80 | | |
| |||
102 | 100 | | |
103 | 101 | | |
104 | 102 | | |
105 | | - | |
106 | | - | |
| 103 | + | |
107 | 104 | | |
108 | 105 | | |
109 | 106 | | |
| |||
117 | 114 | | |
118 | 115 | | |
119 | 116 | | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
120 | 133 | | |
121 | 134 | | |
122 | 135 | | |
| |||
157 | 170 | | |
158 | 171 | | |
159 | 172 | | |
160 | | - | |
161 | | - | |
162 | | - | |
163 | 173 | | |
164 | 174 | | |
165 | 175 | | |
| |||
318 | 328 | | |
319 | 329 | | |
320 | 330 | | |
321 | | - | |
322 | | - | |
323 | | - | |
324 | | - | |
325 | | - | |
326 | | - | |
327 | | - | |
328 | | - | |
329 | | - | |
330 | | - | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
331 | 334 | | |
332 | 335 | | |
333 | 336 | | |
| |||
383 | 386 | | |
384 | 387 | | |
385 | 388 | | |
386 | | - | |
387 | | - | |
388 | | - | |
| 389 | + | |
389 | 390 | | |
390 | 391 | | |
391 | 392 | | |
| |||
408 | 409 | | |
409 | 410 | | |
410 | 411 | | |
411 | | - | |
412 | | - | |
413 | 412 | | |
414 | 413 | | |
415 | 414 | | |
| |||
0 commit comments