Skip to content

docs(skills): navigation.md states the measured behaviour of colSpan and span: 'full', drops the deprecated claim - #18674

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-18496-navigation-span-colspan
Sep 18, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/issue-18496-navigation-span-colspan

Conversation

@os-justin

Copy link
Copy Markdown
Collaborator

Fixes #18496

Clause-②: no

One bullet in one published rule file. skills/objectstack-ui/rules/navigation.md (the 「Field width」 bullet, :136–:139 on origin/main 30be2ac0b) prescribed span: 'full' as "the whole row" and told authors not to use colSpan because "it only lines up at one width and is deprecated". #17328 measured both rendering claims false in Chromium at 390 / 720 / 1700, PR #18492 removed them from packages/spec and the generated reference page, and nothing in packages/spec deprecates colSpan. This was the last prescriptive carrier in the tree, and the one npx skills add objectstack-ai/objectstack/skills ships to customer projects. The bullet now says what the spec declares and the measurement found; it prescribes no preference between the two keys, because the spec does not (PR #18492: 「The preference between the two keys is removed, not reversed」).

The bullet, before and after

Before (origin/main 30be2ac0b, :136–:139):

- **Field width.** Use the relative **`span: 'full'`** to make a field take the
  whole row; otherwise **omit it** (`auto` sizes by widget type × current columns —
  textarea / rich-text / file take the row automatically). Do **not** use the
  absolute `colSpan` — it only lines up at one width and is deprecated.

After (7155de6ac, :136–:141):

- **Field width.** **Omit it** (`auto` sizes by widget type × current columns —
  textarea / rich-text / file take the row). Both keys are valid: `colSpan`
  (1–4) is clamped to the current column count, grid-aligned at every width;
  `span: 'full'` resolves to the form grid's full column count, but the shipped
  renderer emits it at the widest tier only (a 3-column form: one cell of two
  in a modal).

