Skip to content

docs(skills): pages.md rule 2 states the enforceable reason, not the retired ADR-0048 claim - #19445

Merged
hotlong merged 1 commit into
mainfrom
claude/issue-19358-pages-rule-2-retired-collision-claim
Sep 21, 2026
Merged

hotlong merged 1 commit into
mainfrom
claude/issue-19358-pages-rule-2-retired-collision-claim

Conversation

@os-steve

Copy link
Copy Markdown
Collaborator

Fixes #19358

Clause-②: no

Seat domain:skills#2 (seat post #19287), dispatched from the claim on #19358. Tier H: skills/** — this PR stays DRAFT; the seat reviews and ACCEPTs, the maintainer's own click lands it.

What changed

skills/objectstack-ui/rules/pages.md, authoring rule 2 only (:337–:341 at both 23f1de0 and this head 127576f). The rule (the stem must start with the package namespace) and the ADR-0048 citation stay; the REASON sentence is replaced with the facts the source enforces. Net 0 lines (+3 / −3), one file.

Before (23f1de0, :337–:341):

2. **Namespace-prefixed filename.** The filename stem becomes the doc
   `name` (`^[a-z][a-z0-9_]*$`) and must start with the package namespace
   (`crm_…`). Names share one flat, instance-global space with the URL, so
   a bare `user_guide` would collide across packages and fail at install
   (ADR-0048).

After (127576f, :337–:341):

2. **Namespace-prefixed filename.** The filename stem becomes the doc
   `name` (`^[a-z][a-z0-9_]*$`) and must start with the package namespace
   (`crm_…`). `os build` refuses a bare `user_guide`
   (`docs/namespace-prefix`) — hygiene, not uniqueness: two packages
   coexist on one bare name (ADR-0048 §3.4).

The three false clauses, re-measured on this tree, and the source line beside each new clause

# the old text said measured refutation (all at 23f1de0, unchanged at 127576f) the new clause it becomes
1 doc names share "one flat, instance-global space with the URL" docs/adr/0048-cross-package-metadata-collision.md :182–:183 「The route/container coordinate for an installed package's UI is its package id」 (§3.1); :222–:223 「resolves a bare name within the current package first, keyed on the package id」 (§3.3); packages/objectql/src/registry.ts :3452 const storageKey = packageId ? withDisc(${packageId}:${baseName}) : bareKey; — the storage key is composite PACKAGE_ID:NAME, not one flat space dropped; replaced by "two packages coexist on one bare name"
2 a bare name "would collide across packages" ADR-0048 :251–:252 「The cross-package throw is retired; two distinct packages coexist on the same bare name by construction」 (§3.4); registry.ts :3472–:3477 「ADR-0048 §3.4 — the per-item CROSS-package throw is retired … two installed packages shipping the same bare name (e.g. page/home) legitimately COEXIST under distinct composite keys」 — and no throw exists in :3458–:3511, only the ADR-0005 overlay console.warn "hygiene, not uniqueness: two packages coexist on one bare name (ADR-0048 §3.4)"
3 it "would fail at install" BUILD door: packages/cli/src/utils/collect-docs.ts :654–:658 if (namespace && !doc.name.startsWith(${namespace}_)) pushes severity: 'error', rule: 'docs/namespace-prefix'; packages/cli/src/commands/compile.ts :802–:811 if (docErrors.length > 0) { … this.exit(1); }. INSTALL door: registry.ts :4155–:4168 refuses on manifest.namespace ownership and :1456 constructor(namespace: string, existingPackageId: string, incomingPackageId: string)NamespaceConflictError is built from a namespace, never a doc name "os build refuses a bare user_guide (docs/namespace-prefix)"

Reference wording the dispatch pointed at, unchanged and consistent with the new sentence: content/docs/ui/doc-pages.mdx :68–:69 「The build lint still requires every doc name to be namespace-prefixed, as a same-package authoring-hygiene rule」 and :77–:82 「It is no longer load-bearing for uniqueness … two installed packages may each ship a doc with the same bare name and coexist」. The build-check pin: packages/cli/src/utils/collect-docs.package-docs.test.ts :420–:424 (a bare playbook → one docs/namespace-prefix at severity 'error').

Restate vs drop — the card's "First act", decided on the four axes

