Skip to content

bug(skills): testing.md Pattern 5 gates on a bare userRole root nothing publishes — copy the example and the assertion throws #9380

Description

@os-tesla

Found by the os-dev seat implementing objectui#9370 (PR #9378) while enumerating every ${data.…} and every expression example under skills/. This one is independent of objectui#9308: it is wrong on main today, and it stays wrong after that ruling lands.

The example

skills/objectui/guides/testing.md, "Pattern 5: Component rendering with SchemaRenderer", measured on origin/main 69aa9c017, lines 130-169. The fence builds a provider bag and then asserts the gated node is on screen:

const dataSource = { users: [...], userRole: 'admin' };
...
schema={{ type: 'text', content: 'Secret', hidden: '${userRole !== "admin"}' }}
...
// admin should see it
expect(screen.getByText('Secret')).toBeDefined();

userRole is spelled as a bare root. Nothing publishes it as one. SchemaRendererProvider's dataSource never spread its keys as bare names — the guide's own sibling skills/objectui/guides/auth-permissions.md documents exactly that trap at lines 319-327 ("Keys of the dataSource object are reachable only under the data. root — they are not also spread as bare names").

Measured, not inferred

On the built evaluator (packages/core/dist, tree 69aa9c017), evaluateCondition('${userRole !== "admin"}', scope):

scope hidden verdict node on screen
what the OLD renderer built: { data: { userRole: 'admin' } } true NO
what the renderer builds after objectui#9308: nothing published true NO
what the example ASSUMES: { userRole: 'admin' } false YES

So the node is hidden, getByText('Secret') throws, and the published test pattern fails for a reader who copies it verbatim. It is the fail-soft leg: userRole is not in scope, the expression is unevaluable, and the condition path returns true.

Why no gate sees it

--measure on scripts/check-skill-examples.mjs puts this fence in the root-bound refusal set — it imports vitest and @testing-library/react, which only the repository ROOT manifest declares, so the bound keeps it out of the semantic program and it is never type-checked. It is also unmarked, so it is outside the opt-in population either way. And type-checking would not catch this regardless: the defect is a runtime scope fact, not a type.

This is the class the gate's own header names — a fence can be wrong in a way no gate sees — so it needs a human edit, not a marker.

Suggested shape

Either publish userRole as a real root through PredicateScopeProvider (the channel objectui#9308 makes canonical, and the one a reader should be learning in a testing guide), or spell the gate against a root the example actually publishes. ⛔ Do not "fix" it by asserting the node is absent — the comment // admin should see it says what the pattern is meant to demonstrate, and inverting the assertion would publish a test pattern that teaches the wrong wiring while passing.

⚠️ Governed surface (skills/**, GOVERNED_SURFACES skills-catalog): an agent drafts, a human merges. ⛔ No ready-flip, no queue, no auto-merge.

Dedup

Run over the 83 cards this repository's issue-list endpoint returns for labels=domain:skills, non-open cards included, with objectui#9370 as the known-hit control — the control was found, so the zero is a reading. The two prior testing.md cards are different subjects: objectui#7557 retired the KNOWN_ROOT_DEVDEP_EXAMPLES rows and objectui#7494 the KNOWN_BARE_ANY_EXAMPLES rows. Neither touches what this fence asserts.

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


Generated by Claude Code

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions