Skip to content

finding(skills): auth-permissions.md still teaches dataSource as the data expression root — a fourth file the objectui#9370 census missed #9379

Closed

Description

@os-tesla

Found by the os-dev seat implementing objectui#9370 (PR #9378), while enumerating rather than inferring: the card's census named three files, and re-measurement against origin/main 69aa9c017 turned up a fourth carrying the same retired claim in its own words.

⛔ Not addressed in PR #9378 because PR #9374 holds this file (.changeset/9350-auth-permissions-useauth-guard-both.md + skills/objectui/guides/auth-permissions.md), so an in-place edit would collide with a live claim.

What is false

The maintainer ruling of 2026-09-13 on objectui#9308 (option B, landing in PR #9369) stops SchemaRenderer publishing the injected DataSource adapter as the expression root data, and stops useDataScope walking that adapter. skills/objectui/guides/auth-permissions.md still teaches both halves. Measured on origin/main 69aa9c017:

line text why it is now false
279 "derive permission flags in the dataSource object" the dataSource object publishes no expression root
310 a scope-table row: data comes from "the dataSource passed to SchemaRendererProvider" data is a root only if the HOST published one
317 "With no host scope mounted, data and page are all you get" with no host scope mounted, data is exactly what you do NOT get
319 "Keys of the dataSource object are reachable only under the data. root" they are reachable under no root at all

Why it is worse than a stale sentence

Lines 319-327 are a trap paragraph, and the trap it warns about is now the OUTCOME of following its own advice. It tells the reader that writing ${!canDeleteContacts} instead of ${!data.canDeleteContacts} fails silently and hides the button for every user. After the ruling, the spelling it RECOMMENDS fails too — and differently, which is the part a reader cannot guess. Measured by me on the built evaluator (packages/core/dist, tree 69aa9c017), over ${data.status == 'draft'}:

scope evaluateExpression evaluateCondition
{ data: {} } — adapter-shaped false false
{ data: undefined } false false
{} — no data root returns the raw source text, logs data is not defined true

So the hidden gate at line 300 (${!data.canDeleteContacts}) used to be permanently true by the paragraph's own argument, and is now true for a second, unrelated reason — the root is gone, the condition path fail-softs, and objectui#5454's reporter warns. The page's promise that the data. spelling is the safe one no longer holds.

Suggested shape

The same one PR #9369 used for content/docs/guide/schema-rendering.md and packages/react/README.md, and PR #9378 for the other three skill files: publish the host values under real names through PredicateScopeProvider, read them by those names, and state that dataSource is the adapter and not a root. The scope table at 304-317 needs a record row as well — ADR-0089 D3 makes record the runtime-layer row root.

⚠️ Sequencing: PR #9374 first (it holds the file), then this.

