Skip to content

[devx] the spec-property-retirement skill still prescribes the withdrawn "rewrite it automatically" tombstone sentence — a pin test reds anything that follows it #10848

Description

@os-zhuang

Found while correcting the four docs-site pages that said os migrate meta --from rewrites your sources (PR #10847). That PR closed the hand-written docs residue; this is the one remaining prescriptive carrier, and it is upstream of all of them — it tells future agents to author the false sentence again.

The defect

.claude/skills/spec-property-retirement/SKILL.md:150, in the "guidance 字符串怎么写" convention list that every new retiredKey() tombstone is authored from:

  1. Run `os migrate meta --from <N-1>` to rewrite it automatically. —— 仅当有 conversion 重写 sources。

That sentence is the withdrawn claim, twice over:

  • os migrate meta --from rewrites no file. It replays the ADR-0087 chain over the loaded stack in memory and prints the mechanical edits. Both writeFileSync calls in packages/cli/src/commands/migrate/meta.ts are guarded by if (flags.out) (:347, :394-396), so the only file it writes is the --out JSON snapshot; the command header at :155-157 declines the AST rewrite as "unsafe and lossy". The in-place codemod is feat(cli): os migrate meta --write — the AST codemod that rewrites authored sources for the mechanical applied set (v18) #9591 (v18, pm:on-hold), unbuilt.
  • "automatically" is the exact word the class-wide reword was written to remove.

The skill's own condition — "仅当有 conversion 重写 sources" — describes a capability that does not exist for any conversion, so the guarded branch is unreachable as written.

Why this is worse than a stale doc line

packages/spec/src/shared/retired-key-migrate-sentence.test.ts is a class pin that holds both directions. From its docblock:

This pin therefore holds BOTH directions — the new sentence is required where a prescription names the command, and the withdrawn claim is a hard RED wherever it reappears.

The house sentence it requires:

Run `os migrate meta --from <N>` to list the mechanical edits for
existing sources; apply them by hand.

But the pin's population is packages/spec/src plus one occurrence in packages/lint/src/validate-expressions.ts. .claude/** is outside it. So the skill and the pin now disagree, and the skill is the one agents read first:

An agent retiring a property follows the skill, writes the prescribed sentence into a new tombstone, and the pin reds the PR. Best case that costs a round. Worst case the agent reads a red pin as the broken thing and weakens it to match the skill — which is how the withdrawn promise gets restored across ~90 shipped prescriptions that #9529 cleaned.

Evidence the skill is the last live prescriptive carrier

Scanning the tree for to rewrite it automatically / to rewrite existing sources automatically:

carrierstatus
packages/spec/src/shared/retired-key-migrate-sentence.test.tsthe deliberate pin — asserts the string is RED
packages/spec/CHANGELOG.md, packages/lint/CHANGELOG.md, packages/platform-objects/CHANGELOG.md, examples/app-todo/CHANGELOG.mdhistorical release records, never edited
docs/qa/platform-checklist/areas/cli.jsonthe ledger describing the correction
.claude/skills/spec-property-retirement/SKILL.md:150live prescription — tells authors to emit it

packages/spec/src carries no shipped prescription with the withdrawn wording; that half is clean. cli.json revision 3 states "the only other carriers are the deliberate pin test and four CHANGELOGs" — the skill was not counted in that census, which is likely why it survived.

Suggested disposition

Replace convention 5 with the house sentence the pin requires, and drop the "仅当有 conversion 重写 sources" condition (no conversion rewrites sources). The pin's docblock also documents the ONE allowed variant, by shape, for conversions covering only part of a value — worth carrying into the skill so authors have both forms.

⛔ Not actionable by a dev agent unassisted: .claude/** is governed, human-merge-only. Filed for maintainer routing rather than fixed in PR #10847.

Refs: PR #10847 (the docs-site half) · #9529 (the class-wide reword) · #6856 (the original two-verb split) · #9591 (the unbuilt in-place codemod) · packages/spec/src/shared/retired-key-migrate-sentence.test.ts (the pin).


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions