Repository navigation
docs(skills): app-composition guide — a nav item's label is optional and inherited when absent (objectui#11198) - #11427
Conversation
… is required by NavigationItemSchema (objectui#11198) The "Contract Reminders" bullet of skills/objectui/guides/app-composition.md told an AI author that every nav item needs a label, "both required by NavigationItemSchema". @objectstack/spec 17.5.0 made a nav entry's label optional and objectui#9868 relaxed the validator to match: an absent label makes the entry show its target's current label at render time, so a label written on the guide's say-so forfeited that inheritance. The bullet now says the id is required, the label is optional and inherited when absent, and names the two cases that still want one. One bullet and an empty-frontmatter changeset; nothing else in the guide moves. Claude-Session: https://claude.ai/code/session_01FNKm1SmPpuJASnbjxWGtsJ Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Face: governed guide text ( ① Derived judgments
② Semver levelDocs-only in a governed surface; EMPTY-frontmatter changeset present; the phantom ③ Boundary flags
Implemented-by: VERDICT: PASS |
维护者速读(终稿)席位(skills 席 1, 改了什么。 发布给作者的技能指南 为什么改。 这句是 AI 写应用元数据时读的教材。自 风险与代价(含回滚)。 纯文档改动,不动任何发布包与运行时;风险只在措辞:dev 在 objectui 席位意见。 建议批准。无同文件在飞 PR,落地无需 update-branch 顺序。 你要做的(一个动作)。 在本 PR 上留一条 APPROVED review( |
Fixes #11198
Clause-②: no
What changes
One bullet in
skills/objectui/guides/app-composition.md("Contract Reminders"), plus an empty-frontmatter changeset. Nothing else in the guide moves: no code fence, nocontent/docs/**, no package source.Before (the sentence the card quotes):
After:
Why
@objectstack/spec17.5.0 made a nav entry'slabeloptional with a declared semantic (maintainer ruling A on objectstack-ai/objectstack#19049: absent ⇒ the entry inherits its target's current label at render time; present ⇒ rendered as authored), and PR objectui#11186 (objectui#9868) relaxed objectui's validator to match. An AI following the old sentence wrote a label it did not need and lost the inheritance the ruling exists for: a renamed target no longer renamed its nav entry. The wording follows the human-facing twin, the "Requirements" list ofcontent/docs/guide/designing-app-navigation.md, which PR objectui#11186 already corrected; the guide's own "Related" entry says the two are updated together.objectui#11201 (ruled B: a present label renders verbatim, with no text-match exception) is not touched: the bullet states only what an absent label does and when to write one, which holds under that ruling.
Premise check against
origin/main(e0a9c67)packages/types/src/zod/app.zod.ts,NavigationItemObject:idis declared optional only so a bare separator parses (objectstack#4115) and is re-imposed for every other type by thesuperRefine;labelis optional for every type (objectui#9868) and the refinement refuses only an empty string. So "id required" still holds and "label required" does not.packages/app-shell/src/hooks/useNavTargetLabel.tsandpackages/layout/src/NavigationRenderer.tsx(resolveNavItemLabel) document and implement absent ⇒ inherit, bottoming out at the target's machine name.pnpm-lock.yamlpins@objectstack/spec@17.5.0; a direct probe ofNavigationItemSchemafrom@objectstack/spec/uiin the installed worktree: an object item withoutlabelparses, one withoutidis refused (id: Invalid input: expected string, received undefined).git grepoverskills/**: this bullet was the only place a navlabelwas called required.Line readings (the governed
skills/**budget, +1 allowed)skills/objectui/guides/app-composition.md(whole file)skills/objectui/**/*.mdplus everyskills/*/SKILL.mdobjectui has no token ratchet; lines are the reading. No neighbouring line was re-wrapped; the bullet grew from 2 lines to 3.
Verification (at
afc7603f, the branch's only commit)Derived by hand from
.github/workflows/*.ymlonorigin/main(objectui has no dispatch-gates tool). Each exit code was captured to a file before any pipe.node scripts/check-skills-paths.mjsOK (89/90 stated path(s) resolve across 20 guide file(s); 1 baselined)--build-filter(12 packages) →pnpm exec turbo run build … --concurrency=2(29 tasks, 3m00s) →--self-test(60 cases) → the gateEvery marked skill example holds up against the built types.(underos-verify-lock.sh, held 242s, waited 0s)--self-test(29 cases) → the gateEvery must_contain token is taught by its own skill bundle.CITATION_GATE_BASE=origin/main node scripts/check-new-cross-file-line-citations.mjs0 new citation(s), enforcement report-onlynode scripts/check-control-bytes.mjs; plusgrep -naPfor control bytes over the two changed filesOK (scanned 9944 tracked text file(s)); the grep found nonenode scripts/check-changeset-presence.mjs0 of them published source of a package the release covers … 1 changeset(s) addednode scripts/check-changeset-claims.mjs --jsonNo pending changeset names a file this change touchescheck-changeset-no-major.mjs;check-changeset-overwrite.mjs--self-test(188 cases);--teston the two changed pathsskills/**: this PR stays draft until an authorized APPROVED review, then the claiming seat lands itlint.yml)Decide whether this change needs a full runstep**/*.mdand.changeset/**only, every path in that step's exclude list, so the job reports with its steps skipped; CI owns itci.ymland the always-on doc gates (docs-links,doc-fence-languages,doc-component-types,doc-example-ids,doc-snippet-types,docs-route-eager-closure,readme-exports)content/docs, package READMEs and source (check-doc-component-types.mjsstates in its header thatskills/**is deliberately not one of them) and this diff touches no fence; CI owns themAcceptance notes
skills/objectui/evals/app-composition.json, eval id 3: itsexpected_outputprose still lists "a snake_case id, and a label" for the rewritten item. Itsmust_containtokens areobjectName,type,id(nolabel), and the prompt's item already carrieslabel: Projects, so keeping that label is the "present ⇒ as authored" half of the ruling, not a contradiction. Observation only; not changed here (outside this card's one-bullet fence) and not filed. Carrier: none.@objectstack/spec17.5.0 itself accepts an empty-stringlabel; objectui'sNavigationItemObjectrefuses it as its one stated divergence. The bullet does not mention the empty string (the docs guide does) because of the +1 line budget.维护者速读(草稿)
改了什么。 只改 objectui 已发布技能
skills/objectui/guides/app-composition.md里的一条「契约提醒」:原来写「每个导航项都必须有label,NavigationItemSchema要求」,现在写「id必填;label可省略 —— 省略时导航项显示目标当前的名字;只有刻意要起一个导航专用名,或目标本身没有名字(页面、报表、外链、分组)时才写」。外加一个空 frontmatter 的 changeset(声明不发版)。为什么改。
@objectstack/spec17.5.0 已把导航项的label改成可选,并由维护者裁定 A 规定语义:不写就跟着目标当前名字走;写了就原样显示。objectui 的校验器也已随 PR objectui#11186 放开。技能里这句旧话让 AI 作者多写一个不需要的label,结果对象/视图改名后,导航上的名字不再跟着变 —— 正是裁定 A 要避免的事。改了之后,AI 生成的 app 导航默认跟随目标名字,少一处要手工维护的文字。风险与代价(含回滚)。 纯文字,不动代码、不动校验、不动面向人的文档(那边 PR objectui#11186 已经改对,本句措辞照它写)。风险只在措辞:若有人认为导航项仍应强制写
label,这句会导向相反做法 —— 但那与 spec 17.5.0 和裁定 A 相悖。回滚 = revert 这一个 commit。本地门禁全部通过;skills/**是受管面,本 PR 停在 draft,等授权审批后由席位落地。席位意见。(留空,席位定稿时填)
你要做的。 读上面「Before / After」两句;认可措辞就留一条 APPROVED review,席位负责后续 ready 与入队;不认可就在评论里写你要的说法,我们改句子。
Generated by Claude Code