Two restatements in the same section are deleted to pay the token ratchet (below); no other line moves:

  • 「Overlay width」 :142–:143:144: the parenthetical 「(they can't be chosen without knowing the client viewport)」 is gone. It restated the section intro :127–:128 「because an author (especially an AI) cannot know the client's screen」. The 「width / drawerWidth are deprecated」 clause it hung on stays, and it is true: packages/spec/src/ui/view.zod.ts:3539–:3540 carries @deprecated on drawerWidth and the describe opens [DEPRECATED → size buckets].
  • 「Column count」 :146–:147:147: the closing 「; the columns adapt themselves」 is gone. It restated the bullet's own first sentence, 「Not authored. The form grid follows its real rendered width via container queries」.

What the spec declares — packages/spec/src/ui/view.zod.ts at 30be2ac0b

  • :2664 colSpan: z.number().int().min(1).max(4).optional(), describe: 「Absolute column span (1-4). The renderer clamps it to the form grid's current column count, so the cell starts at a real column boundary at every surface width and never overflows (colSpan: 4 in a 3-column grid renders as 3); a colSpan within the column count renders as authored, and colSpan: 1 emits no span class at all.」
  • :2676 span: z.enum(['auto', 'full']).default('auto'), describe: 「'auto' (default — omit it): the renderer sizes the field from its widget type × the current column count (wide widgets like textarea/richtext/json/file/subform take the whole row). 'full': resolves to the form grid's full column count. How far down the container-query tiers that span is emitted is the renderer's, not this key's: at the .objectui-sha pin 53ded82bf7 only the widest tier's class is emitted (@2xl:col-span-3 for a 3-column grid), so at intermediate widths the field took a single cell, not the row (one of two at the 720px modal width; measured in Chromium at viewport widths 390, 720 and 1700).」
  • :2665–:2675 the TSDoc above span: objectui#9253 (objectui bd09957380, 2026-09-12) is 「ahead of that pin」 and the block says 「re-read this block at the pin bump that absorbs it」.
  • Nothing deprecates colSpan, measured over packages/spec/src: .deprecated( → 0 files; retiredKey( calls naming colSpan → 0; UNKNOWN_KEY_GUIDANCE (7 files) and RETIRED_KEY_GUIDANCE (8 files) → 0 colSpan lines inside them; the ADR-0087 registries packages/spec/src/conversions/* and packages/spec/src/migrations/* → 0 colSpan lines (positive control: namespace / tableName / sourceView hit conversions/registry.ts ×3, apply.ts ×2, types.ts ×2, stored.ts ×1); colSpan lines co-occurring with deprecat|retire|legacy → 0. The changeset PR docs(spec,ui): colSpan and span state their measured behaviour — the two claims #17328 falsified are gone #18492 landed (.changeset/17670-colspan-span-measured-behaviour.md) states 「Nothing an author writes moves. Both keys are unchanged, both still parse」.
  • The generated reference page content/docs/references/ui/view.mdx:201–:202 and content/docs/ui/views.mdx:449–:450 say the same two sentences; content/docs/protocol/objectui/layout-dsl.mdx:254–:262 (「Custom Span Widths」) says 「widest tier only at objectui 53ded82bf7 … one clamped class per tier since objectui#9253」.

What the measurement found — #17328, Chromium at 390 / 720 / 1700

From the card's geometry table (hotcrm at 427c98535d, @objectstack/* 17.4.0, one 3-column section, helpful_count cell):

authored 390 (1 col) 720 (2 cols) 1700 (3 cols) emitted class
none 358 285 495
colSpan: 2 358 586 (2 of 2) 1006 (2 of 3) @md:col-span-2
span: 'full' 358 285 (1 of 2 — pixel-identical to none) 1517 @2xl:col-span-3
colSpan: 4 358 285 1517 @2xl:col-span-3 (identical to span: 'full')
colSpan: 1 358 285 495 none

Overflow 0px in every configuration at every width. So: colSpan is clamped and grid-aligned at every width (the old bullet's 「only lines up at one width」 is contradicted at all three), and span: 'full' at the pinned renderer is one cell of two at the modal width (the old bullet's 「the whole row」 is false there). The bullet's parenthetical 「a 3-column form: one cell of two in a modal」 is that row; it is qualified to a 3-column form because a 2-column form grid resolves 'full' to 2 and emits @md:col-span-2, which is the row at 720.

Is the pin state still the shipped state on 30be2ac0b? .objectui-sha = 53ded82bf7a494f54e344e19099dbf00854b8694, untouched since PR #18492 merged (git log 3a9ad22ecf..HEAD -- .objectui-sha is empty). In the objectui clone (git rev-parse --is-shallow-repository = false): git merge-base --is-ancestor bd09957380 53ded82bf7exit 1; control leg PIN~5 (83c77dc30, 2026-09-05) → exit 0; reverse is-ancestor 53ded82bf7 bd09957380 → exit 0; git tag --contains bd09957380 → 0 tags. The span-ladder fix is ahead of the pin and unreleased, so 「the shipped renderer emits it at the widest tier only」 is true today. It stops being true at the pin bump that absorbs bd09957380 — the same event the spec TSDoc :2675 tells its own reader to re-read at; see acceptance note 3.

Why no preference is prescribed

The dispatch left the direction to the measurement: 「If the measurement says neither spelling is to be discouraged, say so; if it says colSpan is the safer primitive, say that」. At the pin, colSpan is the one that does what it says at every width, and a rule could say so — but the spec (the protocol, per 「我们的项目以objectstack 协议为准,文档应该以实际实现为准」) declares both keys without preference after PR #18492's at-tier contract review, and the renderer half is already fixed ahead of the pin (objectui#9253), after which 'full' is the whole row at every multi-column tier and a colSpan-first rule would need reversing again. So the bullet states each key's declared behaviour and the measured caveat, and lets the author choose; it calls neither deprecated because the spec does not.

Token ratchet — scripts/check-skills-token-ratchet.mjs:472 ['skills/objectstack-ui/rules/navigation.md', 2273], unchanged

Convention ceil(utf8 bytes / 4). Before: 9092 bytes → 2273 tokens (ceiling 2273, headroom 0). After (7155de6ac): 9091 bytes → 2273 tokens (ceiling 2273; headroom 0) — the gate's own line: 「✓ check-skills-token-ratchet: skills/objectstack-ui/rules/navigation.md is 2273 tokens (ceiling 2273; headroom 0).」 Arithmetic: bullet 319 → 411 bytes (+92); the two deletions −61 and −32 (−93); net −1 byte. Row not raised, not lowered. File 162 → 162 lines; widest line in the section 84 (file-wide 181, a code example, unchanged).

Sweep — git grep -z -l -F, excluding content/docs/releases/ and **/CHANGELOG.md, files

phrase before (30be2ac0b) after (7155de6ac)
only lines up at 2 — skills/objectstack-ui/rules/navigation.md, .changeset/17670-colspan-span-measured-behaviour.md 1 — the changeset only
at any column count 1 — the changeset 1 — the changeset
lint-discouraged 1 — examples/app-showcase/src/ui/views/task.view.ts (carrier 2, boundary) 1 — unchanged, not this PR's
is deprecated 40 files; in navigation.md 1 line 39 files; in navigation.md 0
files carrying both colSpan and is deprecated 3 — view.zod.ts, references/ui/view.mdx, navigation.md 2 — view.zod.ts, view.mdx (there 「is deprecated」 is on other keys; 0 same-line hits with colSpan)
lit control colSpan 35 35
dark control zzz-no-such-token 0 0

The changeset carries the two old phrases as quotations of the wording it removed — a historical record by construction, consumed into CHANGELOG.md at release (which the exclusion set already exempts); it is not a prescription and is not touched.

Gates (worktree at 7155de6ac)

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack — change set derived from git, 1 path vs merge base 30be2ac0b — derived 22 commands; every one run with redirect-then-$? capture; --ran reconcile: 「22 derived, 22 run, 0 NOT-MEASURED, 0 UNRUN」, exit 0.

node scripts/check-ci-filter-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-doc-route-spelling.mjs --advisory :: exit 0
node scripts/check-doc-route-spelling.mjs --self-test :: exit 0
node scripts/check-skills-token-ratchet.mjs :: exit 0
node scripts/check-skills-token-ratchet.mjs --self-test :: exit 0
pnpm check:agent-test-spelling :: exit 0
pnpm check:corpus-claim-drift :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:doc-authoring :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:pm-governed-merges :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:role-word :: exit 0
pnpm check:skill-compatibility :: exit 0
pnpm check:skill-frame-sync :: exit 0
pnpm check:skill-identifier-liveness :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0

Named verdicts: check:doc-authoring 「44 published skill files clean — no internal issue-id references」; check-skills-token-ratchet --self-test 「65 cases pass」; check:skill-identifier-liveness --self-test OK and the gate exit 0; check:skill-compatibility 「10 SKILL.md file(s) reconciled against 81 workspace packages」; check:nul-bytes exit 0. check:doc-formula-expressions was run after pnpm --filter '@objectstack/lint...' build under scripts/pm/os-verify-lock.sh (「VERDICT command-exit 0 · held the lock 186s · waited 0s」). Not owed locally: no ① dependency-closure build and no ② package test (the diff touches no package); the 51 artifact-roster, 11 wide-population and 2 workflow-valued families are CI's own.

Governed: node scripts/pm/check-governed-merges.mjs --test skills/objectstack-ui/rules/navigation.mdexit 3, 「GOVERNED — a human merge is the review record for this PR … skills/** ×1 — the published skills catalog」. Recorded as GOVERNED, not as a failure. Draft; no seat flips it ready, queues it or arms auto-merge; the maintainer's approval lands it (Prime Directive #14).

Control characters: grep -naP over the touched file → no match (exit 1).

Changeset — skip-changeset, by measurement

83 tracked package.json manifests read: 0 carry a files[] entry naming a skills path (positive control: 70 name dist); skills/*/package.json → 0; the catalog ships from the GitHub tree (skills/README.md:9 npx skills add objectstack-ai/objectstack/skills; packages/create-objectstack/src/skills-install.ts:62 SKILLS_CATALOG = 'objectstack-ai/objectstack/skills'), never inside an npm tarball; .github/workflows/pr-automation.yml:799 names skills/** among the releases-nothing paths.

Acceptance notes

Out of this PR's scope; nothing is filed by this PR.

  1. noted, not filed — 承接者: the card's own routing round. Carrier 2, examples/app-showcase/src/ui/views/task.view.ts:363–:366 (「'full' = whole row at any / derived column count — the primary primitive; absolute colSpan / is legacy and lint-discouraged」, wrapped across comment lines; the lint rule it names was withdrawn by [finding] absolute-colspan-discouraged asserts a misalignment that does not happen — measured in Chromium at all three surface widths, and its recommended alternative span: 'full' is the spelling that misrenders #17328). skills/objectstack-ui/rules/navigation.md still prescribes span over colSpan on the basis #17328 measured false, and calls colSpan deprecated when nothing in packages/spec deprecates it #18496 records it as a boundary, not an expansion; left exactly as found, and the sweep row above keeps it visible.
  2. noted, not filed — 承接者: the pin-bump PR that absorbs objectui bd09957380 (PR docs(spec,ui): colSpan and span state their measured behaviour — the two claims #17328 falsified are gone #18492's acceptance note 5 names the same event; dedupe words spanLadderFor, objectui#9253, span-full-tier-ladder). The new bullet's 「the shipped renderer emits it at the widest tier only」 is anchored to the current pin the way the spec describe is, but no gate watches skills/** for pin-state prose (packages/spec/scripts/check-objectui-pin-citations.ts scans packages/spec/src only), so that PR must re-read navigation.md:139–:141 alongside view.zod.ts:2665–:2676.
  3. noted, not filed — 承接者: whoever next edits that interface block (PR docs(spec,ui): colSpan and span state their measured behaviour — the two claims #17328 falsified are gone #18492 note 4 says the same). content/docs/protocol/objectui/layout-dsl.mdx:850 lists a FormField interface with colSpan and no span — incompleteness, not an error; the card's own refs exclude it.
  4. noted, not filed — 承接者: 无. .changeset/17670-colspan-span-measured-behaviour.md still carries 「only lines up at」 and 「at any column count」 as quotations of the removed spec wording; release consumes it into CHANGELOG.md, where the exclusion set already expects them.

维护者速读(草稿)

改了什么:skills/objectstack-ui/rules/navigation.md「Record Presentation」一节的「Field width」要点重写:不再规定「用 span: 'full' 占满整行、别用 colSpan,它只在一种宽度对齐且已弃用」,改为按 packages/spec 的声明陈述两个键——默认省略(auto);两个键都合法;colSpan(1–4)被渲染器夹到当前列数、在每个宽度都对齐网格;span: 'full' 解析为表单网格的满列数,但当前出货的渲染器只在最宽一档发出它(3 列表单在弹窗里只占两格中的一格)。为了守住 token 棘轮(该文件上限 2273、余量 0),同一节删掉两处重复表述:「Overlay width」里的括号原因句(节首已说过同一理由)和「Column count」末尾的「the columns adapt themselves」(该要点首句已说)。棘轮行不动,实测仍是 2273。

为什么改:#17328 在 Chromium 三个宽度实测:colSpan 被夹紧、每个宽度都对齐;而被推荐的 span: 'full' 在弹窗宽度只占一格、与不写一样。PR #18492 已把这两句从 spec 与生成的参考页移掉,并明确「两键之间的偏好是移除、不是反转」。这一条是树里最后一处仍在规定旧说法的载体,而且随 npx skills add 出货到客户项目;「deprecated」一句更是独立于实测就是假的——spec 里没有任何东西弃用 colSpan(.deprecated() 0、retiredKey 0、ADR-0087 转换表 0、UNKNOWN_KEY_GUIDANCE 0)。

风险与代价(含回滚):① 新要点的「当前出货的渲染器只在最宽一档发出」锚定在 .objectui-sha 53ded82bf7(objectui 修复 bd09957380 在 pin 之后、尚未发布,双腿实测);pin 升级吸收该修复时这句要跟着重读,spec 的 TSDoc 对自己也写了同一句提醒,但 skills/** 没有门禁盯 pin 状态的散文——已记在验收备注 2,承接者是 pin 升级 PR。② 不再给作者一个「首选拼法」,由作者按两句事实自选;这与 spec 现状一致。③ 同节另两处删除只删重复表述,不删事实。回滚 = revert 单个提交(单文件,无发布物,无 changeset)。

席位意见:

你要做的(一个动作):批准并合并本 PR(受管面 skills/**,需你点合并)。


Generated by Claude Code

…ure as, drops the deprecated claim

The Field width bullet in skills/objectstack-ui/rules/navigation.md
prescribed span: 'full' as the whole row and called colSpan deprecated
and misaligned at every width but one. Browser measurement at three
surface widths found the opposite: colSpan is clamped to the current
column count and grid-aligned at every width, while span: 'full' is
emitted by the pinned renderer at the widest tier only. Nothing in
packages/spec deprecates colSpan.

The bullet now states both keys as packages/spec declares them, with
the tier caveat the spec anchors to the objectui pin. Two restatements
in the same section are deleted to hold the token ceiling: the overlay
bullet's reason clause (already the section intro's) and the column
bullet's closing clause (already its first sentence).

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

Copy link
Copy Markdown
Collaborator Author

维护者速读(终稿)

skills 席 session_01Gqi43smmqjJ5sUrhfoPeKu,2026-09-17T14:12Z。对照本席自己读的 diff 校正 dev 草稿;席位意见已填。

改了什么 — 只改发布技能 skills/objectstack-ui/rules/navigation.md 一节(+8 / −8,162 行不变,token 棘轮 2273/2273 零余量守住)。「Field width」那条从「用相对的 span: 'full'……⛔ 别用绝对的 colSpan,它只在一种宽度下对齐且已弃用」改为:默认省略(auto);两个键都有效:colSpan(1–4)按当前列数钳制、每种宽度都对齐网格;span: 'full' 解析为表单网格的满列数,但当前出货的渲染器只在最宽档位输出(3 列表单在弹窗里占两格中的一格)。为了在零余量下塞进真话,同节删了两句重复(Overlay 宽度的括号解释、Column count 的收尾句),PR 正文逐句点名了各自重复的原句。

为什么改#17328 实测把这两条主张判为假,PR #18492 已从 packages/spec 和生成的参考页里移除;这一行是树上最后一处还在规定它们的地方,而且它是规定性的、随产品出货到客户项目、规定的正是测量判在更差一侧的拼法。「已弃用」独立于 #17328 也是假的:packages/spec 里没有任何东西弃用 colSpan(本席核对了 :2664 / :2676 的 describe)。

风险与代价(含回滚) — 受管发布面,只改文本;不动 spec、不动示例、不抬棘轮。新句里「渲染器只在最宽档位输出」锚在当前 .objectui-sha 钉(53ded82bf7,objectui#9253 的修复在钉之前),与 spec 自己的 describe 同样锚定 —— 抬钉的 PR 要回来重读这一条(dev 已记,本席也记)。回滚 = revert 一个提交。

席位意见 — 荐合。它把规则改成 spec 和测量说的话,不是把旧句反过来;偏好被移除而非反转,与 PR #18492 一致。

你要做的(一个动作) — Approve 本 PR(或直接人工合并);席位随后按裁定 C 落地。若你希望技能明确偏好某一个键,Request changes 并说哪个,本席另起。


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review September 18, 2026 01:12
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 18, 2026
Merged via the queue into main with commit 62b114f Sep 18, 2026
44 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-18496-navigation-span-colspan branch September 18, 2026 01:44
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

2 participants