Split out of #491 so the platform-level gap is visible on its own and leadership can decide whether to (re-)escalate it to the upstream runtime repo. This is an upstream limitation, not app metadata.
The gap
The list-view data path (/api/v1/data/..., platform-objects) resolves {current_user_id} in filters — the "My Leads / My Tasks / My Deals" list views all work. The analytics path (dashboard widgets / dataset reports, /api/v1/analytics/...) resolves no user token at all: the literal string reaches the SQL WHERE, matches no owner, and the widget renders 0 for every viewer.
This was proven empirically before #491 and is documented in src/apps/crm.app.ts (My Work group note): a "My Day" dashboard was built and removed after a side-by-side test on one dashboard — {current_user} → 0, {current_user_id} → 0, no owner filter → 10,100,081. That note says "Filed upstream", but no issue link was recorded — hence this tracking issue.
(For contrast, the same analytics path DOES resolve the DATE_MACRO_TOKENS vocabulary — verified during #491 via the generated SQL in analytics responses — so this is specifically about user tokens.)
⚠️ The headline above is not quite the mechanism, per the upstream review of objectstack#12376. Token resolution had already landed in @objectstack/core after 17.1.0; what actually produced the measured 0 was two narrower holes — the direct AnalyticsService.query / generateSql door resolved nothing (so the SQL strategy bound the literal while the ObjectQL strategy resolved via the engine), and the dataset-scope channel handed strategies an unresolved copy of the filter which was ANDed beside the resolved one, producing an unsatisfiable owner = $viewer AND owner = '{current_user_id}'. That second one is why the shape was a hard 0 rather than a partial result. The defect was real; the one-line diagnosis in this card was incomplete.
Impact on this app
To close this issue
Once the Restart-when: predicate above is met, restore the personal widget on the service_dashboard table widget and retitle it back to "My Open Cases by Priority".
⚠️ Use owner_id, not owner. Since #548/#677 the owner column no longer exists and the spelling in the original instruction fails with no such column: owner (measured). Copying that line verbatim will misfire.
⭐ Two behaviour changes arrive with the fix, and both help: an unresolvable placeholder now refuses loudly (FILTER_TOKEN_UNKNOWN / FILTER_TOKEN_UNRESOLVED, HTTP 400) instead of charting a plausible zero — so a broken restore will look like an error rather than an empty widget — and the {current_user} misspelling this card records is now caught with a near-miss suggestion rather than silently rendering 0.
⚠️ Verify the restore by having two different reps see different rows. {current_user_id} is presentation scope, not an access boundary — that is the frozen vocabulary's own declaration (objectstack#3594). Row-level security owns the guarantee that one rep cannot reach another's cases; this token only scopes what a widget shows.
Split out of #491 so the platform-level gap is visible on its own and leadership can decide whether to (re-)escalate it to the upstream runtime repo. This is an upstream limitation, not app metadata.
The gap
The list-view data path (
/api/v1/data/..., platform-objects) resolves{current_user_id}in filters — the "My Leads / My Tasks / My Deals" list views all work. The analytics path (dashboard widgets / dataset reports,/api/v1/analytics/...) resolves no user token at all: the literal string reaches the SQLWHERE, matches no owner, and the widget renders 0 for every viewer.This was proven empirically before #491 and is documented in
src/apps/crm.app.ts(My Work group note): a "My Day" dashboard was built and removed after a side-by-side test on one dashboard —{current_user}→ 0,{current_user_id}→ 0, no owner filter → 10,100,081. That note says "Filed upstream", but no issue link was recorded — hence this tracking issue.(For contrast, the same analytics path DOES resolve the DATE_MACRO_TOKENS vocabulary — verified during #491 via the generated SQL in analytics responses — so this is specifically about user tokens.)
Impact on this app
service_dashboard's "My Open Cases by Priority" widget silently showed 0 for everyone (it also misspelled the token as{current_user}, but the correct spelling would not have helped). The Views/pages/dashboards: dead references, unresolvable tokens, unreachable surfaces #491 branch re-scoped it to team-wide "Open Cases by Priority".my_open_caseslist view + a "My Cases" (我的工单) entry in the My Work nav group, joining My Tasks / My Deals / My Leads.To close this issue
Once the
Restart-when:predicate above is met, restore the personal widget on theservice_dashboardtable widget and retitle it back to "My Open Cases by Priority".owner_id, notowner. Since #548/#677 theownercolumn no longer exists and the spelling in the original instruction fails withno such column: owner(measured). Copying that line verbatim will misfire.⭐ Two behaviour changes arrive with the fix, and both help: an unresolvable placeholder now refuses loudly (
FILTER_TOKEN_UNKNOWN/FILTER_TOKEN_UNRESOLVED, HTTP 400) instead of charting a plausible zero — so a broken restore will look like an error rather than an empty widget — and the{current_user}misspelling this card records is now caught with a near-miss suggestion rather than silently rendering 0.{current_user_id}is presentation scope, not an access boundary — that is the frozen vocabulary's own declaration (objectstack#3594). Row-level security owns the guarantee that one rep cannot reach another's cases; this token only scopes what a widget shows.