Skip to content

docs(skills): guard both useAuth members in the auth-permissions example - #9374

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-9350-useauth-guard-both
Sep 13, 2026
Merged

docs(skills): guard both useAuth members in the auth-permissions example#9374
os-project-manager merged 1 commit into
mainfrom
claude/issue-9350-useauth-guard-both

Conversation

@claude

@claude claude Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Fixes #9350

What changed

skills/objectui/guides/auth-permissions.md, the fence under "useAuth hook", read user.name behind an isAuthenticated-only early return. AuthProvider in @object-ui/auth computes isAuthenticated as user !== null && session !== null only when auth is enabled and not in preview mode; in guest mode (enabled: false) and in preview mode it hardcodes true while user stays null, so the example threw a TypeError in exactly the two modes a reader without an auth backend is in. The shipped UserMenu component already guards both members.

  • The early return now reads 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.
  • One sentence above the fence says why a signed-in-looking context can still carry no user and points at UserMenu as the shipped shape. The prose moved with the example, as AGENTS.md requires.
  • An empty-frontmatter changeset declares that nothing published by a package moves.

Not done, by the grading (comment 5651956190): no os:check marker on this fence. It is a fragment by construction (three undeclared placeholders: the spinner, the login button and the button), and marking it would red check:skill-examples for 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 67cccb0 with 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.
  • TS18047 rows 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 phase summary 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).
  • Count of isAuthenticated || !user in this file: 0 before, 1 after.
  • Count of useAuth in this file (lit control): 5 before, 5 after.
  • Prose sentence present (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.md on the built tree (on-disk proof: 365 lines, old guard 1, new guard 0, prose 0), then --measure, then git checkout HEAD -- FILE. Restoration is proven by git hash-object equal to the HEAD blob (dd4e4633…), git diff HEAD --stat empty and git status --porcelain empty. The very first --measure attempt, before the build, exited 2 (PRECONDITION NOT MET) and is not a reading.

Line budget (published skills/**)

  • Whole file skills/objectui/guides/auth-permissions.md: 365 → 367 lines (net +2, ceiling +2; 3 insertions, 1 deletion; no re-wrap).
  • Whole catalog, sum of skills/**/SKILL.md in objectui: 137 → 137 (one file, untouched).
  • Token gate 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.mjs in this tree): root package.json check:* scripts whose source reads skills/, 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).
  • NOT MEASURED: pnpm check:doc-snippets exited 2 (PRECONDITION NOT MET: a different 34-package closure is unbuilt), and its own header states that skills/objectui/** is not claimed by that gate, so it is not a derived gate for this diff.
  • Not owed: no package source changed, so no package test or typecheck closure; pnpm lint is 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 no skills/ file.

Acceptance notes (noted, not filed)

  • Whether to make the useAuth fence self-contained (declare the spinner, login-button and button placeholders) and then mark it os:check is a separate question by the grading; today it is a fragment by construction, like the other unmarked fences in this file that --measure lists. 承接者:无 — no queued PR or person is on this file.
  • The second useAuth use in this file (the marked PermissionProvider setup fence) reads user?.positions and user ?? undefined; it does not have this defect and was not touched.
  • Same class as objectui#9311 (the dataSource member in data-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 改为同时看 isAuthenticateduser(与仓内已发布的 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_01DAcomhvR9kKizeYgg89Vo8


Generated by Claude Code

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>
@claude

claude Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor Author

Contract review

Head: 67cccb09c (objectui PR #9374, card objectui#9350) — read at 2026-09-13T08:01Z by the skills seat at the contract-review tier (served model claude-fable-5-1, get_session external_metadata.last_served_model at 2026-09-13T07:35Z).

① derived judgments: the diff makes ONE falsifiable claim on a published skill — in guest mode and preview mode isAuthenticated is true while user is null, so the example must guard both — checked on objectui origin/main 69aa9c0: packages/auth/src/AuthProvider.tsx :197–:199 const isAuthenticated = (enabled && !isPreviewMode) ? user !== null && session !== null : true and packages/auth/src/UserMenu.tsx :43 if (!isAuthenticated || !user): correct. The probe direction was proven both ways by the dev on one built tree (check-skill-examples.mjs --measure: the TS18047 row at :49:20 present with the base content, absent with the head content, restore proven by blob hash). No accept-set or public-surface change; no clause-② carrier script exists in objectui, so the pair gate is not applicable — declared Clause-②: no, no widening in the diff.
② semver: docs-only; objectui's convention is the empty-frontmatter changeset, present (.changeset/9350-auth-permissions-useauth-guard-both.md, ---\n---), and check-changeset-presence.mjs reads no changeset owed.
③ boundary flags: none raised (open_questions: []); the fence stays an unmarked fragment by the grading's instruction — three noted, not filed items carry no bearer and are accepted as noted.

Implemented-by: claude/issue-9350-useauth-guard-both (mode:subagent)
Reviewed-by: session_01DAcomhvR9kKizeYgg89Vo8

Verdict: PASS. Governed surface (published skills/**): no gate carrier was hung (the content limb is reviewed here); the PR stays a draft for the maintainer's hand merge.


Generated by Claude Code

@claude

claude Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor Author

维护者速读

改了什么 —— 发布技能 skills/objectui/guides/auth-permissions.mduseAuth 示例的一行守卫:从只看 isAuthenticated 改成 !isAuthenticated || !user,并在示例上方加一句解释——guest 模式和 preview 模式下 AuthProviderisAuthenticated 写死为 true 而 user 仍为 null,所以读 user 要单独守。365 → 367 行(预算 +2 内);附一个空 frontmatter changeset(objectui 文档改动的正确形态)。

为什么改 —— 照抄这个示例的读者在没有后端的 guest / preview 模式下会直接 TypeError——而那正是原型阶段最常见的两种模式;仓库自己发运的 UserMenu 早就两个都守。修法与它对齐。

风险与代价(含回滚) —— 纯文档面,不动任何包;回滚 = revert 单文件 3 行 + 删 changeset。

席位意见 —— 收。本席在 head 67cccb0 上亲核:守卫替换 1/0、解释句在、AuthProvider :197–:199 与 UserMenu :43 一致;dev 在同一棵已构建树上用 check-skill-examples --measure 证明了红→绿(旧内容 1 行 TS18047、新内容 0,按 blob 哈希还原);真门禁 check:skill-examples exit 0;契约复核 PASS 记录 5652098578。CI 在读时 24 绿 7 在跑,Lint / Type Check / 队列守卫已绿。

你要做的(一个动作) —— 受管面(发布 skills/**):CI 转绿后 approve 并合并。


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review September 13, 2026 08:02
@os-zhuang
os-zhuang enabled auto-merge September 13, 2026 08:02
@os-zhuang
os-zhuang disabled auto-merge September 13, 2026 08:03
@claude

claude Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor Author

维护者速读(补记:检查全部跑完)

读数 —— head 67cccb09,2026-09-13T08:18Z:35 个 check 全部完成 —— 31 绿、3 跳过、1 红:Doc Snippet Type Check

那一红不是本 PR 的 —— 同名检查在 main 上自 edea22a5(PR #9310,2026-09-13T04:59Z 起)就红,之后每次 push 都红;本 PR 与 main 最新一跑(69aa9c01)的失败签名逐字相同:同一步 node scripts/check-doc-snippet-types.mjs,同样三处 TS2740(content/docs/guide/schema-rendering.md:99 / :434packages/react/README.md:73),首行错误一致。它不在 main 的必过集里(必过集为 Lint / Type Check / Build & E2E / Test 四分片 / Build Docs / Changeset Declaration,已现读 rulesets)。承接卡是 objectui#9346(domain:ui,pm:blocked 等 objectui#9308;修它的 PR 是 #9369,ui 席在飞)。按你今早在 #17934 上接受的形状(同名且同签名的 base 继承红不计入「全绿」),本 PR 自己的面是干净的。

你要做的(一个动作) —— 你已 approve、翻 ready、开过又关了 auto-merge;若关它是因为那一红,现在可以重新挂 auto-merge(队列只看必过集)或直接合;本席不代你挂。


Generated by Claude Code

@os-project-manager
os-project-manager added this pull request to the merge queue Sep 13, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks Sep 13, 2026
@os-project-manager
os-project-manager added this pull request to the merge queue Sep 13, 2026
Merged via the queue into main with commit ffc4c44 Sep 13, 2026
35 of 36 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-9350-useauth-guard-both branch September 13, 2026 10:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(skills): the auth-permissions.md useAuth example reads user.name behind an isAuthenticated guard that guest mode and preview mode hardcode true

3 participants