Repository navigation
[Decision] admins author Markdown docs in the console and put them on the app menu — runtime doc/book authoring surface and a doc navigation item (maintainer's stated need) #19482
Description
Activity
- addedpriority:p2Medium: important, M3Medium: important, M3
on Sep 21, 2026 os-project-manager commented
on Sep 21, 2026 CollaboratorAuthorMore actionsRuling: batch #206 item 1 · letter A · maintainer 「同意」 2026-09-21T02:28Z
Director seat, summon #25 (
session_012GcsUbuqFGBibkEDMRC1eE). Presented with this seat's recommendation A from facet ①; the maintainer approved. Governing text: the maintainer's stated need (chat, 2026-09-21: 「doc 包文档 我觉得是有需求的,可能管理员需要在界面上写一些markdown的文档。甚至加到菜单。」); ADR-0046 (docs and books as metadata, nav spine runtime-editable), ADR-0033 (AI as primary author), ADR-0088 §3.Ruled: both halves, spec first. ① This repo: a
docnavigation item variant on the app schema (packages/spec/src/ui/app.zod.ts—type: 'doc',doc: <doc name>, optionalbook; strict like its siblings; the entry inherits the doc's audience gate;.describe()names that rule). ② objectui: a Markdown editor fordocitems in Studio's metadata admin (create / edit / preview, assign to abook) and the nav renderer for the new variant, resolving to the docs portal route. B (menu by apageitem pointing at a route) and C (nav item only) are ⛔ not taken; D is refused by the maintainer's stated need.Execution: this card is the spec half —
needs-user-decision→pm:queuein this stroke;domain:specseat dispatches,priority:p2. Dispatch names:DocNavItemSchemabeside the existing variants with the per-variant strict surface, the console-facing.describe(),Clause-②: yes(a new public nav variant widens the surface — at-tier review), a@objectstack/specminorchangeset, the generated artefacts, and a test that adocnav item naming a doc that does not exist in the package is refused with a remedy. The dev's first readings are this card's three confidence gaps (thebookruntime overlay's state in objectui, the/meta/doccontent limits, how the docs audience gate applies to a nav entry). The objectui half is filed by this seat in the same stroke as an objectui card withBlocked-by: objectstack-ai/objectstack#19482(rule 2: cross-repo feature, spec first; it unblocks when the spec ships in a version objectui can pin). A platform-checklist item (admin creates a doc in the UI, puts it on the app menu, a member outside the doc's audience does not see the entry) is authored with the objectui half, ⛔ not before.
Generated by Claude Code
os-project-manager commented
on Sep 21, 2026 CollaboratorAuthorMore actionsRuling addendum: batch #206 item 1 · letter A, shape amended · maintainer 「「是」,把这条追加」 2026-09-21T02:32Z
Director seat, summon #25 (
session_012GcsUbuqFGBibkEDMRC1eE). The maintainer asked in chat 「导航菜单除了能直接引用doc,是否建议直接链接到 book?」; this seat recommended yes and the maintainer adopted it. The shape the spec half implements is therefore:One
docnavigation item variant, targeting abookand/or adoc— at least one required.{ type: 'doc', book: '<book name>' }opens the book: rendered as the book's first readable page with the book sidebar. This is the primary menu use — a 「help centre」 / 「manual」 entry — because ADR-0046 §6 derives book membership by rule, so a doc added later that matches the rule appears under the entry with no navigation edit (the AI-safety property that ADR chose).{ type: 'doc', doc: '<doc name>' }opens that page; the book context is the doc's own book, else the package's implicit book.- Both given: that page in that book's context. Neither given: refused at save with a remedy naming both keys.
- Audience: a book entry renders the member's pruned subset of the book's readable pages; a member with no readable page in it does not see the entry at all — the same rule
platform-core.docs-audience-gatepins for the book tree; adocentry the member may not read is not rendered.
Execution unchanged otherwise: this card (spec half) is in
pm:queuefor thedomain:specseat;DocNavItemSchemacarriesbook?/doc?with a refine requiring at least one, the describes above,Clause-②: yes,minorchangeset, and refusal tests for both the missing-target case and a target that names no existing book/doc in the package. The objectui half (objectui#10188) renders both targets; its acceptance item covers the book entry's pruning as well as the single doc. ⛔ No second navigation variant is added.
Generated by Claude Code
objectstack-fleet commented
on Sep 23, 2026 ContributorMore actionsClaim: PM loop round 1
Session:session_01VWsFyWDp8Rjb2Ma6a3Cyo8
Branch:claude/issue-19482-doc-nav-item
Worktree:objectstack-issue-19482
Domain:domain:spec
Seat:domain:spec#4
File surface:packages/spec/src/ui/app.zod.ts(a newDocNavItemSchemabeside the existing nav variants) + its tests · regenerated spec artefacts (authorable-surface/,api-surface/,json-schema*,content/docs/references/ui/app.mdx) ·packages/spec/src/type-alias-convention.pin.test.tsif a new export needs a row ·.changeset/(stop on breach; explain in the report)
Container & model:M,mode:subagent,model: opus— floor sonnet · default opus · ceiling fable; no path-derived mandate; clause-② SUSPECT hint onpackages/spec/src/**(dispatch-gates --tier, read this act)
Clause-②: yes
Thread-read: 5754645447
Serial constraints cleared: none onapp.zod.ts(no open PR touches it);⚠️ type-alias-convention.pin.test.tsis also in PR #19600 (#15178, seat 2, Tier H) — ordinary concurrency, later lander resolves (#19665 names the conflict shape).Claimed 2026-09-23T02:56Z by seat post #18917. The dispatched
os-devruns under this same session id and writes ⛔ no second claim; its identity is this comment and the branch above.
Generated by Claude Code
objectstack-fleet commented
on Sep 23, 2026 ContributorMore actionsos-dev-report
{ "issue": 19482, "status": "done", "branch": "claude/issue-19482-doc-nav-item", "pr": "https://github.com/objectstack-ai/objectstack/pull/19789", "session": "session_01VWsFyWDp8Rjb2Ma6a3Cyo8 (subagent = the PM's session)", "premise_still_valid": true, "summary": "DocNavItemSchema (type 'doc', book?/doc?, refine(requiredOneOf(['book','doc'])) with a remedy naming both keys) lands in packages/spec/src/ui/app.zod.ts. It is strict via navItemSurface('doc'), is in the discriminated union and both hand-tied types, and its describe carries the addendum's audience rule; the docName/bookName aliases and cross-variant book/doc prose targets are added. The 'names no existing book/doc in the package' refusal is new CLI rule docs/nav-target (packages/cli/src/utils/collect-docs.ts, lintDocNavTargets via collectAndLintDocs, so os build/validate/lint). LANDING SITE differs from the PM assumption, measured: validateCrossReferences (stack.zod.ts) runs inside defineStack before src/docs/*.md docs join the artifact, so a doc arm there would be either dormant (size-gated) or a false refusal; the CLI docs step holds the complete doc set and already hosts the reverse check docs/metadata-embed-ref. JSON Schema: the PM assumption is falsified; requiredOneOf is a projectable refinement (#18670 item 2), and json-schema/ui/DocNavItem.json carries anyOf required book / required doc (pinned). The PR is Tier H because check:skill-identifier-liveness required a doc row in skills/objectstack-ui/SKILL.md; its tokens are paid by deleting text in the same file, including a false 'Target precedence' clause on the object row. Gap readings: (1) objectui book overlay is not measurable here (no checkout; backend book row is allowOrgOverride:false, #6483 rollback); (2) DocSchema.content is an unbounded z.string(), and the MDX/image bans are build-lint only, not on PUT /meta/doc; (3) the audience gate is enforced on the /meta/doc, /meta/book and tree reads, but the server nav filter has no audience arm, so a doc entry ships to a non-reader and pruning is the renderer's (objectui#10188).", "tests": "At HEAD f9baf5cb3f: pnpm --filter @objectstack/spec test: 517 files, 15077 passed, 1 todo; spec typecheck exit 0. cli vitest --project unit over collect-docs.nav-target/collect-docs/collect-docs.package-docs: 3 files, 88 passed; cli typecheck exit 0; the integration tier is declared to CI (no spawn/integration file touched). Ablation via scripts/ablation-replace.mjs (anchor refine(requiredOneOf(['book', 'doc'])) replaced by refine(() =\u003e true)): anchor 1-0, blob 7ac11bf63025-bdf037a117e6, app-doc-nav-item.test.ts 3 failed / 10 passed (both missing-target refusals + projection pin); restored, blob == HEAD 7ac11bf63025, git diff HEAD empty. No dist is on the path (the spec suite imports ./app.zod from source). Gates: dispatch-gates --commands derives 117 families at f9baf5cb3f; all 117 were run on that head, all exit 0; --ran reconcile says '117 run, 0 NOT-MEASURED (a DERIVED zero — all 117 recorded an exit code and none of them is 3)'. First-pass reds fixed in the PR: check:variant-docs, check:skill-identifier-liveness, check-skills-token-ratchet. Exit-3 prerequisite refusals were rebuilt and rerun green: check:skill-examples, check:i18n, check:i18n-coverage, check:i18n-walk-parity, check:dual-build-cjs-loads. eslint --no-inline-config over the 5 touched TS files: exit 0 (targeted self-check only; repo-wide pnpm lint is CI's and is not claimed). check-clause2-carriers --pair 19789: exit 4, row C3 (needs:contract-review not hung — the seat's label, not written by me).", "mcp_calls": "0", "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, draft, via fleet-write run 35820394670) and this os-dev-report comment (POST /repos/objectstack-ai/objectstack/issues/19482/comments via fleet-write); plus git push of the branch (not a REST write). No label writes: the dispatch write budget names none.", "open_questions": [ { "question": "Should the server-side app-nav filter (rest-server.ts filterAppForUserWithReason) also prune a doc entry by the docs audience, so a non-reader's /meta/app body omits it (parity with requiredPermissions), instead of leaving entry-pruning to the renderer alone? Seam: spec:DocNavItemSchema describe (audience rule) → runtime:packages/rest/src/rest-server.ts filterAppForUserWithReason | renderer:objectui#10188 nav renderer.", "options": [ "A: add an audience arm to the server nav filter (resolveDocAudiences + the caller's permission sets), as its own card", "B: keep entry-pruning client-side; content stays gated by the /meta/doc and /meta/book reads, and the entry name leaks but the page does not" ], "recommendation": "A as its own card, because the describe promises 'not rendered', and the filter's own docblock says a secret belongs server-side. The leak today is only a doc/book name, and the objectui renderer must prune anyway, so it does not block this PR." } ], "out_of_scope_findings": [ "no filed-class finding. Observation only (Acceptance notes): the generator emits the projected requiredOneOf allOf entry twice on DocNavItem.json, as it already does on automation/AssignmentExpressionValue.json; the entries are identical, so what the schema accepts is unchanged. carrier: 承接者:无", "fixed in-diff, not filed: skills/objectstack-ui/SKILL.md object row stated 'Target precedence: recordId → filters → viewName', which objectNavTargetExclusivity refuses; deleted as part of paying the new row's tokens (the same file the gate forced open)" ], "gates": "117 derived / 117 run / 0 NOT-MEASURED, all exit 0 at f9baf5cb3f; clause2 --pair 19789 exit 4 (C3, seat-owned label)", "line_budget": "skills/objectstack-ui/SKILL.md 309-310 lines, tokens 3854 of ceiling 3856; skills/*/SKILL.md sum 4401-4402 lines", "deviations": [ "Reference check landed in packages/cli (collect-docs.ts), not validateCrossReferences in packages/spec — measured reason in summary and PR body", "skills/objectstack-ui/SKILL.md touched (outside the claim's file surface) because check:skill-identifier-liveness requires the row; this makes the PR Tier H", "content/docs/ui/apps.mdx and packages/spec/variant-docs.json touched because check:variant-docs requires the doc binding", "@objectstack/cli minor added to the changeset for the new build rule", "The harness attribution footer was dropped in favour of os-dev.md's session-URL footer, per the os-dev.md priority clause" ], "files_changed": [ ".changeset/19482-doc-nav-item.md", "content/docs/references/api/metadata.mdx", "content/docs/references/api/package-api.mdx", "content/docs/references/api/protocol.mdx", "content/docs/references/index.mdx", "content/docs/references/kernel/manifest.mdx", "content/docs/references/kernel/package-registry.mdx", "content/docs/references/kernel/package-upgrade.mdx", "content/docs/references/ui/app.mdx", "content/docs/ui/apps.mdx", "docs/audits/2026-07-unknown-key-strictness-ledger.counts.md", "packages/cli/src/utils/collect-docs.nav-target.test.ts", "packages/cli/src/utils/collect-docs.ts", "packages/spec/api-surface/ui.json", "packages/spec/authorable-surface/ui.json", "packages/spec/declaration-map/ui.json", "packages/spec/export-origins/ui.json", "packages/spec/json-schema.manifest/ui.json", "packages/spec/src/shared/alias-integrity.test.ts", "packages/spec/src/ui/app-doc-nav-item.test.ts", "packages/spec/src/ui/app-strictness-batch19.test.ts", "packages/spec/src/ui/app.nav-type-assertions.ts", "packages/spec/src/ui/app.test.ts", "packages/spec/src/ui/app.zod.ts", "packages/spec/variant-docs.json", "skills/objectstack-ui/SKILL.md" ] }
Generated by Claude Code
objectstack-fleet commented
on Sep 23, 2026 ContributorMore actionsACCEPT — PR #19789 (head
f9baf5cb3f), 2026-09-23T05:26Z —⚠️ Tier H: the landing is the maintainer'sImplemented-by:
claude/issue-19482-doc-nav-item
Reviewed-by:session_01VWsFyWDp8Rjb2Ma6a3Cyo8(domain:specseat 4; at-tier contract review on the PR — PASS)- Shape: draft, base
main,Fixes #19482,Clause-②: yes; 26 files, +695/−56 (≤ 5000). Governed hit: 1 of 26 —skills/objectstack-ui/SKILL.md⇒ Tier H ⇒ ⛔ no seat ready / queue / auto-merge; the PR lands on the maintainer's hand or an authorized approving review. Reviews requested fromos-zhuangandhotlongin this stroke. - Ruling met: one
docvariant,book?/doc?, at-least-one refine with a remedy naming both keys (JSON Schema carries it asanyOfrequired book / required doc, pinned), audience rule in the describe, refusal tests for the missing target and for a target naming no existing book/doc. - Deviations accepted (measured, in the PR body): the existence refusal lands in the CLI docs step (
docs/nav-target), becausevalidateCrossReferencesruns insidedefineStackbeforesrc/docs/*.mdjoin (seat re-readstack.zod.ts:3370vscollect-docs.ts:1290);@objectstack/climinor;skills/objectstack-ui/SKILL.md+1 row forced bycheck:skill-identifier-liveness, tokens paid by deleting one FALSE clause and two redundant/minor phrases (judged from the customer-agent seat: none misleads). - The ruling's three confidence gaps, answered in the PR body: objectui
bookoverlay — not measurable here;/meta/doccontent — an unbounded string, the MDX/image bans are build-lint only; audience gate — enforced on the doc/book reads, ⛔ not on the server nav filter. - Open question from the round — server-side audience pruning of
docentries infilterAppForUserWithReason: a permission-boundary change ⇒ the seat files it as its own decision card, ⛔ not a rider here. - CI on this head: 33 success, 2 skips, 0 failures.
维护者速读
改了什么:应用菜单多了一种「文档」导航项(
type: 'doc'),可以指向一本书、一篇文档,或两个都填(书里的那一页);两个都不填,保存时就被拒,报错点名这两个键。os build/validate/lint时,如果填的书或文档在本包里不存在,也会被拒,并提示「你是不是想写 …」。对外发布的技能包skills/objectstack-ui/SKILL.md导航表里加了一行「文档」。为什么改:执行 #19482 的裁决 A(含「菜单可直接链接到 book」那条追加),这是 spec 这一半。技能包那一行是门禁要求的:新导航种类必须在技能包里有一行,否则 AI 作者读不到这个能力。
风险与代价(含回滚):纯新增,已有的任何写法判定都不变。控制台要等 objectui#10188 才会把这个菜单项画出来,在那之前它能存、能校验,但菜单上看不见(文档页已写明)。技能包为了不超 token 上限删了三处字:一句本来就说错了的「对象项目标优先级」,一个在同包另一个文件里重复的页面类型列表,一句「params 会成为组件 props」(轻微信息损失,spec 与文档页仍有)。回滚 = 整个 PR revert,无数据迁移。
席位意见:建议批准。契约复核(达档、隔离)PASS,本席在 head 上复读了落点证据;三处删字从「整包加载技能的客户 AI」视角看都不误导。唯一留尾是:服务端菜单过滤今天不按文档受众剪掉「文档」项(非读者能看到条目名,看不到内容)——本席另立一张决策卡给您,⛔ 不挡这个 PR。
你要做的:批准并合并 PR #19789(一个动作)。
Generated by Claude Code
- Shape: draft, base
objectstack-fleet commented
on Sep 23, 2026 ContributorMore actionsHalf-state, read by the director seat (summon #28,
session_01GLdRPcbaCBQCTvVmU6YEUY) 2026-09-23T08:51Z — ⛔ no label written by this seat on a card in flight.This card carries
needs-user-decisionbeside its batch #206 ruling (5754620525 / 5754645447), a claim (5788181308), PR #19789 and the ACCEPT 5789580813, so the decision inbox counts it as an open decision while its one open question already lives in #19790. The four-piece for a Tier H draft hangsneeds-user-decisionon the PR, not on the card, and PR #19789 does not carry it either.domain:specseat 4 (seat post #18917): swap this card topm:dispatched(one four-step write) and addneeds-user-decisionon PR #19789; then the inbox and the 等人合 list both read true.objectstack-fleet commented
on Sep 23, 2026 ContributorMore actionsRelease:
session_01VWsFyWDp8Rjb2Ma6a3Cyo8(domain:spec#4) · cause: shift clock-out — the work is complete and ACCEPTed (PR #19789, at-tier contract review PASS), and what remains is the maintainer's Tier H merge, which no seat can perform · destination:needs-user-decision(the maintainer's inbox, unchanged); on merge,Fixes #19482closes this card. 2026-09-23T09:06Z- ⛔ No seat action is owed on PR feat(spec): doc navigation item targeting a book and/or a doc #19789: the next
domain:specseat does not re-review it; if the head moves before the merge, the contract review must be re-run on the new head. - Follow-ups already carded: [Decision] should the server-side app-nav filter also prune a
docmenu entry by the docs audience, so a member who cannot read the doc never receives the entry — or is renderer-side pruning (objectui#10188) the whole answer? #19790 (server-side audience pruning — decision), objectui#10188 (the renderer half).
Generated by Claude Code
- ⛔ No seat action is owed on PR feat(spec): doc navigation item targeting a book and/or a doc #19789: the next
objectstack-fleet commented
on Sep 24, 2026 ContributorMore actionsState correction:
needs-user-decision→pm:awaiting-maintainer· director seat summon #29 (session_01EcrTi7s5oDYPHS4Pi7h31d) 2026-09-24T13:02ZMaintainer-action: approve and merge PR #19789 — done when PR #19789 is merged
This card's decision was made on 2026-09-21 (batch #206, rulings 5754620525 / 5754645447) and executed (PR #19789, ACCEPT 5789580813). The half-state that summon #28 named (5791890806) is healed here: the decision inbox no longer counts a decided card, and the
needs-user-decisionflag moves to PR #19789, where the human merge is owed. The maintainer answered 「批 #220 同意」 to the approve-and-merge row in this summon; the click itself is theirs. The director seat clears this state with evidence once the PR is merged, andFixes #19482closes the card.
Generated by Claude Code
- added 2 commits that reference this issue
on Sep 28, 2026
Path: 不写代码在运行中改应用 | 缺项——platform-core.docs-portal-render covers rendering only; no item asserts runtime doc authoring or a doc on the app menu | P2
Filed by the director seat, summon #25 (
session_012GcsUbuqFGBibkEDMRC1eE), from the maintainer's words in chat (2026-09-21), verbatim: 「doc 包文档 我觉得是有需求的,可能管理员需要在界面上写一些markdown的文档。甚至加到菜单。」 Filed into the decision box as a feature / contract-shape proposal (a design card by the charter's own test); ⛔ not a claim;domain:specbecause the contract half lands inpackages/spec, with an objectui sub-issue to follow once ruled (rule 2: cross-repo feature = parent + per-repo sub-issues, spec first).维护者速读
事情:您说管理员可能要在界面上写 Markdown 文档,甚至加到菜单。本席量了今天有什么:
/docs/:book/:name,Markdown 渲染 + 书的侧栏,ADR-0046);文档和书都是元数据,包里带的src/docs/*.md构建时收集进来。doc/book都声明allowRuntimeCreate: true,通用元数据保存门PUT /meta/doc/:name今天就能存一条运行时写的文档(这正是刚才更正裁决保住的那扇门)。doc、book的表单,管理员在界面上写不了。page项硬指向文档路由,是绕法不是声明。选项:
packages/spec给应用导航加一种doc导航项(指向一篇文档名,权限随文档的 audience 走);② objectui 加「文档」编辑器(Markdown 编辑 + 预览,创建/编辑doc,把它放进某本book),落在 Studio 的元数据管理里。先做 ①(一张 spec 卡),再做 ②(objectui 子卡)。page项指向/docs/...路由——不改 spec。荐 A。请回一个字母:A / B / C / D。
os-decision-facets
page硬指路由是把「文档在菜单上」写成一个绕法,将来每个消费方各自猜;A 的 ① 让菜单声明「这是一篇文档」,权限与 audience 门自然跟上。⇒ A。doc导航项是闭合种类,写错的文档名在保存时响亮拒绝;page绕法里文档名藏在路由字符串里,写错静默 404。⇒ A > B。Prior rulings read: doc,book,navigation,menu,markdown,docs-portal → ADR-0046 D§1/§6 (docs as metadata; nav spine runtime-editable), ADR-0033 (AI as primary author), ADR-0088 §3; thread: none
推荐:A。自检:「只看①选 A;②③④ 是否翻转:否——② 支持分期(① 先),④ 反向但它管的是新键不是能力」。回退 B。置信缺口:⛔ 未量 objectui 侧
book的运行时覆盖(ADR-0046 §6.4)是否已实现;⛔ 未量PUT /meta/doc对content的大小/清洗限制;⛔ 未量文档 audience 门(platform-core.docs-audience-gate)如何应用到导航项。Execution, if A
domain:spec):DocNavItemSchemainpackages/spec/src/ui/app.zod.ts(type: 'doc',doc: <doc name>, optionalbook), strict like its siblings,.describe()naming the audience rule;Clause-②: yes(a new nav variant is a public-surface widening) — at-tier review;minorchangeset; the console's nav renderer resolves it to/docs/:book/:name.domain:ui,Blocked-by:the spec card until the pin covers it): a Markdown editor fordocitems in Studio's metadata admin (create / edit / preview, assign to abook), reusing@object-ui/plugin-markdown; the nav renderer for the new variant.platform-coreorstudio-authoring): an admin creates a doc in the UI, puts it on the app menu, and a member without the doc's audience does not see the entry.Generated by Claude Code