Skip to content

docs(ui): a dashboard global filter's field resolves against the dataset object, not its dimensions (#16167) - #16266

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-16167-global-filter-resolution-docs
Sep 6, 2026
Merged

docs(ui): a dashboard global filter's field resolves against the dataset object, not its dimensions (#16167)#16266
baozhoutao merged 1 commit into
mainfrom
claude/issue-16167-global-filter-resolution-docs

Conversation

@claude

@claude claude Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Fixes #16167

Adds one section — ### Where a Filter's field Resolves — to content/docs/ui/dashboards.mdx, inside ## Global Filters, between the name paragraph and ### Date Filter Defaults. Docs only; no source, no schema, no behaviour change.

What the gap actually was

Triage (comment 5556889150) corrected the card's premise, and re-reading origin/main confirms the correction: two of the four facts are already written down, on content/docs/deployment/validating-metadata.mdx.

  • validating-metadata.mdx:44-47 — "A dashboard widget points at a dataset and reads dimensions/values from it." (dimensions resolve against the dataset)
  • validating-metadata.mdx:49-58 — "os validate fails when a filter's effective field — after any per-widget filterBindings re-target — is absent on the widget's dataset object … Opt a widget out with filterBindings set to false for that filter."

So the gap is not "unwritten". It is that the two resolution targets sit in adjacent paragraphs on a validation reference page and their asymmetry is never named — nobody states that filter field and widget dimensions are two different namespaces, which is why the same field can be filterable and not group-by-able on one dataset. The new section states that side by side on the page authors read when writing globalFilters, and links out to the validation page rather than duplicating it.

Readings taken on origin/main (0e16fc4), platform side

packages/lint/src/validate-widget-bindings.ts:

Reading Location
const datasetObject = typeof dataset.object === 'string' ? dataset.object : undefined; :857
const verdict = resolveFieldPath(graph, datasetObject, field); — the filter field resolves against dataset.object, never dataset.dimensions :877
DASHBOARD_FILTER_FIELD_UNKNOWN, severity: 'error' (dotted-path arm) :900 / :901
DASHBOARD_FILTER_FIELD_UNKNOWN, severity: 'error' (bare-name arm) :917 / :918
Dimension lookup: dimensionNames built from recordsOf(dataset.dimensions) by name; a widget dimension is accepted iff dimensionNames.has(...) :1057-1060, :1068-1070
WIDGET_DIMENSION_UNKNOWN, severity: 'error' — hint reads "Widgets select dataset dimensions BY NAME." :1072 / :1073

Also read and reflected in the wording: a dotted relationship.field filter path resolves hop by hop and additionally requires its prefix to be declared in the dataset's include (WIDGET_FILTER_FIELD_NOT_INCLUDED, :1040-1053) — so the section says "the object's own fields, or a dotted path whose prefix is in include" rather than the flatter "the object's own fields".

The card's query-layer readings (ObjectQLStrategy.resolveFieldName, planCrossObject, combineFilters) were not re-derived here and are not cited in the doc. The query layer appears only as the layering caveat below.

Why the layering caveat is there

The card asked for it and triage required it: the "cannot group by" rule holds at the authoring layer, enforced by widget-dimension-unknown; at the raw analytics-query layer an object's own field may be used as a dimension without the dataset declaring it. The section therefore closes by scoping itself to the authorable surface explicitly, so it cannot be read as a claim about the query API.

Scope

Gates — all pinned to head 940152c1c

Derived with node scripts/pm/dispatch-gates.mjs --commands content/docs/ui/dashboards.mdx → 38 commands. All 38 run, all exit 0. Highlights: check:doc-anchors 0 (validates the three new links, including the cross-page validating-metadata#2-dangling-widget-bindings anchor), check:docs-single-h1 0, check:docs-section-name 0, check:doc-authoring 0, check:docs-transcript-drift 0, check:nul-bytes 0, pnpm --filter @objectstack/spec run check:docs 0, check:skill-examples 0.

Three gates first returned exit 3 PREREQUISITE NOT MET (@objectstack/lint unbuilt) and check:skill-examples exit 1 for an unbuilt @objectstack/client-react — none of those was a finding; after pnpm --filter '@objectstack/lint...' --filter '@objectstack/formula...' --filter '@objectstack/spec...' build and --filter '@objectstack/client-react...' build (both through scripts/pm/os-verify-lock.sh, VERDICT command-exit 0), all four re-ran to 0.

Repo-wide scans (pnpm lint and the rest of the lint workflow) are left to CI.


Generated by Claude Code

`## Global Filters` on the dashboards page explained `name`, date defaults and
`filterBindings`, but never said where a filter's `field` is looked up. The two
halves of the answer were written on the validation reference page in adjacent
paragraphs (`content/docs/deployment/validating-metadata.mdx:44-58`) and their
asymmetry was never named: dimensions resolve against the dataset, filter fields
against the dataset's object, so the same field can be filterable and not
group-by-able on one dataset.

Adds one section to the page authors actually read when writing `globalFilters`,
stating both resolution targets side by side, the two error-severity lint rules
that enforce them, the `filterBindings: { name: false }` opt-out, and a caveat
scoping the statement to the authorable surface.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vbw3RPgdtqesx4azk9SbW8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants