Skip to content

docs(skills): objectstack-upgrade's late-arrival example starts at the support floor - #22145

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-22123-upgrade-skill-late-arrival-floor
Oct 8, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/issue-22123-upgrade-skill-late-arrival-floor

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #22123

Clause-②: no

The published upgrade skill's "several majors late" paragraph examples os migrate meta --from 10. The chain refuses every --from below MIGRATION_SUPPORT_FLOOR = 16 (packages/spec/src/migrations/registry.ts:79) with MigrationFloorError — exit 1, --json error: unsupported_from_major — and the same file's failure-mode row already says so. This PR rewords the paragraph so its point (lateness is the designed-for case) is stated with an example the chain accepts and with the floor in the same breath, within the file's token ceiling. #22120 is landed (PR #22122, same file); this branch cuts from origin/main after it.

What changed (one file: skills/objectstack-upgrade/SKILL.md)

The paragraph under §0 "Establish the FROM major", before:

Arriving several majors late is the designed-for case. `os migrate meta --from 10`
replays every step in order; there is no penalty for lateness and no requirement
to upgrade one major at a time.

after:

Arriving several majors late is the designed-for case: `os migrate meta --from 16`
replays every step in order, with no requirement to upgrade one major at a time —
down to the chain's support floor, 16 today. Below the floor, upgrade to it by
the older route first, then run the chain.

