|
| 1 | +--- |
| 2 | +'@objectstack/lint': patch |
| 3 | +--- |
| 4 | + |
| 5 | +lint: `dashboard-filter-field-unknown` resolves dotted dashboard-filter fields on the object graph, and answers system columns per object |
| 6 | + |
| 7 | +A dashboard-level filter (`dateRange`, or a `globalFilters[]` entry) is ANDed into |
| 8 | +**every** widget's analytics query, so its effective field — after any |
| 9 | +`filterBindings` re-target — has to resolve on each bound widget's dataset object. |
| 10 | +The rule that enforces that shipped with two holes, and this closes both by |
| 11 | +migrating the check onto the shared `resolveFieldPath` / `joinablePrefixes` seam |
| 12 | +the widget's own `filter` keys already use one position over. |
| 13 | + |
| 14 | +- **Dotted paths are no longer skipped.** The branch carried |
| 15 | + `if (field.includes('.')) continue;`, accurate when nothing in the package could |
| 16 | + walk relationship hops and false since the object-graph seam landed. A filter |
| 17 | + re-targeted to `account.signed_at` was unjudged whether or not `account` existed, |
| 18 | + whether or not `signed_at` existed on it, and whether or not `account` was |
| 19 | + declared in the dataset's `include`. It is now walked hop by hop, and a miss |
| 20 | + names **which** hop failed. |
| 21 | +- **System columns are resolved per object, not through the flat union.** The old |
| 22 | + test was `objectFields.has(field) || SYSTEM_FIELDS.has(field)`, which answers |
| 23 | + "could this be a system column *anywhere*". On an `ownership: 'none'` object the |
| 24 | + platform injects no `owner_id`, and on `systemFields: { audit: false }` no |
| 25 | + `created_at` — both were answered as resolvable and are now reported. |
| 26 | + |
| 27 | +New error id **`dashboard-filter-field-not-included`**: the effective field |
| 28 | +resolves, but its relationship prefix is not declared in the bound dataset's |
| 29 | +`include`, so ADR-0021 compiles no join and the column is out of the broadcast |
| 30 | +query's reach. It mirrors `widget-filter-field-not-included` one level down, and is |
| 31 | +its own id because the fix is a different edit (declare the join, versus point the |
| 32 | +filter at something real). |
| 33 | + |
| 34 | +This **narrows the accept set of a shipped gating rule**. Both new answers are |
| 35 | +error-tier, so like the rule's other errors they fail `os validate` / `os build` |
| 36 | +and the runtime publish gate for `dashboard` writes. Measured over the shipped |
| 37 | +dashboard corpus — the three example apps plus the platform's own |
| 38 | +`system_overview` — the change is 0 findings before and 0 after; the |
| 39 | +`dashboard-filter-field-unprovisioned` warning is unchanged and now travels with |
| 40 | +the verdict, so it answers a dotted path landing on an ADR-0015 `external` object |
| 41 | +too. |
0 commit comments