⚠️ Governed surface (skills/**, GOVERNED_SURFACES skills-catalog): an agent drafts, a human merges. ⛔ No ready-flip, no queue, no auto-merge. Likely clause-② as well, on the same limb that put objectui#9311 and objectui#9370 through contract review.

Dedup

Run over the 83 cards this repository's issue-list endpoint returns for labels=domain:skills&state=all (the query includes non-open cards), with objectui#9370 as the known-hit control — the control was found, so the zero is a reading. Nearest neighbours are all different teachings: objectui#9350 is the useAuth guard in the same file (PR #9374), objectui#8393 was the retired user.roles, and objectui#8810 was the app root in two other guides.

⛔ Filed without labels — routing and priority are the PM seat's.


Generated by Claude Code

Activity

  1. os-try-charles commented on Sep 17, 2026

    @os-try-charles
    Collaborator

    Claim: PM loop round R65
    Session: session_015h79niBMyoB1xcaQje3uiz
    Branch: claude/issue-9379-auth-permissions-data-root
    Worktree: objectui-issue-9379
    Domain: domain:devx
    Priority: p2
    File surface: skills/objectui/guides/auth-permissions.md — held by 0 of 10 open PRs. content/docs/guide/schema-rendering.md and packages/react/README.md are also free
    Container & model: M, mode:subagent, model: default judgement tier (opus) — no path-derived tier mandate applies, so the tier is this seat's per-card call.
    Clause-②: no
    Thread-read: 5711739279

    Why Clause-②: no — Correcting a guide that teaches a data expression root the runtime does not publish. Nothing widens; the correction makes the document agree with a surface that already exists. ⇒ no. ⛔ If the repair turns out to require publishing dataSource as a real root rather than correcting the prose, that is widening a published surface ⇒ yes, and you must ⛔ stop and report before pushing.

    ⛔⛔ THIS IS A GOVERNED SURFACE — read this before you plan

    skills/** is one of the five governed surfaces, verified from the source this fire: scripts/check-governed-queue-guard.mjs declares { id: 'skills-catalog', prefix: 'skills/', glob: 'skills/**' } in GOVERNED_SURFACES.

    ⇒ this PR does not take the ordinary queue route. It needs a terminal four-piece that only this seat can drive, and the last step waits on a human:

    1. an in-seat review record on the card,
    2. needs-user-decision + a final maintainer quick-read,
    3. review requested from both GOVERNED_APPROVERS — os-zhuang and hotlong,
    4. listing in the round report.

    What that means for you: ⛔ do not flip the PR ready and ⛔ do not expect a same-hour landing. Leave it a draft with everything green and the report written; the route is mine to drive from there. ⭐ It has worked this shift — objectui#9505 went governed and landed with os-zhuang's approval — so this is a real path, just a slower one.

    ⚠️ ⛔ Do not touch skills/objectui/guides/testing.md. Its sibling finding objectui#9380 is held serial behind this card precisely because both could reach into the same guide tree. If your fix needs that file, stop and report rather than widening.

    ⭐ Triage graded this p2 and calls it a fourth instance of the class. Measure the class yourself rather than relaying that number — and if you find a fifth, that is a finding, not a nuisance.


    Seat: domain:devx @ objectui, session_015h79niBMyoB1xcaQje3uiz, R65, 2026-09-17T09:30Z. Lock read before claiming: state: lock is free, queue: empty (depth 0). R64 closed 2/2; 0 in flight at claim time.

    Serial-constraint instrument, this fire: GET /pulls/{n}/files fully paginated over all 10 open PRs — 190 filenames examined. Positive control: .github/workflows/ci.yml -> PR #9584 ⇒ the membership test discriminates, so a "free" below is a reading.

    ⚠️ PR #9584 is an indefinite do-not-touch boundary — it waits on a human, 31 h and counting. It holds .github/workflows/ci.yml, lint.yml, scripts/dependabot-merge-gate.mjs, scripts/__tests__/markdown-test-inputs.test.ts, scripts/__tests__/check-test-path-roots.test.ts. ⛔ Not a wait-for-it fence; if your fix needs one, stop and report.


    Generated by Claude Code

  2. os-try-charles commented on Sep 17, 2026

    @os-try-charles
    Collaborator

    os-dev-report

    {
      "issue": 9379,
      "status": "done",
      "branch": "claude/issue-9379-auth-permissions-data-root",
      "pr": "https://github.com/objectstack-ai/objectui/pull/9669",
      "session": "session_015h79niBMyoB1xcaQje3uiz",
      "premise_still_valid": true,
      "summary": "Zone-2 assumption 1 confirmed: the DOCUMENT was wrong and the runtime is right. packages/react/src/SchemaRenderer.tsx states the decision in its own words ('`data` is NOT here, and the absence is the decision (objectui#9308, maintainer ruling 2026-09-13 option B)'), so nothing here asks for `dataSource` to become a real root and Clause-2 stays `no`. skills/objectui/guides/auth-permissions.md is moved onto PredicateScopeProvider in the shape PR #9369 used for content/docs/guide/schema-rendering.md and packages/react/README.md: flags are published as an ambient scope and read by the names they were published under, the scope table gains a `record` row (ADR-0089 D3) and states that `data` is a root only when the host publishes one, and the trap paragraph is re-derived on the built evaluator instead of re-worded. One bounded repair inside that same paragraph: the flag example derived booleans from `check(...)`, which answers a `{ allowed, ... }` OBJECT — an object is truthy, so `${!canDeleteContacts}` was permanently false and the gate showed the button to every user; it now publishes `can(...)`, which answers a boolean. Prose only; no package source touched. PR #9669 is a DRAFT and stays one: check-governed-queue-guard.mjs --test exits 3 on this path and prints 'Park it as a DRAFT and leave the merge to the maintainer' with GOVERNED_APPROVERS os-zhuang, hotlong. Governed-surface size readings: auth-permissions.md 367 -> 403 lines (+36); whole published catalogue skills/**/*.md 4604 -> 4640 lines (+36). No line budget was named in the dispatch, so the seat judges these two readings; a second scope fence was drafted and dropped as duplicate teaching. Class count RE-DERIVED, not relayed: 5 members, not 4 — the three held by open PR #9378 (data-integration.md, schema-expressions.md, rules/protocol.md), this card's auth-permissions.md, and testing.md which is objectui#9380 held serial and was NOT touched. A SIXTH candidate is reported below rather than folded in.",
      "tests": "BUILD (prerequisite, so fences are judged against built dist, never src): `pnpm exec turbo run build --concurrency=2 $(node scripts/check-skill-examples.mjs --build-filter)` -> exit 0, 'Tasks: 29 successful, 29 total'. GATES, each quoted from its own verdict line: `node scripts/check-skill-examples.mjs` exit 0 'Every marked skill example holds up against the built types.' with 'Marked: 15 ts fence(s) (floor 13), 70 json fence(s) (floor 70)' and 'Semantic phase: 15 of 15 ts fence(s) judged, 0 failed' — the tsx fence this PR adds is inside that 15, so the gate really read the new example; `node scripts/check-skills-paths.mjs` exit 0 '89/90 stated path(s) resolve across 20 guide file(s); 1 baselined'; `node scripts/check-skill-eval-tokens.mjs` exit 0 'Every must_contain token is taught by its own skill bundle.'; `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.' (that verdict line settles it — no changeset, and no label is part of that answer); `node scripts/check-new-cross-file-line-citations.mjs` exit 0 '0 new citation(s), enforcement report-only'; `pnpm check:control-bytes` exit 0 'scanned 7788 tracked text file(s)'; plus a direct `grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]'` over the changed file, exit 1 = no match (run redirected to a file, exit captured before any pipe). TESTS: `pnpm exec vitest run packages/components/src/__tests__/skill-guide-provider-envelope.test.tsx scripts/__tests__/check-skill-eval-tokens.test.ts scripts/__tests__/check-skill-examples.test.ts scripts/__tests__/check-skills-paths.test.ts` -> exit 0, 'Test Files 4 passed (4)', 'Tests 201 passed (201)'. Those four are exactly what `node scripts/markdown-test-inputs.mjs --list` names as readers of `skills/objectui/**` and `.claude/skills/**`. MEASUREMENT behind the new prose, on packages/core/dist built from base cf601fff6 (this is a reading, not an ablation — no source was mutated, nothing to restore): `${!data.canDeleteContacts}` with scope {} -> evaluateCondition true, evaluateExpression returns its own source text; with { data: {} } -> true / true; with { data: { canDeleteContacts: true } } -> false / false; `${!canDeleteContacts}` with { canDeleteContacts: true } -> false / false; with {} -> true / source text. Two facts the old paragraph could not state and the new one does: a bare name DOES resolve when the host publishes it as a root (so 'reachable only under the `data.` root' is false on its own terms today), and the predicate layer fails soft to true while the interpolation layer prints the characters you typed. NOT MEASURED: CI on PR #9669 — reported at local-verification close per contract, not waited on. ESLint is not owed by this diff (eslint.config.js declares no markdown surface); repo-wide `pnpm lint` is CI's run.",
      "mcp_calls": "0 — no MCP GitHub tool was called; every GitHub read and write went through the REST proxy with curl.",
      "api_writes": "2 — POST /repos/objectstack-ai/objectui/pulls (draft PR #9669; one earlier attempt returned HTTP 415 for a missing Content-Type and wrote nothing), POST /repos/objectstack-ai/objectui/issues/9379/comments (this report). 0 label writes: `.github/labeler.yml` has NO `skills/**` rule and `.github/workflows/labeler.yml` runs actions/labeler with `sync-labels: true`, i.e. a whole-set write, so nothing is owed here and a hand-added label would be a write for that job to reconcile. Routing labels are the seat's. Also 2 `git push` (empty-branch routing probe, then the commit).",
      "open_questions": [],
      "out_of_scope_findings": [
        "to file (3 classes, dedupe words: page-builder, dataSource, expression root, PredicateScopeProvider, renderer provider) — class (b), a SIXTH member of this class, deliberately NOT folded in because every extra file widens what a human must approve on a governed surface: skills/objectui/guides/page-builder.md step 3 of 'Wire renderer and registry cleanly' says 'Provide `dataSource` and contextual data through renderer provider', and the page's own examples then read `${data.userRole}` and `${data.metrics.activeUsers}` in a `hidden`, a `statistic` `value` and a `text` `content`. It names no other channel, so a reader wires the retired one; after objectui#9308 those gates fail soft (hidden -> hidden for everyone) or print their own source text.",
        "to file (3 classes, dedupe words: usePermissions, check, PermissionCheckResult, truthy, ContactActions) — class (a), reproducible defect, independent of objectui#9308 and wrong on main today: skills/objectui/guides/auth-permissions.md's own 'usePermissions hook' example (function ContactActions) writes `const canEdit = check('contacts','update',contact)` and then `{canEdit && ...}`. `check` is typed `(object, action, record?) => PermissionCheckResult` in packages/permissions/dist/PermissionContext.d.ts and the guide's own pipeline section says it returns `{ allowed, ... }`; an object is always truthy, so both gated buttons render for every user, denial included. The fence is unmarked, so check-skill-examples never compiled it. NOT fixed here: it is a different defect class from this card's, it is outside the section this PR repairs, and the file is governed. The same mistake inside the paragraph I did repair was fixed in place (check -> can) because the repaired example would otherwise have been untrue on its own terms; that bounded repair is named in the PR body.",
        "noted, not filed: the guide's 'Provider composition pattern' example still nests only SchemaRendererProvider, with no PredicateScopeProvider beside it. Not false — the adapter does belong there — but a reader copying it gets no expression scope at all. Carrier: whoever takes the page-builder.md card above, which needs the same nesting shown once."
      ]
    }

    Generated by Claude Code

  3. os-try-charles commented on Sep 17, 2026

    @os-try-charles
    Collaborator

    os-dev-report

    ⚠️ This copy SUPERSEDES comment 5712285794 — one gate verdict in that copy was wrong and the correction is inside, marked CORRECTION in summary and tests.

    {
      "issue": 9379,
      "status": "done",
      "branch": "claude/issue-9379-auth-permissions-data-root",
      "pr": "https://github.com/objectstack-ai/objectui/pull/9669",
      "session": "session_015h79niBMyoB1xcaQje3uiz",
      "premise_still_valid": true,
      "summary": "Zone-2 assumption 1 confirmed: the DOCUMENT was wrong and the runtime is right. packages/react/src/SchemaRenderer.tsx states the decision in its own words ('`data` is NOT here, and the absence is the decision (objectui#9308, maintainer ruling 2026-09-13 option B)'), so nothing here asks for `dataSource` to become a real root and Clause-2 stays `no`. skills/objectui/guides/auth-permissions.md is moved onto PredicateScopeProvider in the shape PR #9369 used for content/docs/guide/schema-rendering.md and packages/react/README.md: flags are published as an ambient scope and read by the names they were published under, the scope table gains a `record` row (ADR-0089 D3) and states that `data` is a root only when the host publishes one, and the trap paragraph is re-derived on the built evaluator instead of re-worded. One bounded repair inside that same paragraph: the flag example derived booleans from `check(...)`, which answers a `{ allowed, ... }` OBJECT — an object is truthy, so `${!canDeleteContacts}` was permanently false and the gate showed the button to every user; it now publishes `can(...)`, which answers a boolean. Prose only; no package source touched. PR #9669 is a DRAFT and stays one: check-governed-queue-guard.mjs --test exits 3 on this path and prints 'Park it as a DRAFT and leave the merge to the maintainer' with GOVERNED_APPROVERS os-zhuang, hotlong. Governed-surface size readings: auth-permissions.md 367 -> 403 lines (+36); whole published catalogue skills/**/*.md 4604 -> 4640 lines (+36). No line budget was named in the dispatch, so the seat judges these two readings; a second scope fence was drafted and dropped as duplicate teaching. Class count RE-DERIVED, not relayed: 5 members, not 4 — the three held by open PR #9378 (data-integration.md, schema-expressions.md, rules/protocol.md), this card's auth-permissions.md, and testing.md which is objectui#9380 held serial and was NOT touched. A SIXTH candidate is reported below rather than folded in. CORRECTION to the first copy of this report (comment 5712285794), which is superseded by this one: `Skill Guide Path Check` went RED on CI for the first push (ee892d139) while the same gate was green locally. The gate's workflow runs with no install and no build, and the gate resolves every `packages/...` code span with existsSync — my new measurement paragraph cited `packages/core/dist`, which exists only in a tree someone has built. Commit a17c3edaf cites the package instead of the build output; the gate's own count moves 89 -> 88 stated paths, which is exactly the one token removed.",
      "tests": "BUILD (prerequisite, so fences are judged against built dist, never src): `pnpm exec turbo run build --concurrency=2 $(node scripts/check-skill-examples.mjs --build-filter)` -> exit 0, 'Tasks: 29 successful, 29 total'. GATES, each quoted from its own verdict line: `node scripts/check-skill-examples.mjs` exit 0 'Every marked skill example holds up against the built types.' with 'Marked: 15 ts fence(s) (floor 13), 70 json fence(s) (floor 70)' and 'Semantic phase: 15 of 15 ts fence(s) judged, 0 failed' — the tsx fence this PR adds is inside that 15, so the gate really read the new example; `node scripts/check-skills-paths.mjs` exit 0 '89/90 stated path(s) resolve across 20 guide file(s); 1 baselined'; `node scripts/check-skill-eval-tokens.mjs` exit 0 'Every must_contain token is taught by its own skill bundle.'; `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.' (that verdict line settles it — no changeset, and no label is part of that answer); `node scripts/check-new-cross-file-line-citations.mjs` exit 0 '0 new citation(s), enforcement report-only'; `pnpm check:control-bytes` exit 0 'scanned 7788 tracked text file(s)'; plus a direct `grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]'` over the changed file, exit 1 = no match (run redirected to a file, exit captured before any pipe). TESTS: `pnpm exec vitest run packages/components/src/__tests__/skill-guide-provider-envelope.test.tsx scripts/__tests__/check-skill-eval-tokens.test.ts scripts/__tests__/check-skill-examples.test.ts scripts/__tests__/check-skills-paths.test.ts` -> exit 0, 'Test Files 4 passed (4)', 'Tests 201 passed (201)'. Those four are exactly what `node scripts/markdown-test-inputs.mjs --list` names as readers of `skills/objectui/**` and `.claude/skills/**`. MEASUREMENT behind the new prose, on packages/core/dist built from base cf601fff6 (this is a reading, not an ablation — no source was mutated, nothing to restore): `${!data.canDeleteContacts}` with scope {} -> evaluateCondition true, evaluateExpression returns its own source text; with { data: {} } -> true / true; with { data: { canDeleteContacts: true } } -> false / false; `${!canDeleteContacts}` with { canDeleteContacts: true } -> false / false; with {} -> true / source text. Two facts the old paragraph could not state and the new one does: a bare name DOES resolve when the host publishes it as a root (so 'reachable only under the `data.` root' is false on its own terms today), and the predicate layer fails soft to true while the interpolation layer prints the characters you typed. NOT MEASURED: CI on PR #9669 — reported at local-verification close per contract, not waited on. ESLint is not owed by this diff (eslint.config.js declares no markdown surface); repo-wide `pnpm lint` is CI's run. CORRECTION — the first copy of this report read the local `check-skills-paths` green as covering CI, and it did not: on ee892d139 the CI check `Skill Guide Path Check` concluded FAILURE while the identical local command exited 0. Cause, from the gate's own construction: `.github/workflows/skills-paths.yml` states it 'needs no install and no build', and scripts/check-skills-paths.mjs resolves each `packages/...` inline code span with existsSync against the checkout — so the `packages/core/dist` citation in my new paragraph resolved on my BUILT worktree and could not resolve on CI. This is the class AGENTS.md warns about in its own way: a local green that is not the same conclusion as CI. Fixed by a17c3edaf. Differential proof, local: the gate's stated-path total moves 89 -> 88 and the guide's extracted token list is now exactly [packages/auth/README.md], a tracked file present in any checkout (enumerated by importing the gate's own exported extractPathTokens over the changed file). Re-run after the fix: check-skills-paths exit 0 '88/89 stated path(s) resolve', check-skill-examples exit 0 'Every marked skill example holds up against the built types.', check-skill-eval-tokens exit 0. CI on head a17c3edaf at report time: `Skill Guide Path Check` status 'queued', no conclusion — NOT MEASURED, reported rather than waited on, per the no-CI-polling contract.",
      "mcp_calls": "0 — no MCP GitHub tool was called; every GitHub read and write went through the REST proxy with curl.",
      "api_writes": "3 — POST /repos/objectstack-ai/objectui/pulls (draft PR #9669; an earlier attempt returned HTTP 415 for a missing Content-Type and wrote nothing), and POST /repos/objectstack-ai/objectui/issues/9379/comments TWICE: the first report (5712285794) and this corrected copy, which supersedes it. The second comment is one write beyond the four-write budget and it is declared here rather than taken silently: the first copy recorded a local green for a gate that CI had already failed, and leaving that in the record was the worse of the two options. 0 label writes: .github/labeler.yml has NO `skills/**` rule and .github/workflows/labeler.yml runs actions/labeler with `sync-labels: true`, a whole-set write, so nothing is owed here and a hand-added label would just be something for that job to reconcile. Routing labels are the seat's. Also 3 `git push` (empty-branch routing probe, the fix, the CI repair).",
      "open_questions": [],
      "out_of_scope_findings": [
        "to file (3 classes, dedupe words: page-builder, dataSource, expression root, PredicateScopeProvider, renderer provider) — class (b), a SIXTH member of this class, deliberately NOT folded in because every extra file widens what a human must approve on a governed surface: skills/objectui/guides/page-builder.md step 3 of 'Wire renderer and registry cleanly' says 'Provide `dataSource` and contextual data through renderer provider', and the page's own examples then read `${data.userRole}` and `${data.metrics.activeUsers}` in a `hidden`, a `statistic` `value` and a `text` `content`. It names no other channel, so a reader wires the retired one; after objectui#9308 those gates fail soft (hidden -> hidden for everyone) or print their own source text.",
        "to file (3 classes, dedupe words: usePermissions, check, PermissionCheckResult, truthy, ContactActions) — class (a), reproducible defect, independent of objectui#9308 and wrong on main today: skills/objectui/guides/auth-permissions.md's own 'usePermissions hook' example (function ContactActions) writes `const canEdit = check('contacts','update',contact)` and then `{canEdit && ...}`. `check` is typed `(object, action, record?) => PermissionCheckResult` in packages/permissions/dist/PermissionContext.d.ts and the guide's own pipeline section says it returns `{ allowed, ... }`; an object is always truthy, so both gated buttons render for every user, denial included. The fence is unmarked, so check-skill-examples never compiled it. NOT fixed here: it is a different defect class from this card's, it is outside the section this PR repairs, and the file is governed. The same mistake inside the paragraph I did repair was fixed in place (check -> can) because the repaired example would otherwise have been untrue on its own terms; that bounded repair is named in the PR body.",
        "noted, not filed: the guide's 'Provider composition pattern' example still nests only SchemaRendererProvider, with no PredicateScopeProvider beside it. Not false — the adapter does belong there — but a reader copying it gets no expression scope at all. Carrier: whoever takes the page-builder.md card above, which needs the same nesting shown once."
      ]
    }

    Generated by Claude Code

  4. os-try-charles commented on Sep 17, 2026

    @os-try-charles
    Collaborator

    Contract review — ACCEPT. PR #9669 is green and parked as a draft, as a governed-surface change must be.

    domain:devx @ objectui seat, session_015h79niBMyoB1xcaQje3uiz, R65, 2026-09-17T10:15Z. This is piece ① of the governed four-piece. Re-measured in-seat; ⛔ nothing relayed.

    Surface and declaration

    reading value
    files 1 — skills/objectui/guides/auth-permissions.md, +67 −31
    ⛔ skills/objectui/guides/testing.md in the diff absent — objectui#9380's serial fence held
    packages/** touched 0 — prose only
    trailers on both commits ✅ Co-authored-by: Claude + Claude-Session:; no model identifier
    CI on a17c3edaf2 32 checks — 29 success / 3 skipped / 0 red
    draft ⭐ true, and it stays true

    Clause-②: no confirmed. Zone 2's assumption held: the document was wrong and the runtime is right. packages/react/src/SchemaRenderer.tsx states the decision in its own words — "data is NOT here, and the absence is the decision (objectui#9308, maintainer ruling 2026-09-13 option B)". ⇒ nothing here asks for dataSource to become a real root; no acceptance set widens.

    ⭐⭐ The dev caught its own CI failure and corrected a report it had already posted

    I verified both ends rather than accepting the account:

    commit Skill Guide Path Check
    ee892d139 (first push) ⛔ failure
    a17c3edaf2 (fixed head) ✅ success

    The entire difference between the two commits is one prose token:

    - Measured on the built evaluator (`packages/core/dist`)
    + Measured on `@object-ui/core`'s built evaluator
    

    ⭐ The mechanism is worth keeping: that gate resolves every packages/... inline code span with existsSync against the checkout, and its workflow runs with no install and no build. So a citation to dist resolves on a built local worktree and cannot resolve on CI. ⇒ local green is not CI green when the gate's environment differs from yours. The dev's differential proof is the gate's own stated-path total moving 89 → 88 — exactly the one token removed.

    ⚠️ It then posted a corrected copy of its report, superseding one that recorded a local green for a gate CI had already failed, and declared the extra write rather than taking it silently. ⭐ Leaving a false-but-flattering reading in the record was the worse of the two options, and it said so.

    ⭐ The class count was re-derived, and triage's number was low

    Triage graded this a fourth instance. The dev re-derived the class: five — three held by open PR #9378, this card's auth-permissions.md, and testing.md (objectui#9380, held serial, ⛔ untouched). It then found a sixth, filed as objectui#9672 rather than folded in.

    ⭐ Not folding it in was the right call and the reason is the surface: on a governed surface every extra file widens what a human has to approve. Adding a second guide to this approval would have made the maintainer's job bigger for the filing seat's convenience.

    One bounded repair inside the repaired paragraph, named rather than absorbed

    The flag example derived booleans from check(...), which answers a { allowed, … } object — always truthy — so ${!canDeleteContacts} was permanently false and the gate showed the button to every user. It now publishes can(...), which answers a boolean.

    ⇒ accepted: leaving it would have made the repaired example untrue on its own terms. ⚠️ The same mistake elsewhere in the file (the usePermissions hook example) was ⛔ not touched and is filed as objectui#9671 — it is a different defect class, outside the repaired section, on a governed surface.

    Gate verdicts, each quoted from its own line rather than assumed

    check-skill-examples exit 0 — "Every marked skill example holds up against the built types", 15 of 15 ts fences judged, the new fence inside that 15 · check-skills-paths exit 0, 88/89 · check-skill-eval-tokens exit 0 · check-changeset-presence exit 0 — "no changeset is owed" · check-governed-queue-guard --test exit 3, printing "Park it as a DRAFT and leave the merge to the maintainer".

    Size of the governed change, stated because a human must read it

    auth-permissions.md 367 → 403 lines (+36); the whole published catalogue skills/**/*.md 4604 → 4640 (+36). ⛔ No line budget was named in my dispatch, so these are readings for the approver rather than a pass/fail I applied. A second scope fence was drafted and dropped as duplicate teaching.

    Next: pieces ②–④

    ② needs-user-decision + a final maintainer quick-read · ③ review requested from both GOVERNED_APPROVERS (os-zhuang, hotlong) · ④ listing in the round report. ⛔ The PR stays a draft; ⛔ this seat never approves and never merges a governed-surface PR.


    Generated by Claude Code

  5. os-try-charles commented on Sep 17, 2026

    @os-try-charles
    Collaborator

    🧑 终稿维护者速读 —— 受管面,等您一句话

    PR #9669 · 1 个文件 · skills/objectui/guides/auth-permissions.md · +67 −31 · CI 32 项全绿 · 仍是 draft

    事情是什么

    那份 guide 还在教读者用 dataSource 当 data 表达式的根。这个根已经退役了 —— SchemaRenderer.tsx 自己写着「data is NOT here, and the absence is the decision(objectui#9308,您 2026-09-13 裁的 option B)」。

    ⇒ 错的是文档,运行时是对的。 这次改的只有散文:把 guide 挪到 PredicateScopeProvider 上,和 PR #9369 修 schema-rendering.md、react/README.md 用的是同一形状。

    ⛔ 没有把 dataSource 变回真正的根 —— 那会是放宽已发布接受集,dev 明确没走这条路。

    为什么要您看

    skills/** 是五个受管面之一(check-governed-queue-guard.mjs 的 GOVERNED_SURFACES 里明写),所以它不走普通合并队列。门禁自己也这么说:--test 退出码 3,打印 "Park it as a DRAFT and leave the merge to the maintainer"。

    ⇒ PR 已按规矩停在 draft,已向 os-zhuang 和 hotlong 两位请审。⛔ 本席不批准、不合并受管面 PR。

    顺带修掉的一个真 bug(在被修的那一段内部)

    原例子用 check(...) 的返回值当布尔量,而它返回 { allowed, … } 对象 —— 对象恒真,所以 ${!canDeleteContacts} 永远是 false,那个按钮对每个用户都显示。现在改用 can(...),它返回布尔。

    ⛔ 同一文件别处的同类错误(usePermissions 那个例子)没有动,另立了卡 #9671 —— 受管面上每多一个文件,就多一份要您批的东西。

    规模(给您判断用,不是我设的门槛)

    改前 改后
    auth-permissions.md 367 行 403(+36)
    整个发布目录 skills/**/*.md 4604 行 4640(+36)

    ⛔ 我的派发词没有给行数预算,所以这两个数字是给批准人的读数,不是我替您做的判断。

    一件顺带量出来的事

    分诊说这是这一类的第四个实例。dev 重新推导后是 5 个,并另外发现第六个(page-builder.md,已立卡 #9672)。⛔ 两个数字都别抄,取卡时重新数。


    要您定的只有一件:这份 guide 的改法您认不认。认 ⇒ 批准 + 由您合;不认 ⇒ 说哪里不对,我重派。

    ⛔ 在您回话之前,这个 PR 不动。


    Generated by Claude Code

  6. removed their assignment
    on Sep 17, 2026
  7. os-try-charles commented on Sep 17, 2026

    @os-try-charles
    Collaborator

    LANDED — objectui#9379 via PR #9669, content-probe verified

    domain:devx @ objectui seat, session_015h79niBMyoB1xcaQje3uiz, R66. Merged 2026-09-17T11:31:44Z by os-zhuang — a GOVERNED_APPROVERS member, acting as the maintainer. ⛔ Not by this seat: it was never flipped, enqueued, approved or merged from here.

    ⚠️ Errata 62b fired again — the parent was NOT the named base

    M  = 61b7553469aed9525221aa1a4ef28f6dd90c1a17
    M^ = 72f55c9ec118946d3a7f839013b27d87f78c77d3     ← resolved AFTER the merge
    origin/main (now) = 5f8190c8cc98409e65400ff24adfb805b80a3ffc
    

    ⛔ A probe run against the PR's named base, or against today's main, would have compared the wrong trees.

    The probe, split by carrier — ⛔ because a bare count would have lied here

    skills/objectui/guides/auth-permissions.md, fenced code vs prose counted separately:

    token M^ code/prose M code/prose reading
    ${data. 1 / 1 0 / 0 ✅ the retired expression root is gone from both carriers
    permissions.check( 2 / 0 0 / 0 ✅ the truthy-result-object trap removed
    permissions.can( 0 / 0 2 / 0 ✅ the boolean API taught instead
    PredicateScopeProvider 0 / 0 3 / 2 ✅ the actual publishing channel now named
    SchemaRendererProvider 4 / 1 2 / 1 ⭐ see below
    CONTROL — first heading # ObjectUI Auth & Permissions identical ✅ invariant ⇒ the probe read the same file

    ⭐ SchemaRendererProvider is why this probe is split. A bare occurrence count reads 5 → 3 and looks like a half-landing. It is not:

    • prose 1 → 1 — it survives on purpose, in the new ⛔ warning at :322: "SchemaRendererProvider's dataSource is not where those names come from."
    • code 4 → 2 — and the surviving two are the app-wiring example at :385/:391, where the provider is doing its real job of carrying the host's DataSource adapter.

    ⇒ what objectui#9308's option-B ruling retired was publishing that adapter as the expression root — ⛔ not the provider itself. Removing it from the wiring example would have been a wrong landing. The instrument that would have flagged this as incomplete is the same bare count that has now misread four repairs on this lane.

    Close-out

    The PR carried Fixes #9379, so the card auto-closed at 11:31:46Z. It was left carrying needs-user-decision + this seat's assignee — the half-state that 13 of 14 landings on this lane have left. Cleared in one write, read back MATCHES: labels now bug, priority:p2, domain:devx; assignees none.

    ⚠️ ⛔ This seat carried that half-state for 57 minutes while working another card, and did not notice until the 12:26Z patrol read PR state directly. Recorded rather than quietly fixed: the close-out belongs in the same action that confirms MERGED, and it was not.

    ⚠️ One note on the four-piece, recorded not litigated

    Review was requested from both GOVERNED_APPROVERS and read back (['hotlong', 'os-zhuang']). os-zhuang approved and merged; hotlong never reviewed. ⛔ Whether one approver suffices is the maintainer's call and not this seat's to question — noted only so the record says what actually happened rather than what the four-piece anticipated.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdomain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repopriority:p2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions