Skip to content

feat(lint): the #8116 unprovisioned-anchor warning reaches filter and page-binding surfaces (#8340) - #8406

Merged
qq9340100 merged 4 commits into
mainfrom
claude/issue-8340-filter-surface-unprovisioned-anchor
Aug 13, 2026
Merged

feat(lint): the #8116 unprovisioned-anchor warning reaches filter and page-binding surfaces (#8340)#8406
qq9340100 merged 4 commits into
mainfrom
claude/issue-8340-filter-surface-unprovisioned-anchor

Conversation

@qq9340100

Copy link
Copy Markdown
Collaborator

Fixes#8340

What

The #8116 unprovisioned-anchor warning could not reach the filter surfaces. Its two rules resolve fields per object; the filter-position and page-binding checks judge a name against the object-independent SYSTEM_FIELDS union, which by design answers "could this name be a system column anywhere" and therefore never flags a system name. So filter: [['owner_id', '=', '…']] on a view, widget, page or flow bound to an ADR-0015 external object linted clean while the runtime degraded exactly as #8116 describes: on SQLite, constant-false, HTTP 200, zero rows, no error.

Four rules now ask the provenance question on the path where the existence check stays silent. Per the card's assumption 2, the blanket union is not replaced anywhere — it keeps owning every pass/fail decision, and #8340 only adds a question about a name it already decided not to flag:

rule idsurfaceconsequence the message names
dashboard-filter-field-unprovisioneddashboard filter (dateRange / globalFilters[], after filterBindings) ANDed into a widget's analytics querywidget renders empty instead of crashing; suppressible per widget
page-field-unprovisionedpage + react component field bindings (shared checkFieldRefs core)QUERY positions: silent zero. display positions: blank column
react-chart-field-unprovisioned< ObjectChart aggregate>'s field / groupByone empty bucket / nothing aggregated
flow-template-field-unprovisioned{record.< anchor>} in a record-change flow on an external trigger objectin a guarded CRUD filter, the token erases the condition and the node refuses to run (framework#3810)

All four are warning, never gating — including in the two positions where the existence twin is an error. #8116's severity reasoning is unchanged: the existence question has a closed oracle (the field is absent or it is not), the provenance one does not — this pass knows the platform provisions no storage, not what the deployment's remote schema holds.

Shared, rather than four copies of one sentence: indexUnprovisionedAnchors, unprovisionedAnchorCause and unprovisionedAnchorHint in packages/lint/src/system-fields.ts, over #8116's unprovisionedInjectedColumnsFor. No new derivation — the spec predicate stays the single source (packages/spec untouched).

Per-surface false-positive analysis

The card warned each rule's tolerance for unresolvable names differs. Measured, all four could adopt the per-object derivation, and none needed a new object binding:

  • widget-bindings — the object comes from dataset.object; the rule already skips when its fields are unknown in this stack. The anchor lookup rides the same skip.
  • react-page-propsobjectName prop, already required by the existing checks.
  • page-field-bindings — the shared core already bails on a missing object name and a cross-package object. The anchor index is an optional sixth parameter, so out-of-repo callers of this exported core (cloud graph-lint, the AI authoring path) keep the pre-lint: view-filter / page-binding field checks resolve against the blanket SYSTEM_FIELDS union, so the #8116 unprovisioned-anchor warning cannot reach filter surfaces #8340 behaviour instead of silently gaining findings.
  • flow-template-paths — the trigger object off the start node, already resolved and already required (the rule skips the whole flow without it). Note the token reads the TRIGGER record, so the anchors are the trigger object's, not the CRUD node's target.

Two exclusions were kept everywhere: a dotted relationship path (engine-resolved, unjudgeable here) and an author-declared column of the same name, which is the author's real remote column (#7859) and never enters the set.

Tests

New named coverage per surface, each mutation-tested in both directions:

  • killing each emission turns that surface's warns… test red and leaves the is silent… tests green;
  • making the derivation over-reach (every injected column treated as unprovisioned) turns the is silent on the local twin / author DECLARES the column tests red — and, as a bonus, three pre-existing false-positive-floor tests in other suites.

pnpm --filter @objectstack/lint test — 72 files, 1996 passed, 4 skipped. Typecheck, eslint, check:cross-package-test-inputs, check:spec-parsed-alias, check:nul-bytes, check:changeset-gate-self-tests, check:objectui-changeset, check:query-options-erasure, check:type-check-coverage, check-changeset-no-major all green locally.

Notes for review

Generated by Claude Code


Generated by Claude Code

@vercel

vercelBot commented Aug 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 13, 2026 12:14pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/lint.

3 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/automation/hook-bodies.mdx(via @objectstack/lint)
  • content/docs/deployment/validating-metadata.mdx(via packages/lint)
  • content/docs/permissions/authorization.mdx(via @objectstack/lint)

1 release-owned page(s) also reference the affected code. These are read-only:

  • content/docs/releases/v17.mdx(via @objectstack/lint)

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

…r's return (#8340)
The two new-suite helpers were annotated `{ rule: string }[]`, so every
assertion past `.rule` was a TS2339 the package's own `typecheck` cannot see
(its tsconfig excludes `**/*.test.ts`) but check:type-check-debt counts: 12 raw
errors on top of @objectstack/lint's frozen TEST_DEBT of 20.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/lteststooling

Projects

None yet

2 participants

@qq9340100@claude