Option A (taken): restate — the enforceable fact plus one corrected clause naming where the refusal happens and what the prefix is not for, with the ADR section. Option B: drop to the bare enforceable fact ("must start with the package namespace; enforced by os build") and a bare (ADR-0048).

  • 实际业务需求 — the reader is an AI author of package docs in a customer project (skills/** ships via npx skills add / npm create objectstack). Both options let it comply. What the old sentence did in practice was get copied as a reason into the author's own docs; B leaves the "why" blank, and a blank "why" beside an ADR number is the shape an author fills with the retired claim. A gives the one fact that closes it. Neither option adds any capability.
  • 项目长远合理性 — spec/ADR > implementation > docs. ADR-0048 §3.4 itself classifies this lint as authoring hygiene (:258–:259), and the source header (collect-docs.ts :32–:54) says the same. A keeps the skill's sentence tied to the ADR clause it cites (§3.4), so a future change to that clause has one sentence to update; B cites a document that then says nothing about the sentence.
  • 防 AI 写代码/元数据犯错 — A names the door (os build) and the rule id (docs/namespace-prefix), so an author hitting the refusal can find it, and states the negative ("not uniqueness: two packages coexist on one bare name") that stops an AI from re-deriving the retired collision claim or designing around a constraint that does not exist (e.g. inventing cross-package-unique names). B is silent on exactly the claim this card is about.
  • 创业阶段不扩散需求 — both are net 0 lines; A costs +2 ratchet units (see below), B would shrink. No new capability, no new surface, immediate correction, no transition text.

Decision: A. The cost is stated honestly: this file's token headroom goes from 2 to 0, so the next edit to pages.md pays by deletion.

Also considered and not written, for the byte budget: the second true reason the source states — the prefix is what separates a same-package link from a cross-package one, because a doc link is a bare ./NAME.md with nowhere to carry a package coordinate (collect-docs.ts :45–:54 and the check at :737 if (namespace && !target.startsWith(${namespace}_)) continue;). It is measured and true; the sentence had room for one clause, and the §3.4 framing is the direct refutation of the retired claim. "authoring hygiene" was trimmed to "hygiene" for the same reason: the full spelling lands at 5504 units against a 5501 ceiling.

Published-skill ratchet readings (both readings, per os-dev.md)

  • Gate: node scripts/check-skills-token-ratchet.mjs (scripts/check-skills-token-ratchet.mjs, invoked directly in .github/workflows/lint.yml :5527–:5528; unit = ceil(utf8 bytes / 4)). Ceiling row :473 ['skills/objectstack-ui/rules/pages.md', 5501].
  • File, tokens: before 21996 bytes → 5499 units (headroom 2); after 22003 bytes → 5501 units (headroom 0). Gate line: ✓ check-skills-token-ratchet: skills/objectstack-ui/rules/pages.md is 5501 tokens (ceiling 5501; headroom 0). Paid within the replaced span (148 → 155 bytes); ceiling row untouched.
  • File, lines: before 448 → after 448 (net 0; the claim's budget was net ≤ +2).
  • Package, tokens: bundle total after 140368 (gate output); before 140366 — the unit is per-file additive and only this file changed (+2).
  • Package, lines (sum over all skills/**/SKILL.md, 10 files): before 6145 → after 6145. Sum over skills/objectstack-ui/**: 2155 → 2155.
  • pnpm check:pm-skill-ratchet is the .claude/** LINE ratchet and deliberately excludes the published skills/ root (its header says so); it is not the gate this file answers to.

Gates — derived union, every exit captured before any pipe, reconciled with --ran

Derived by node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths; change set from merge base 23f1de0, 1 path, +3/−3, under the 5000 human-merge threshold). Reconcile: Run reconciliation — 23 derived, 23 run, 0 NOT-MEASURED, 0 UNRUN. (exit 0).

command exit
node scripts/check-ci-filter-parity.mjs 0
node scripts/check-closing-keyword-parity.mjs 0
node scripts/check-closing-keyword-parity.mjs --self-test 0
node scripts/check-comment-mask-corpus.mjs 0
node scripts/check-doc-route-spelling.mjs --advisory 0
node scripts/check-doc-route-spelling.mjs --self-test 0
node scripts/check-skills-token-ratchet.mjs 0
node scripts/check-skills-token-ratchet.mjs --self-test 0
pnpm --filter @objectstack/lint run check:doc-formula-expressions first run 3 (PREREQUISITE NOT MET — dist/ of @objectstack/formula / @objectstack/lint absent in a fresh worktree; NOT MEASURED); after pnpm exec turbo run build --filter=@objectstack/formula --filter=@objectstack/lint --concurrency=2 under os-verify-lock.sh (VERDICT command-exit 0, held 390s): rerun 0
pnpm check:agent-test-spelling 0
pnpm check:corpus-claim-drift 0
pnpm check:cross-package-test-inputs 0
pnpm check:doc-authoring 0
pnpm check:driver-memory-census 0
pnpm check:gitlink-declared 0
pnpm check:nul-bytes 0
pnpm check:pm-governed-merges 0
pnpm check:refd-timer-probe 0
pnpm check:role-word 0
pnpm check:skill-compatibility 0
pnpm check:skill-frame-sync 0
pnpm check:skill-identifier-liveness 0
pnpm check:watch-hint-literal 0

Outside the derived union, run as the dispatch ordered: pnpm check:pm-dispatch-gates launched detached with its exit captured to a file; its verdict is reported in the os-dev-report comment on #19358 (it was still in its self-test when this body was written). No package build or test is owed: the diff touches no package (① empty), and packages/cli / packages/objectql are cited, not edited. The ## Contract review for this Tier H head is the seat's; node scripts/pm/check-governed-merges.mjs --pr on this PR is read after creation and goes into the report comment.

PM mechanism assumptions, verified

  1. Open PRs touching skills/objectstack-ui/**: 0 of 21 open PRs (read via REST /pulls?state=open + /pulls/{n}/files). Two open PRs touch skills/ at all, neither in this surface: fix(skills): enumerate every authorable top-level stack key in the platform skill, and gate it #19378 (skills/objectstack-platform/SKILL.md) and fix(spec,objectql): declare the inert-JSON artifact and registry-record package body stages, and stop the record under-reporting functions #19373 (skills/objectstack-platform/references/_index.md) — the claim named only the first; the second is a refinement of the reading, not a conflict. Holds.
  2. check-governed-merges.mjs --pr → read after creation; expected GOVERNED / Tier H. Reported in the report comment.
  3. The published-skill token ratchet (scripts/check-skills-token-ratchet.mjs) and check:skill-identifier-liveness are both in the derived union and both green on this diff. Holds, with the ratchet's name pinned — it has no pnpm check:* alias and is not check:pm-skill-ratchet.

维护者速读(草稿)

  • 改了什么:对外发布的 objectstack-ui skill 里「页面文档」编写规则第 2 条,只改「为什么要加命名空间前缀」那一句;规则本身(文件名必须以包命名空间开头)与 ADR-0048 引用都保留。
  • 为什么改:原句说「裸名字会跨包冲突、安装时失败,依据 ADR-0048」——而 ADR-0048 §3.4 恰恰宣布跨包冲突这一说法已退役(两个包可以同时用同一个裸名字,按包 id 各自解析),真正的拒绝发生在 os build(docs/namespace-prefix),不在安装。这份 skill 是客户项目里 AI 写文档时读的权威,错误的理由会被原样抄进客户文档。
  • 风险与代价(含回滚):纯文案,零代码、零发布产物、零 changeset;净 0 行;该文件的 token 上限余量从 2 变 0(下一次改这个文件须删字付账)。回滚 = revert 这一个 commit。
  • 席位意见:(留空,席位定稿)
  • 你要做的:Tier H,本 PR 保持 draft;席位完成 ## Contract review 与 ACCEPT 后,由你点合并。

Acceptance notes


Generated by Claude Code

…retired ADR-0048 claim

Authoring rule 2 of skills/objectstack-ui/rules/pages.md told an AI author
that doc names "share one flat, instance-global space with the URL, so a
bare `user_guide` would collide across packages and fail at install
(ADR-0048)". Each clause is refuted by the source it cites:

- routing keys on the package id and packaged items are stored under the
  composite `<packageId>:<name>` key (ADR-0048 §3.1/§3.3;
  packages/objectql/src/registry.ts storageKey line);
- the cross-package throw is retired — two distinct packages coexist on
  the same bare name by construction (ADR-0048 §3.4);
- a bare doc name is refused at BUILD by `docs/namespace-prefix`
  (packages/cli/src/utils/collect-docs.ts, severity error; `os build`
  exits 1 on doc errors), not at install — the install gate refuses on
  `manifest.namespace` ownership and `NamespaceConflictError` is
  constructed with a namespace, not a doc name.

The rule (the stem must start with the package namespace) and the ADR
citation stay; the REASON now names where the refusal happens and what
the prefix is for. Net 0 lines; published-skills token ratchet 5499 -> 5501
of 5501 (paid within the same span).

Claude-Session: https://claude.ai/code/session_017ETYWqMQD4qMtZzAGovWNi
Co-authored-by: Claude <noreply@anthropic.com>
@os-steve os-steve added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 20, 2026 — with Claude
@github-actions github-actions Bot added size/xs documentation Improvements or additions to documentation labels Sep 20, 2026

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 127576f695017a2eceacaa026ec6c5ff5fac90d6

① Derived judgments

  • Published accept set / public surface: none moves — one customer-published skill page (skills/objectstack-ui/rules/pages.md, +3 / −3, net 0 against the ≤ +2 budget), authoring rule 2's REASON sentence only; the rule (namespace-prefixed stem) and the ADR-0048 citation stay; no package, no schema, no gate. check-governed-merges --pr 19445: GOVERNED — skills/** ×1, Tier H, 6 changed lines under the human-merge line — the maintainer's click lands it. Judged correct.
  • The sentence, read against the source on this head: before, 「Names share one flat, instance-global space with the URL, so a bare user_guide would collide across packages and fail at install (ADR-0048)」 — three clauses, each false against the ADR it cites. After, 「os build refuses a bare user_guide (docs/namespace-prefix) — hygiene, not uniqueness: two packages coexist on one bare name (ADR-0048 §3.4)」. Seat-measured on 127576f: the storage key is composite (packages/objectql/src/registry.ts :3452 storageKey = packageId ? withDisc(\${packageId}:${baseName}`) : bareKey); the cross-package throw is retired (ADR-0048 :251, :325); the refusal is at BUILD (packages/cli/src/utils/collect-docs.ts:657 emitsdocs/namespace-prefix), while the install gate's NamespaceConflictError(:1444) is thrown withmanifest.namespace` (:4168), never a doc name. The new sentence states exactly the three measured facts and nothing beyond them; restate-vs-drop decided on the four axes in the PR body (restate — a bare fact beside an ADR number is the shape an author refills with the retired claim). Judged correct.
  • Evidence, seat-run on this head in a detached worktree: check-skills-token-ratchet.mjs exit 0 — pages.md 5501 / 5501 (headroom 0; the ceiling row untouched, the deviation that trimmed 「authoring hygiene」 to 「hygiene」 is the honest consequence and is stated); merge-tree vs origin/main 57ceb9d: 0 conflicts; CI on 127576f: 34 check runs, 2 still running, 0 red. The dev's derived union 23 / 23 exit 0 with --ran reconciled (a DERIVED zero; one NOT MEASURED first run re-run green after the prerequisite build under the shared lock), check:pm-dispatch-gates 1883 cases exit 0 captured.

② Semver level

None — a published skill's prose, no package version; skip-changeset on the PR is the correct declaration. Judged correct.

③ Boundary flags

open_questions empty. All three mechanism assumptions confirmed by measurement (0 of 21 open PRs on this surface; GOVERNED exit 3 Tier H; the token ratchet is scripts/check-skills-token-ratchet.mjs invoked directly by lint.yml, not a pnpm check:* alias — the seat's assumption 3 named the right gate by the wrong route). Deviations read and accepted: the trimmed spelling at a zero-headroom ceiling; the source's second reason (a same-package vs cross-package link) left out of the sentence within the claim's surface; the slow gate and the --pr / --pair readings reported on the card rather than in the body written once. Three noted, not filed observations carry no carrier and stay observations (the pre-§3.4 lead-in comment at registry.ts :3458; the doc-pages.mdx :76 lint-name imprecision; the PR count 21 vs the claim's 20).

Implemented-by: claude/issue-19358-pages-rule-2-retired-collision-claim
Reviewed-by: session_017ETYWqMQD4qMtZzAGovWNi

VERDICT: PASS


Generated by Claude Code

@hotlong
hotlong marked this pull request as ready for review September 21, 2026 04:53
@hotlong
hotlong added this pull request to the merge queue Sep 21, 2026
Merged via the queue into main with commit 0f9245c Sep 21, 2026
37 checks passed
@hotlong
hotlong deleted the claude/issue-19358-pages-rule-2-retired-collision-claim branch September 21, 2026 05:23
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/xs 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.

[finding] a published skill teaches the ADR-0048 claim ADR-0048 retired — and cites ADR-0048 as its authority

2 participants