The example is now the floor itself (the chain's lowest accepted --from, and the spelling every other example in the file already uses); the floor's value is stated where the reader decides --from; the below-floor case carries the same remedy the failure-mode row and the CLI's own refusal text give ("Upgrade to protocol 16 by another path first, then re-run"). "There is no penalty for lateness" is dropped as restating "the designed-for case". Nothing else in the file states a --from below 16: grep -rn -F -- '--from 10' skills/objectstack-upgrade/ is now 0 hits (control: --from 16 12 hits in SKILL.md), and references/examples-upgrade.md and evals/protocol-major-upgrade.json never carried the example.

Token ratchet — paid in content, not wrapping

node scripts/check-skills-token-ratchet.mjs (tokens = ceil(utf8 bytes / 4); ceiling for this file 6193):

reading lines bytes tokens headroom
before (ef1fcb26a2, the file as #22122 left it) 484 24748 6187 6
after (3e842f9fd8) 485 24736 6184 9

Whole package (the ten skills/*/SKILL.md): 4407 → 4408 lines, 52575 → 52572 tokens; the ratchet's authored-bundle total 144050 → 144047 (shipped tree 154836 → 154833). Diff: +6 / −5 lines. Gate line at 3e842f9fd8: ✓ check-skills-token-ratchet: skills/objectstack-upgrade/SKILL.md is 6184 tokens (ceiling 6193; headroom 9).

The paragraph grew by +94 bytes (197 → 291). That is paid by deleting two clauses the same file states beside them — no rule, failure-mode row or command among them, and no line re-wrapped:

  1. the trailing comment on mkdir -p .upgrade in §0's "Make the work reviewable" block ("every artifact this skill produces lands here", −57 bytes) — the paragraph directly under the block opens "The .upgrade/ directory is the deliverable's workspace" and lists the artifacts;
  2. the clause "which is exactly what the table above points at" closing §2.1's "Not reachable from a consumer project" callout (−49 bytes) — the callout's sentence already names spec-changes.json and the chain's --json output, which are two rows of that table.

Net −12 bytes.

Scope held

  • One file, as the claim's file surface allows. No packages/spec/**, no packages/cli/**, no content/docs/**; references/examples-upgrade.md and evals/protocol-major-upgrade.json untouched (neither carries the example; the eval's must_contain is os migrate meta --from 16, which still holds). Frontmatter unchanged: check:skill-docs and check:skill-refs green ("Skill docs in sync", "9 generated files in sync").
  • The floor's value is written as "16 today" the way the file already writes --from 16, ^17 and "The 16 → 17 crossing"; the frontmatter's compatibility line keeps the general statement ("the chain replays from the spec's MIGRATION_SUPPORT_FLOOR"), and §2.1's reading prints supportFloor from the installed spec. When the floor moves, this sentence is one of the file's dated numbers, not the only one.

Gates

Derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on this tree (24 families at ef1fcb26a2 and again at 3e842f9fd8; identical to the PM's path-derived list). All 24 run, exit 0 each, recorded beside the printed command and reconciled with --ran ("24 derived, 24 run, 0 NOT-MEASURED, 0 UNRUN", a derived zero). check:doc-formula-expressions first exited 3 (prerequisite: @objectstack/formula and @objectstack/lint not built) and was re-run green after the prescribed build under the verify lock. Beyond the derived list, also green: check:skill-top-level-keys, check:skill-frame-freshness, check:skill-refs. NOT MEASURED: check:skill-examples (prerequisite: the client SDK dist is not built; outside the derived list, and this diff touches no SDK example).

Acceptance notes

  • Observation, not changed and not a card: neither this skill nor the CLI's refusal text names what "the older route" / "another path" is for a project below the floor (install the spec major that still reaches it and run its chain, then continue from 16). The refusal is loud and the remedy's direction is stated; naming the route is a product sentence for the maintainer, not a drift fix. Carrier: none.

维护者速读(草稿)

改了什么:只改一份对外发布的技能文件 skills/objectstack-upgrade/SKILL.md 的一个段落。原文以 os migrate meta --from 10 作为"晚几个大版本再升级也没关系"的示例,但迁移链的支持下限是 16(MIGRATION_SUPPORT_FLOOR = 16),--from 10 会被 CLI 直接拒绝(MigrationFloorError,退出码 1)。现在示例改为链接受的 --from 16,同一句话里说明下限(今天是 16),并告诉低于下限的项目先用旧路线升到 16 再跑链——与同一文件故障表里已有的那一行一致。

为什么改:这份技能随每次 npx skills add 整包进入客户项目的 agent 上下文;一句教人运行会被拒绝的命令的话,是发布面上的错误句子(NORTH-STAR「优先级」第 4 条)。CLI 的拒绝挡住了实际伤害,但文字不改就一直是错的。

风险与代价(含回滚):纯文本改动,无代码、无 changeset、无生成物变化。token 棘轮:6187 → 6184(上限 6193),净减 12 字节,靠删除两处紧邻处已有陈述的重复子句支付(一处代码块尾注,一处收尾从句),未删任何规则、故障行或命令,未折行。回滚即 revert 本 PR 的一个提交。注意:下限值"16"写成了具体数字,与文件里其它写死的 --from 16、^17 同样随下限移动而需要更新;frontmatter 与 §2.1 的读数保留了通用表述。

席位意见:(留空,席位定稿)

你要做的:skills/** 为 Tier H 受管面:请以授权账号 APPROVE 一次,或亲手合入;本 PR 保持 draft,不由 agent 翻 ready。


Generated by Claude Code

…e support floor

The "several majors late" paragraph examples `os migrate meta --from 10`,
which the chain refuses below MIGRATION_SUPPORT_FLOOR = 16 with
MigrationFloorError. Reword it: the example is now `--from 16`, the floor is
stated in the same breath (16 today), and a project below the floor is told
to upgrade to it by the older route first, then run the chain.

Token ratchet (ceil(utf8 bytes / 4), ceiling 6193): 6187 -> 6184. The reword
is paid by deleting two clauses the same file already states beside them —
the `mkdir -p .upgrade` trailing comment (the paragraph under the block says
it) and "which is exactly what the table above points at" (the table above is
those two sources). No re-wrap.

Claude-Session: https://claude.ai/code/session_01CXydFDyiQwNbGFkmwrcRQq
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 3e842f9fd8f667f2b22066787d69fd1db6b53694
Local-runs: none

Reviewed in-seat by the skills seat 1 (dispatching seat; this session is served at the contract-review tier, read off get_session), 2026-10-08T03:12Z. Face hit: governed rule text (skills/objectstack-upgrade/SKILL.md, Tier H). Read-only shape held: the diff (get_files = 1 file, +6/−5), the card #22123 and its thread, the head's check-runs; nothing built or run locally. Premises re-read on origin/main at ef1fcb26a2, not taken from the report.

① Derived judgments

  1. Example os migrate meta --from 10 → --from 16: correct. MIGRATION_SUPPORT_FLOOR = 16 (packages/spec/src/migrations/registry.ts:79); the chain refuses every --from below it (packages/spec/src/migrations/chain.ts:177-178: "Cannot migrate from protocol N: the chain's support floor is 16 (ADR-0087 D3). Upgrade to protocol 16 by another path first, then re-run."; packages/cli/src/commands/migrate/meta.ts:975 emits unsupported_from_major). 16 is the lowest accepted value and the spelling the file's other eleven --from 16 occurrences use; the eval must_contain os migrate meta --from 16 still holds.
  2. "down to the chain's support floor, 16 today": correct and consistent with the file's existing dated numbers (--from 16, ^17, "The 16 → 17 crossing"); the frontmatter compatibility line keeps the general statement and §2.1 prints supportFloor from the installed spec. The sentence is one more dated number, not the only one.
  3. "Below the floor, upgrade to it by the older route first, then run the chain": correct, the same remedy direction as the failure-mode row at SKILL.md:472 (MigrationFloorError) and the CLI's own refusal text. Neither names the route; that observation is the dev's and stays a note (below).
  4. Dropped "there is no penalty for lateness": correct, it restated "the designed-for case" in the same sentence; no rule, command or failure row lost.
  5. Ratchet payment, clause 1: the trailing comment on mkdir -p .upgrade ("every artifact this skill produces lands here", −57 bytes). Survives in the paragraph directly under the block (head :115, "The .upgrade/ directory is the deliverable's workspace", listing the artefacts). Nothing lost.
  6. Ratchet payment, clause 2: "which is exactly what the table above points at" closing §2.1's "Not reachable from a consumer project" callout (−49 bytes). Survives: the callout's sentence still names spec-changes.json and the chain's --json output (head :247), the two rows the clause pointed at. Nothing lost. No line re-wrapped: the diff is +6/−5 inside three hunks, each a content edit.
  7. Ratchet reading pinned to the head: 6187 → 6184 tokens, ceiling 6193, headroom 6 → 9; the PR body quotes the gate line at 3e842f9fd8. The CI reading is the Lint & Repo Gates job on this head (status at this record's clock recorded in the ACCEPT on skills(objectstack-upgrade): the "several majors late" paragraph still examples os migrate meta --from 10, which the chain refuses below MIGRATION_SUPPORT_FLOOR = 16 (MigrationFloorError) #22123; landing waits on it being success either way).
  8. The one other --from below 16 in the published skills, SKILL.md:93 (the range example whose lower bound is 15 and upper bound 18, derived to --from 15): not this defect's class, untouched and judged correct as is. The line teaches range arithmetic (take the lower bound, never the upper), not that the chain accepts 15; the reworded paragraph two lines below now gives the below-floor case its remedy. The PR body's sentence "Nothing else in the file states a --from below 16" is therefore over-stated (its grep was --from 10 only); corrected in the ACCEPT, mechanism unaffected.
  9. Frontmatter unchanged; references/examples-upgrade.md and evals/protocol-major-upgrade.json untouched (neither carried the example). No packages/spec/**, no packages/cli/**, no content/docs/**.

② Semver level

None. Prose-only edit to a published skill file; no package files[] content, no API, no schema. skip-changeset on the PR is the correct declaration for this repository (docs-only), read back on the PR.

③ Boundary flags

  • Dev flag (acceptance note): the "older route" below the floor is unnamed in the skill and in the CLI refusal text. Answered: stays a note, not a card. The refusal is loud and states the remedy's direction; naming the route is a product sentence for the maintainer (raised in the seat-opinion section of the maintainer brief comment on this PR), not a drift fix.
  • open_questions: none reported.
  • Seat flag: judgment 8 above (the :93 illustration) is put to the maintainer in the maintainer brief comment, not ordered; a same-byte swap of that range example to one starting at 16 is available if they want the illustration to use an accepted value too.

Implemented-by: claude/issue-22123-upgrade-skill-late-arrival-floor
Reviewed-by: session_01CXydFDyiQwNbGFkmwrcRQq

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

维护者速读(终稿)

席位:skills 席 1,session_01CXydFDyiQwNbGFkmwrcRQq,2026-10-08T03:13Z。对照席位自己读的 diff(head 3e842f9fd8,一个文件 +6/−5)校正 dev 草稿;契约复核记录(PASS)与 ACCEPT 见本 PR 上一条评论与卡片 #22123。

改了什么:只改对外发布的技能文件 skills/objectstack-upgrade/SKILL.md 里 §0 的一个段落。原文以 os migrate meta --from 10 作"晚几个大版本再升级也没关系"的示例;但迁移链的支持下限是 16(MIGRATION_SUPPORT_FLOOR = 16,packages/spec/src/migrations/registry.ts:79),--from 10 会被 CLI 直接拒绝(MigrationFloorError,退出码 1,--json 报 unsupported_from_major)。现在示例改为链接受的 --from 16,同一句话里写明下限"今天是 16",并告诉低于下限的项目先走旧路线升到 16 再跑链——与同文件故障表里已有的那一行(:472)和 CLI 的拒绝文案方向一致。另删了两处紧邻处已有陈述的重复子句(一处代码块尾注、一处收尾从句),用来支付 token 棘轮;席位逐条核过,被删内容在旁边各有一句原样保留(:115、:247),没有丢规则、故障行或命令,也没有折行凑数。

为什么改:这份技能随 npx skills add 整包进入客户项目的 agent 上下文;一句教人运行会被拒绝的命令的话,是发布面上的错误句子(NORTH-STAR「优先级」第 4 条)。CLI 的拒绝挡住了实际伤害,但文字不改就一直是错的。

风险与代价(含回滚):纯文本改动,无代码、无 changeset(skip-changeset,docs-only)、无生成物变化;frontmatter 未动,check:skill-docs/check:skill-refs 在 head 的 Lint & Repo Gates 里已绿。棘轮读数 6187 → 6184(上限 6193,余量 6 → 9),净减 12 字节。回滚即 revert 本 PR 的单个提交。注意:下限值"16"写成了具体数字,与文件里其它写死的 --from 16、^17、"16 → 17" 同样随下限移动而需一并更新;frontmatter 与 §2.1 的读数保留了通用表述,所以它不是唯一一处。

席位意见:同意合入,席内契约复核 PASS。两点留给维护者,均未下令、不阻塞:① 同文件 :93 的范围推导示例(下界 15、上界 18 的区间)取下界得 --from 15,也低于下限;席位判它教的是"取区间下界"的算法而非"链接受 15",且新段落紧随其后已给出低于下限时的做法,故原样保留。若你希望发布面上不再出现任何低于下限的 --from 示例,把区间改成从 16 起是同字节数的一字之换,可让席位补一轮。② 技能与 CLI 拒绝文案都只说"先用旧路线/另一条路升到 16",没有点名那条路是什么(装仍覆盖该版本的 spec 大版本并跑它的链,再从 16 继续);这是产品句子,由你定是否写进技能。

你要做的:用授权账号(os-zhuang 或 hotlong)在本 PR 上 APPROVE 一次,或亲手合入。PR 保持 draft 不由 agent 翻 ready;收到授权 APPROVED 后由本席按落地前检翻 ready、挂 auto-merge 入队并收口 #22123。


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review October 8, 2026 03:30
@os-zhuang
os-zhuang enabled auto-merge October 8, 2026 03:30
@os-zhuang
os-zhuang added this pull request to the merge queue Oct 8, 2026
Merged via the queue into main with commit aaa4ad2 Oct 8, 2026
41 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-22123-upgrade-skill-late-arrival-floor branch October 8, 2026 04:04
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Oct 9, 2026
…does: lists the edits, `--write` applies the proven sites (objectstack-ai#22199)

Fixes objectstack-ai#22144

Clause-②: no

Two published lines in the objectstack-data skill said `os migrate meta
--from 16` strips the retired index keys `type` and `partial` ("to strip
them automatically" at `rules/indexing.md:31`, "strips them" at
`SKILL.md:377`). Neither was true of the tool: the default run writes no
authored source file, and `--write` rewrites only the sites it can
prove. Both lines now carry the house sentence. The closing enumeration
of every `os migrate meta` sentence in `skills/**` is below; every other
hit reads true and is left byte-for-byte alone.

Family: objectstack-ai#22120 is landed (PR objectstack-ai#22122, the upgrade skill) and objectstack-ai#22123 is
landed (PR objectstack-ai#22145, the `--from 10` example); this PR is the family's
closing card. objectstack-ai#9591 (PR objectstack-ai#22142, spec lane) is referenced only: it moves
the spec tombstones to the same sentence and holds the class pin.

## The tool, re-taken on this tree (`0aa5205228`, cut from `origin/main`
at `1e5d322c1e`)

- `packages/cli/src/commands/migrate/meta.ts:762-769`, the flag
declaration, verbatim:

  ```ts
  write: Flags.boolean({
    description:
'Rewrite the authored source files in place for each mechanical change
traced to one literal in one '
+ 'project file; every other change is listed with the reason it was not
written. Never writes the '
      + 'manual (semantic) changes.',
    default: false,
    exclusive: ['stored'],
  }),
  ```

- `packages/cli/src/utils/authored-source-codemod.ts` (module header):
`--write` writes a diff change only when its path leads, through the
authored modules' syntax, to ONE object or array literal in ONE project
file and the loaded value agrees with that literal; anything else is
refused by a named reason and stays on the list for the author.
- `packages/spec/src/migrations/registry.ts:79`: `export const
MIGRATION_SUPPORT_FLOOR = 16;` — `applyMetaMigrations` throws
`MigrationFloorError` for any `--from` under it (`meta.ts:713-716`).
- `packages/spec/src/conversions/registry.ts:3906`: `id:
'object-index-type-partial-removed'` — the 16 → 17 step carries the
conversion, so "lists the mechanical edits" is true of these two keys
specifically, not only in general.
- House sentence (`packages/spec/src/shared/retired-key.ts`: "It must be
TRUE of the tool"). The tombstones on `main` close with "Run `os migrate
meta --from 16` to list the mechanical edits for existing sources; apply
them by hand." (`packages/spec/src/data/object.zod.ts:558,567`); PR
objectstack-ai#22142 moves that to "… `--write` applies the ones it can prove, and you
apply the rest by hand."; the upgrade skill says "By default `os migrate
meta` rewrites no source file"
(`skills/objectstack-upgrade/SKILL.md:153`) and "`--write` … rewrite the
proven sites in place" (`:132`). No third vocabulary is introduced here.

## The two edits

`skills/objectstack-data/rules/indexing.md:31-33` (headroom 1058 tokens
before):

- before: "… run `os migrate meta --from 16` to strip them
automatically. What to do instead is the subject of "Access methods and
partial indexes" below."
- after: "… run `os migrate meta --from 16` to list the mechanical
edits; `--write` applies the ones it can prove, and you apply the rest
by hand. What to do instead is the subject of "Access methods and
partial indexes" below."

`skills/objectstack-data/SKILL.md:377-378` (ceiling 6128, headroom 0
before — the shortest form that stays true):

- before: "Both are now a `tsc` error and a parse error; `os migrate
meta --from 16` strips them. Access methods and partial predicates are
database-layer migrations."
- after: "Both are now a `tsc` error and a parse error; `os migrate meta
--from 16` lists the edits; `--write` applies the ones it can prove, the
rest by hand."

### Token ratchet payment (`node
scripts/check-skills-token-ratchet.mjs`, `ceil(utf8 bytes / 4)` per
file)

The new sentence in `SKILL.md` costs 63 bytes over the old one. It is
paid by deleting one clause the same section restates — never by
re-wrapping, never by touching the ceiling:

- deleted (`SKILL.md:377-378`): "Access methods and partial predicates
are database-layer migrations." (70 bytes with its leading space);
- where its content survives, same file: `SKILL.md:387-388` "See
rules/indexing.md for composite indexes, unique scope, and how to build
partial / gin / gist indexes at the database layer." and `SKILL.md:44`
"Index Strategy (rules/indexing.md) — btree/gin/gist/fulltext, composite
indexes, partial indexes"; and in `rules/indexing.md` § "Access methods
and partial indexes", the section the retirement callout points at;
- net: 24512 → 24506 bytes, 6128 → 6127 tokens, headroom 0 → 1. The
ceiling row in `scripts/check-skills-token-ratchet.mjs` is not touched
(see Acceptance notes).

## `skills/**` readings — lines, and tokens as the ratchet counts them

| File | Before | After |
|:--|:--|:--|
| `skills/objectstack-data/SKILL.md` | 469 lines · 24512 bytes · 6128
tokens (ceiling 6128, headroom 0) | 469 lines · 24506 bytes · 6127
tokens (headroom 1) |
| `skills/objectstack-data/rules/indexing.md` | 229 lines · 8729 bytes ·
2183 tokens (ceiling 3241) | 230 lines · 8805 bytes · 2202 tokens |
| Whole package — every `skills/**/SKILL.md` summed | 4408 lines ·
210279 bytes | 4408 lines · 210273 bytes |
| Whole shipped bundle — the ratchet's own "bundle total" line | 154833
tokens (the gate run in a detached worktree at `1e5d322c1e`) | 154851
tokens (+18: −1 and +19) |

No eval under `skills/objectstack-data/evals/` quotes either sentence
(`grep -rn strip skills/objectstack-data/evals/` — 0 hits). Frontmatter
untouched; `check:skill-docs` and `check:skill-refs` both report in
sync.

## Closing enumeration — every `os migrate meta` sentence in `skills/**`

`git grep -n "os migrate meta" -- skills/` on `0aa5205228`: 30 hits in 5
files (`objectstack-data/SKILL.md` 1,
`objectstack-data/rules/indexing.md` 1, `objectstack-upgrade/SKILL.md`
21, `objectstack-upgrade/evals/protocol-major-upgrade.json` 5,
`objectstack-upgrade/references/examples-upgrade.md` 2) — the same lines
as on `origin/main`, since only the two data-skill lines moved. A
widened `git grep -n "migrate meta" -- skills/` adds one bare hit
(`objectstack-upgrade/SKILL.md:466`), judged too. Three tests per hit:
(a) the default run lists and writes no source; (b) `--write` rewrites
only the provable sites; (c) `--from N` is at or above
`MIGRATION_SUPPORT_FLOOR` (16). A line is changed only when it is false.

| File:line | Sentence (abridged) | Reading | Changed? |
|:--|:--|:--|:--|
| `objectstack-data/SKILL.md:377` | "`os migrate meta --from 16` strips
them." | FALSE on (a) and (b): the default run strips nothing; `--write`
strips only the proven sites | yes |
| `objectstack-data/rules/indexing.md:31` | "run `os migrate meta --from
16` to strip them automatically." | FALSE on (a) and (b) | yes |
| `objectstack-upgrade/SKILL.md:64-66` | Quickstart: `--from 16 --step`,
`--from 16 --json`, `--from 16 --out …`, under the comment "replay the
chain (writes only --out; --write also rewrites the sites it can prove)"
| true: (a) listing runs, `--out` is a snapshot and not a source; (b)
stated; (c) 16 | no |
| `objectstack-upgrade/SKILL.md:74` | "`os migrate meta --from 17
--json` — `applied` must be []" | true: the replay from the target
major; (c) 17 ≥ 16 | no |
| `objectstack-upgrade/SKILL.md:103` | "`os migrate meta --from 16`
replays every step in order … down to the chain's support floor, 16
today" | true: (c) the floor constant is 16 | no |
| `objectstack-upgrade/SKILL.md:124-133` | "What `os migrate meta`
actually does" and its command block (`--out` "write the canonicalized
stack", `--write` "rewrite the proven sites in place") | true on (a),
(b), (c) | no |
| `objectstack-upgrade/SKILL.md:153` | "By default `os migrate meta`
rewrites no source file … `--write` rewrites in place each edit it can
trace to one literal in one project file, lists every other with the
reason …" | true: matches the flag description | no |
| `objectstack-upgrade/SKILL.md:177-179` | `--stored` preview, `--stored
--type …` narrowing, `--stored --apply --yes` | true of the stored pass
(`write` is `exclusive: ['stored']`; `--apply` is the only writer there)
| no |
| `objectstack-upgrade/SKILL.md:215` | "`os migrate meta --from N
--json` → `.specChanges`" | true: the JSON face carries `specChanges`
(`meta.ts:881,928`); N is bounded by the floor sentence at `:103` | no |
| `objectstack-upgrade/SKILL.md:313` | "`os migrate meta --from 16
--json`" piped into `node -e`, reading `.todos` | true: (a) a listing
run; `todos` is the key (`meta.ts:459`) | no |
| `objectstack-upgrade/SKILL.md:404` | "`os migrate meta --from
TARGET_MAJOR --json` — `applied` must be []" (the placeholder is spelled
out here) | true: (a); (c) by construction | no |
| `objectstack-upgrade/SKILL.md:449` | "`os migrate meta --stored
--json` — 0 = every row canonical, 1 = work left" | true of the stored
pass: read-only, exit 1 while rows are pending (`storedMigrationClean`)
| no |
| `objectstack-upgrade/SKILL.md:466` | "`migrate meta` reports changes,
but the files are unchanged — working as designed, the default run only
lists — pass `--write`, or port the printed edits by hand" | true on (a)
and (b) | no |
| `objectstack-upgrade/evals/protocol-major-upgrade.json:7` | "`--step`,
`--json`, and `--out …` — the command rewrites nothing on disk, so port
the printed edits into the sources" | true of the invoked forms (none
carries `--write`; `--out` writes a new snapshot and rewrites no source)
| no |
| `objectstack-upgrade/evals/protocol-major-upgrade.json:10,20` |
`must_contain` token lists | not behaviour claims | no |
| `objectstack-upgrade/evals/protocol-major-upgrade.json:17` | "runs `os
migrate meta --from AUTHORED_MAJOR` to attribute the site to its
`conversionId`, ports `requiredWhen` …" (placeholder spelled out) |
true: (a) the listing attributes; the port is by hand | no |
| `objectstack-upgrade/evals/protocol-major-upgrade.json:37` | "Replays
`os migrate meta --from 17 --json` and reads `applied` … runs `os
migrate meta --stored` (read-only) then `--stored --apply --yes`" | true
on (a), (c), and of the stored pass | no |
| `objectstack-upgrade/references/examples-upgrade.md:57` | "Ported into
sources from `os migrate meta --out`." | true: hand-ported from the
snapshot | no |
| `objectstack-upgrade/references/examples-upgrade.md:79` | "`os migrate
meta --stored --apply` — rows rehydrate correctly today; this makes it
durable." | true of the stored pass | no |

## Local verification (tree `0aa5205228`; every exit code captured
before any pipe)

Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` (no paths; the tool took the changeset from
the merge-base itself): 24 commands. Run after the final commit as one
union with the tool's own loop idiom, recorded as `cmd :: exit N`, and
reconciled: `dispatch-gates --ran` — "24 derived, 24 run, 0
NOT-MEASURED, 0 UNRUN". All 24 exit 0:

`check-ci-filter-parity` · `check-closing-keyword-parity` (+
`--self-test`) · `check-comment-mask-corpus` · `check-doc-route-spelling
--advisory` (+ `--self-test`) · `check-skills-token-ratchet` (+
`--self-test`) · `@objectstack/lint check:doc-formula-expressions` ·
`@objectstack/spec check:skill-docs` · `check:agent-test-spelling` ·
`check:corpus-claim-drift` · `check:cross-package-test-inputs` ·
`check:doc-authoring` · `check:driver-memory-census` ·
`check:gitlink-declared` · `check:nul-bytes` ·
`check:pm-governed-merges` · `check:refd-timer-probe` ·
`check:role-word` · `check:skill-compatibility` ·
`check:skill-frame-sync` · `check:skill-identifier-liveness` ·
`check:watch-hint-literal`.

- `check:doc-formula-expressions` first answered exit 3 (PREREQUISITE
NOT MET — `@objectstack/formula` and `@objectstack/lint` were unbuilt;
nothing measured). After `pnpm exec turbo run build
--filter=@objectstack/formula --filter=@objectstack/lint
--concurrency=2` behind `scripts/pm/os-verify-lock.sh` (VERDICT
command-exit 0; held 92 s, waited 0 s) it exits 0.
- Also run, outside the derivation: `pnpm --filter @objectstack/spec run
check:skill-refs` exit 0 ("9 generated files in sync"); `pnpm
check:skill-top-level-keys` exit 0.
- NOT MEASURED locally, by design: the type-check lanes, the Test Core
shards, the 11 wide-population families and the 51 roster families the
derivation names are CI's; the 15 pending-changeset families do not
apply (no changeset — this diff publishes nothing from any released
package; label `skip-changeset`).

### Reverse verification of the ratchet payment (one-off; committed
first; `scripts/ablation-replace.mjs`)

- Attempt 1 was a no-op by the tool's own count check (the anchor was a
substring of its replacement, anchor count 1 → 1): refused and restored,
nothing measured.
- Attempt 2, re-anchored on "prove, the rest by hand." with the deleted
clause re-added: mutation landed on disk (blob `7220a34363d3` →
`efe8f6825326`); `node scripts/check-skills-token-ratchet.mjs` exit 1 —
"`skills/objectstack-data/SKILL.md` is 6144 tokens; the ratchet ceiling
is 6128 (over by 16)". Restore proven: blob == HEAD `7220a34363d3`, `git
diff HEAD` empty, `git status --porcelain` empty.

## Acceptance notes

- The class pin
`packages/spec/src/shared/retired-key-migrate-sentence.test.ts`
(`WITHDRAWN_CLAIM`) matches only "to rewrite … automatically" and the
"rewrites (it for you / existing sources / authored sources / your
sources / your source files)" spellings — no "strip" — so it never saw
these two lines, and nothing in this PR is implied to be covered by it.
Widening it is spec-lane work and the file is held by PR objectstack-ai#22142; it is
not touched here. Carrier: the `domain:spec` seat, via the skills seat's
relay.
- `skills/objectstack-data/SKILL.md` now sits 1 token under its
unchanged 6128 ceiling. Lowering the ceiling to 6127 is legitimate per
the gate's own header and outside this card's file surface. Carrier: the
next PR that touches `scripts/check-skills-token-ratchet.mjs`, or the
skills seat.
- Tier H (`skills/**`): this PR stays draft and lands on an authorized
APPROVED review or the maintainer's hand; no seat flips it ready.

## 维护者速读(草稿)

**改了什么**:objectstack-data
技能里两句话(`rules/indexing.md:31`、`SKILL.md:377`)原本说 `os migrate meta --from
16` 会"自动剥掉"/"剥掉"已退役的索引键 `type` 和 `partial`。改成工具的真实行为:默认只列出机械修改;`--write`
只落它能证明的那些站点;其余由作者手工完成。顺带把 `skills/**` 里所有 `os migrate meta`
句子逐条核对了一遍(上表),其余均属实,一字未动。

**为什么改**:这是对外发布的技能包(`npx skills add` 原样装进客户项目),读到这句的 AI
作者会以为源码已被清理,把退役键留在原地,直到 `tsc` 或解析报错才发现。`docs/NORTH-STAR.md` 优先级第 4
条:发布面上的错句就是产品缺陷;`retired-key.ts` 的内部裁决是"这句话必须对工具为真"。

**风险与代价(含回滚)**:纯文本改动,不碰代码、不碰 spec、不发包、无 changeset。`SKILL.md` 已顶在 token
上限,新句子靠删掉同一段里被下文重述的一句付账(内容仍在 `SKILL.md:387-388` 与
`rules/indexing.md`)。回滚 = revert 这一个提交。

**席位意见**:

**你要做的**:确认两句新措辞与 PR objectstack-ai#22142 正在采用的 house sentence 一致;同意则 APPROVE,由席位落地。

---
_Generated by [Claude
Code](https://claude.ai/code/session_01CXydFDyiQwNbGFkmwrcRQq)_

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/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants