fix(skills): teach {current_user_id}, not $currentUser, in the objectstack-ui Filtering example - #14781
Merged
Merged
Conversation
…tering example
`skills/objectstack-ui/rules/list-views.md` taught `$currentUser` as a filter
value. No filter path resolves it: both resolvers recognise a placeholder only
when the whole value is brace-wrapped (`FILTER_TOKEN_WRAPPED_RE` in
`packages/spec/src/data/context-tokens.zod.ts`, `WHOLE_TOKEN_RE` in
`@object-ui/core`), so an unbraced `$currentUser` is not even classified as a
placeholder attempt — it reaches the data engine as a literal, matches nothing,
and the list renders empty with no diagnostic anywhere.
Rewrite the example value and its note to `{current_user_id}`, the declared
token, so the rule file agrees with the package's own
`## Date Macros — Filter Placeholders` contract in SKILL.md.
Net -4 bytes (3011 -> 3010 tokens, ceiling 3011 unchanged).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
os-zhuang
approved these changes
Sep 3, 2026
os-zhuang
marked this pull request as ready for review
September 3, 2026 02:32
os-zhuang
enabled auto-merge
September 3, 2026 02:32
Contributor
Contributor
This was referenced Sep 3, 2026
This was referenced Sep 3, 2026
This was referenced Sep 3, 2026
This was referenced Sep 3, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #14139
skills/objectstack-uitaught$currentUseras a filter value. Nothing resolvesit. The example and its note now teach
{current_user_id}, the declared token,so the rule file agrees with the package's own filter-placeholder contract.
Step 1 — the route, settled at source
Route 1. No filter path resolves the literal
$currentUser, on either sideof the wire, and no legacy alias maps it. Route 2 (an ADR-0087 conversion-layer
question) does not arise.
Where the literal was searched — every place, with a positive control
git grep -n -F '$currentUser'(all tracked paths)224f8ea4docs/adr/0017-object-has-many-view.md:216(SQL-shaped prose),packages/cli/src/commands/explain.ts:128(anassignmentdefault value — a different surface), and the two sites fixed heregit grep -ni 'currentuser'excluding*CHANGELOG.md224f8ea4packages/spec/src/data/context-tokens.test.ts:44REJECTScurrentUserIdamong near-misses;packages/spec/src/data/default-value-shape.test.ts:54pinscurrentUser (camelCase) is a literalgit grep -n -F '$currentUser'67dadd6packages/types/src/__tests__/phase2-schemas.test.ts:791,808—ListViewSchema.safeParse(...)shape assertions on a tab's filter array. Neither asserts resolutioncurrent_user_idon the same tree: 14 hits inpackages/core/src/utils/filter-tokens.tsand 14 in its testgit grep -n -E "'\$[a-zA-Z]"overpackages/core/src,packages/objectql,packages/lint/src,packages/spec/src224f8ea4$in,$and,$or,$not,$gte…) and$source/$root— no$-prefixed session-token alias table anywherepackages/does returnexplain.ts:128, so it can see the shape it is looking forWhy nothing can resolve it — the mechanism, not an absence of hits
A filter value is recognised as a placeholder only when the whole value is
brace-wrapped.
$currentUsercarries no braces, so it is not classified as aplaceholder at all — not even as an unknown one.
packages/spec/src/data/context-tokens.zod.ts:84CONTEXT_TOKENS = ['current_user_id', 'current_org_id']— the complete setpackages/spec/src/data/context-tokens.zod.ts:146FILTER_TOKEN_WRAPPED_RE = /^\$?\{([^{}]+)\}$/packages/spec/src/data/context-tokens.zod.ts:239-253classifyFilterTokenreturnsnullwhen that regex does not match — i.e. "not a placeholder", pass through verbatimpackages/core/src/utils/filter-tokens.ts:107,135,209WHOLE_TOKEN_RE = /^\$?\{([a-zA-Z0-9_]+)\}$/, used byresolveContextTokensandresolveFilterPlaceholderspackages/core/src/utils/filter-tokens.ts:364resolveFilterTokenswalks with the sameclassifyFilterToken; itshasFilterTokenpre-pass returnsfalsefor a tree holding only$currentUserpackages/lint/src/validate-filter-tokens.ts:65,123-124filter-token-unknownpushes a finding only whenclassifyFilterToken(node)?.kind === 'unknown'Consequence, and it is sharper than the card assumed: because
$currentUserisunbraced it is not a placeholder attempt, so
filter-token-unknownnever fireson it and
resolveFilterTokensnever throws. The value reaches the data engineas a literal string, matches no record, and the list renders empty — with no
build error and no runtime warning anywhere. The card offered "a red
os validateor a silent empty list"; only the silent half is reachable.The change
Two lines in
skills/objectstack-ui/rules/list-views.md, in the### Filteringsection. The example keeps its shape.
Example — before
Example — after
Note — before (71 bytes)
Note — after (62 bytes, i.e. no more than the old note)
Every claim in the new note is traceable to a source line:
{current_user_id}is a declared filter tokenpackages/spec/src/data/context-tokens.zod.ts:84-87packages/core/src/utils/filter-tokens.ts:364(server) and objectuipackages/core/src/utils/filter-tokens.ts:209(client)packages/spec/src/data/context-tokens.zod.ts:176—CONTEXT_TOKEN_DESCRIPTIONS.current_user_id = "The signed-in user's id (\sys_user.id`)."`After the change the rule file agrees with its own package entry:
skills/objectstack-ui/SKILL.md→## Date Macros — Filter Placeholdersnames{current_user_id}/{current_org_id}and delegates the vocabulary toobjectstack-query→rules/filters.md.Token budget — shrink-only, ceiling untouched
The ratchet convention is
ceil(utf8 bytes / 4).rules/list-views.mdbytesrules/list-views.mdtokensrules/list-views.mdlinesskills/objectstack-ui/— hand-authored (ratcheted) tokensskills/objectstack-ui/— whole package tokens (incl. generator-owned)skills/objectstack-ui/— hand-authored linesThe honest rewrite is net negative, so no payment was needed and no
restatement was deleted. No ceiling was changed: the row stays
['skills/objectstack-ui/rules/list-views.md', 3011], and the gate's own line isNo re-wrap was used as payment — the diff is two whole-line replacements, and
the line count is unchanged.
Gates
All run under
scripts/pm/os-verify-lock.sh, each exit code captured byredirect before any pipe, each verdict quoted from the gate's own output.
node scripts/check-skills-token-ratchet.mjs✓ check-skills-token-ratchet: 36 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted.node scripts/check-skills-token-ratchet.mjs --self-test✓ check-skills-token-ratchet self-test: 64 cases pass.pnpm check:skill-identifier-livenesscheck-skill-identifier-liveness OK — Leg 1: 465 citation(s) over 46 published file(s) …; Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s).pnpm --filter @objectstack/spec run check:skill-examples✅ 256 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of thempnpm --filter @objectstack/spec run check:skill-docs✅ Skill docs in syncpnpm check:role-wordcheck-role-word: OK, no new occurrences of the reserved word.(Scanned: 224 .md/.mdx file(s) … skills 34)pnpm check:nul-bytescheck-nul-bytes: OK (scanned 8052 text file(s) … no raw ASCII control bytes).pnpm --filter @objectstack/lint run check:doc-formula-expressionsThe re-derived union
Re-derived after the last edit with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands,which reported
gate list derived from the tree of 'objectstack-ai/objectstack' at commit 482fb9c75and a change set of 1 path. Every command it named was run:
node scripts/check-ci-filter-parity.mjsOK: all 130 declared cross-package glob(s) (92 unique) are covered …node scripts/check-cross-package-test-inputs.mjsOK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.node scripts/check-shard-attestation.mjs✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s).node scripts/check-skills-token-ratchet.mjsnode scripts/check-test-completeness.mjscheck-test-completeness: PREREQUISITE NOT MET — this gate grades a saved 'turbo run test' log, and no log was named.The gate's own text adds: "running the family locally, record this gate as NOT MEASURED. ⛔ It is not a red, and there is nothing here to fix."pnpm --filter @objectstack/lint run check:doc-formula-expressionspnpm check:agent-test-spellingpnpm check:corpus-claim-driftcheck-corpus-claim-drift: OK, no new claim sites beside a pinned spelling.pnpm check:cross-package-test-inputsAll 117 self-test cases passed.+OK: 25 package(s) read outside themselves, all declared …pnpm check:doc-authoring✓ doc authoring guard: 46 published skill files clean — no internal issue-id references.pnpm check:pm-governed-merges✓ check-governed-merges --self-test: 243 assertions …+live: the real generator declared 9 output(s) and certified this treepnpm check:role-wordpnpm check:skill-compatibility✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packagespnpm check:skill-frame-sync✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 filespnpm check:skill-identifier-livenessThe union derivation also notes that 9 further families "apply once this card's
changeset exists" — this PR carries
skip-changeset(below), so those paths donot exist and those families do not apply.
check:skill-examplesneeded a build prerequisite on its client SDK surface(
packages/client-react/dist holds no .d.ts declarations — the package is not built), which is unrelated to this diff. It was satisfied(
pnpm --filter '@objectstack/client-react...' build, thenpnpm --filter '@objectstack/client...' build, both exit 0) and the gate re-run,so the row above is a real measurement and not a NOT MEASURED.
Fence census — the
### Filteringexample is not a typed blockcheck:skill-examplesextracts a fence only when the line directly above itcarries an
os:checkmarker (an HTML comment — written here as the bare token sothis body survives GitHub's sanitizer). Census of
skills/objectstack-ui/rules/list-views.md:224f8ea4)482fb9c7)os:checkmarker linesNo marker moved and no fence moved. The
### Filteringfence opens at line 92and line 91 is blank — no marker — so that block is not among the gate's
extracted examples, before or after. The gate's skills+docs surface count is
unchanged at 224 blocks.
skip-changesetThis PR publishes nothing from any package:
skills/is not listed in anypackage manifest's
files, and no build step copies it into a publishedartifact. Merged precedent on this exact surface —
58ea39a5d(#14658),446117fc2(#14673),c985ae958(#14660) — are all skills-only merges and nonecarries a
.changeset/*.md.Check Changesetrequires an added.changeset/*.mdunless the label is present, so the label is what keeps a release-less PR green.
Premises that did not hold
skills/objectstack-ui/SKILL.mdskills/objectstack-ui/rules/list-views.md. The ui split (#14658) moved them. Same published package, different file — and the fix landed on the file that actually holds the text## Context Tokenssection stating "the only two tokens"skills/any more. The surviving contract half is## Date Macros — Filter Placeholdersinskills/objectstack-ui/SKILL.md, which delegates the vocabulary toobjectstack-query→rules/filters.md. So the contradiction spanned two files in one package, not two halves of one fileSKILL.md's row, untouched here. The row governing this edit is['skills/objectstack-ui/rules/list-views.md', 3011]— headroom 0 before, 1 after$currentUsergets a redos validate(filter-token-unknown) or a silent empty listfilter-token-unknownfires onkind === 'unknown', which requires a brace-wrapped value;$currentUserclassifies asnull(not a placeholder) and is passed through verbatim### Filteringexample is a typed block checked bycheck:skill-examplesos:checkmarker on the line directly above (packages/spec/scripts/check-skill-examples.ts:398,601). The### Filteringfence has none — see the fence census aboveNothing else in the card's scope changed:
packages/cli/src/commands/explain.tsand
docs/adr/0017-object-has-many-view.mdare untouched, as dispatched.🤖 Generated with Claude Code
https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Generated by Claude Code