docs(skills): guard both useAuth members in the auth-permissions example - #9374
Conversation
The `useAuth` fence under "useAuth hook" read `user.name` behind an `isAuthenticated`-only guard. `AuthProvider` hardcodes `isAuthenticated` to `true` in guest mode and in preview mode while `user` stays `null`, so the example threw a TypeError in exactly the two modes a reader without an auth backend is in. Guard both members the way the shipped `UserMenu` does, and add one sentence beside the fence saying why a signed-in-looking context can still carry no user. The fence stays unmarked: it is a fragment by construction (three undeclared placeholders), and marking it would red the gate for reasons that are not this defect. Claude-Session: https://claude.ai/code/session_01DAcomhvR9kKizeYgg89Vo8 Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewHead: ① derived judgments: the diff makes ONE falsifiable claim on a published skill — in guest mode and preview mode Implemented-by: claude/issue-9350-useauth-guard-both (mode:subagent) Verdict: PASS. Governed surface (published Generated by Claude Code |
维护者速读改了什么 —— 发布技能 为什么改 —— 照抄这个示例的读者在没有后端的 guest / preview 模式下会直接 风险与代价(含回滚) —— 纯文档面,不动任何包;回滚 = revert 单文件 3 行 + 删 changeset。 席位意见 —— 收。本席在 head 你要做的(一个动作) —— 受管面(发布 Generated by Claude Code |
维护者速读(补记:检查全部跑完)读数 —— head 那一红不是本 PR 的 —— 同名检查在 你要做的(一个动作) —— 你已 approve、翻 ready、开过又关了 auto-merge;若关它是因为那一红,现在可以重新挂 auto-merge(队列只看必过集)或直接合;本席不代你挂。 Generated by Claude Code |
Fixes #9350
What changed
skills/objectui/guides/auth-permissions.md, the fence under "useAuth hook", readuser.namebehind anisAuthenticated-only early return.AuthProviderin@object-ui/authcomputesisAuthenticatedasuser !== null && session !== nullonly when auth is enabled and not in preview mode; in guest mode (enabled: false) and in preview mode it hardcodestruewhileuserstaysnull, so the example threw aTypeErrorin exactly the two modes a reader without an auth backend is in. The shippedUserMenucomponent already guards both members.if (!isAuthenticated || !user) return LOGINBUTTON;where LOGINBUTTON stands for the login-button element the fence returns (JSX tag shapes are spelled in words in this body because the platform strips tag-shaped fragments). The returned element is unchanged.UserMenuas the shipped shape. The prose moved with the example, asAGENTS.mdrequires.Not done, by the grading (comment 5651956190): no
os:checkmarker on this fence. It is a fragment by construction (three undeclared placeholders: the spinner, the login button and the button), and marking it would redcheck:skill-examplesfor reasons that are not this defect. Whether to make it self-contained is a separate question, noted below and not filed.Acceptance, both directions
Measured on this branch at
67cccb0with the gate's own scoped build in place:pnpm exec turbo run build $(node scripts/check-skill-examples.mjs --build-filter) --concurrency=2, 29 of 29 tasks successful, run under the shared verify lock (VERDICT command-exit 0, held 141s, waited 0s).Before = the base (
69aa9c0) content of the guide on that same built tree; After =67cccb0.node scripts/check-skill-examples.mjs --measure,TS18047: 'user' is possibly 'null'rows for this file: 1 (auth-permissions.md:49:20) before, 0 after.TS18047rows across the whole corpus: 1 before, 0 after.[semantic]diagnostic rows across the whole corpus (positive control, not a silent zero): 270 before, 269 after.Semantic phasesummary line, both sides:97 of 121 ts fence(s) judged, 79 failed(the fence still fails on its three undeclared placeholders before and after, so the failed-fence count does not move while the diagnostic-row count drops by exactly one).isAuthenticated || !userin this file: 0 before, 1 after.useAuthin this file (lit control): 5 before, 5 after.signed-in-looking context): 0 before, 1 after.The before column is an ablation leg run after the commit:
git checkout 69aa9c0 -- skills/objectui/guides/auth-permissions.mdon the built tree (on-disk proof: 365 lines, old guard 1, new guard 0, prose 0), then--measure, thengit checkout HEAD -- FILE. Restoration is proven bygit hash-objectequal to theHEADblob (dd4e4633…),git diff HEAD --statempty andgit status --porcelainempty. The very first--measureattempt, before the build, exited 2 (PRECONDITION NOT MET) and is not a reading.Line budget (published
skills/**)skills/objectui/guides/auth-permissions.md: 365 → 367 lines (net +2, ceiling +2; 3 insertions, 1 deletion; no re-wrap).skills/**/SKILL.mdin objectui: 137 → 137 (one file, untouched).pnpm check:skill-eval-tokens, before and after identical: exit 0;Scanned 1 skill bundle(s) under skills: 11 eval file(s), 33 eval(s), 125 must_contain token(s), scored against 16 guide file(s).;Red under the chosen oracle: 0 (0 beyond the baseline).Gates run locally (exit captured before any pipe; verdict lines quoted)
Derived by hand for objectui (there is no
dispatch-gates.mjsin this tree): rootpackage.jsoncheck:*scripts whose source readsskills/, plus the.md-scanning and.changeset-scanning workflow steps.pnpm check:skill-examples— exit 0 —Semantic phase: 14 of 14 ts fence(s) judged, 0 failed./Every marked skill example holds up against the built types.pnpm check:skills-paths— exit 0 —OK (88/89 stated path(s) resolve across 20 guide file(s); 1 baselined).pnpm check:skill-eval-tokens— exit 0 —Every must_contain token is taught by its own skill bundle.pnpm check:doc-fences— exit 0 —every TypeScript block in 227 document(s) is fenced ts/tsx/typescript(rest of the line elided).pnpm check:control-bytes— exit 0 —OK (scanned 7540 tracked text file(s); skipped 85 binary).pnpm check:shell-escape-residue— exit 0 —OK (5/5 root(s) resolved … skills: 16 file(s), 210 fence(s) …).pnpm check:doc-types— exit 0 —Every documented component type is registered.pnpm check:upstream-port-parity— exit 0 —11 ported file(s) match objectstack-ai/objectstack modulo their declared divergences.node scripts/check-changeset-presence.mjs— exit 0 —No source or published contract of a released package changed in this range, so no changeset is owed.(the empty-frontmatter changeset is declared anyway, per the docs-only convention).check-changeset-claims,check-changeset-no-major,check-changeset-fixed,check-changeset-overwrite— exit 0 each.node scripts/check-new-cross-file-line-citations.mjs— exit 0 —0 new citation(s), enforcement report-only.node scripts/check-governed-queue-guard.mjs --test skills/objectui/guides/auth-permissions.md— exit 3 —GOVERNED — 1 of 1 path(s) are on a governed surface: skills/** x1(the path face, not a failure).pnpm check:doc-snippetsexited 2 (PRECONDITION NOT MET: a different 34-package closure is unbuilt), and its own header states thatskills/objectui/**is not claimed by that gate, so it is not a derived gate for this diff.pnpm lintis the repo-wide run CI owns and this diff has no lintable source.Serial check
No open objectui PR touches
skills/**: re-read at 07:58Z today, the 8 PRs updated after the PM's 06:58Z reading (#9367, #9371, #9369, #9349, #9364, #9368, #9360, #9366) list noskills/file.Acceptance notes (noted, not filed)
useAuthfence self-contained (declare the spinner, login-button and button placeholders) and then mark itos:checkis a separate question by the grading; today it is a fragment by construction, like the other unmarked fences in this file that--measurelists. 承接者:无 — no queued PR or person is on this file.useAuthuse in this file (the markedPermissionProvidersetup fence) readsuser?.positionsanduser ?? undefined; it does not have this defect and was not touched.dataSourcemember indata-integration.md; its PR fix(skills): guard the DataSource read in the marked data-integration example #9352 landed 2026-09-13T06:29Z).维护者速读(草稿)
改了什么:发布给使用者的 skills 指南
skills/objectui/guides/auth-permissions.md里,useAuth示例的早退守卫从只看isAuthenticated改为同时看isAuthenticated和user(与仓内已发布的UserMenu组件一致),并在示例上方加一句说明为什么看起来已登录的上下文仍可能没有 user。净增 2 行;另加一个空 frontmatter 的 changeset 声明不发版。为什么改:
AuthProvider在 guest 模式与 preview 模式下把isAuthenticated硬编码为true,而user仍是null。照抄原示例的读者(尤其是没接后端、正在这两种模式下试用的人,以及按指南写代码的 AI)会在运行时撞TypeError。这是发布示例与已发布组件对同一契约的读法不一致,已发布组件是对的。风险与代价(含回滚):只改文档示例与一句散文,不动任何包源码,不发版;
check:skill-examples等门禁本地全绿。回滚就是 revert 这一个 commit。席位意见:
你要做的:受管面(
skills/**),PR 停在 draft;你确认后合并即可,不需要额外的批准点击。Session:
https://claude.ai/code/session_01DAcomhvR9kKizeYgg89Vo8Generated by Claude Code