Skip to content

feat(lint): catch legacy pre-ADR-0021 dashboard analytics keys at author time (#1878/#1894)#3238

Merged
os-zhuang merged 2 commits into
mainfrom
claude/metadata-property-liveness-audit-sj47n1
Jul 18, 2026
Merged

feat(lint): catch legacy pre-ADR-0021 dashboard analytics keys at author time (#1878/#1894)#3238
os-zhuang merged 2 commits into
mainfrom
claude/metadata-property-liveness-audit-sj47n1

Conversation

@os-zhuang

@os-zhuang os-zhuang commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

Part of the metadata-liveness follow-through (#1878), serving the platform's core goal — AI writes metadata, humans review, and we catch AI mistakes at author time (in CI) rather than leaving silent no-ops for a human reviewer to miss.

An author (very often an AI) can still write the removed pre-ADR-0021 inline-analytics shape on a dashboard widget — categoryField / valueField / xAxisField / yAxisFields / aggregate / aggregation / rowField / columnField. Post-cutover the renderer routes dataset-bound widgets through DatasetWidget and never reads these keys. Two failure modes, two severities:

Case Behavior Rule Severity
Legacy key present and a data source exists (dataset/object/data) widget still renders; legacy key is ignored noise widget-legacy-analytics-shape warning (suppressible)
Legacy key is the only data wiring — no dataset, no object, no inline data widget has no data at all → renders nothing widget-legacy-analytics-unrenderable error (not suppressible)

Why this shape

  • Lives in validateWidgetBindings, which runs only in the CLI author path (objectstack compile / validate / doctor / lint) — the path AI writes to and CI gates. It is not in objectui or any Studio/runtime authoring path, so this does not touch Studio (which still authors the legacy shape via its own inspectors — a separate, deferred workstream).
  • The error only fails builds that are already broken (the widget renders nothing regardless), so it surfaces an existing defect rather than introducing a new gate. That's the highest-leverage AI-safety move in an AI-writes / human-reviews model: a silently-blank widget is exactly what a reviewer misses, so it should hard-fail in CI.
  • The framework DashboardWidgetSchema is already clean (declares none of these keys; examples are 100% dataset-shaped), so nothing regresses. A hard schema .strict() is a separate, breaking step blocked on migrating Studio's WidgetConfigPanel — deliberately out of scope here.

Testing

  • 7 cases total: warning (dataset-bound legacy key, object-bound legacy pivot, clean widget = no finding, suppression) + error (unrenderable → error, object-bound → warning not error, error-not-suppressible).
  • Full validate-widget-bindings suite green (40 passed).

🤖 Generated with Claude Code

https://claude.ai/code/session_01LddW4NaQBdf5FTEnBPpnUJ

#1894)

An author — very often an AI — can still write the removed inline-analytics
shape (categoryField/valueField/xAxisField/yAxisFields/aggregate/aggregation/
rowField/columnField) on a dashboard widget. Post-ADR-0021 the renderer routes
dataset-bound widgets through DatasetWidget and never reads these keys, so
authoring one is a silent no-op — exactly the "AI writes a dead property"
failure the liveness audit targets, but on the authoring side.

Add a `widget-legacy-analytics-shape` advisory rule to validateWidgetBindings
(already wired into `objectstack compile`): when a widget carries any legacy
key, emit a warning steering the author to `dataset` + `dimensions` + `values`,
with the fix spelled out. Fires whether or not a dataset is also present (the
keys are dead either way) and closes the gap where a dataset-less legacy
widget was skipped silently. Warning-only, per-widget suppressible via
`suppressWarnings`; never fails the build.

Tests: 4 new cases (dataset-bound legacy key, dataset-less legacy pivot,
clean dataset widget, suppression); full validate-widget-bindings suite green
(37 passed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LddW4NaQBdf5FTEnBPpnUJ
@vercel

vercel Bot commented Jul 18, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
spec Canceled Canceled Jul 18, 2026 5:04pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

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

  • content/docs/permissions/authorization.mdx (via @objectstack/lint)

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.

…data source (#1878/#1894)

Escalation of the legacy-analytics-shape rule for the case that is an outright
bug rather than deprecated-but-working: a widget that uses the removed
pre-ADR-0021 inline keys (categoryField/rowField/valueField/…) as its ONLY
data wiring — no `dataset`, no `object`, no inline `data`. The renderer reads
only the dataset path, so such a widget has no data at all and renders
nothing.

New rule `widget-legacy-analytics-unrenderable` (severity error) fires for
exactly that case; the existing `widget-legacy-analytics-shape` stays a
suppressible warning when a data source IS present (the widget still renders,
the legacy keys are just ignored noise).

Rationale (AI-writes / human-reviews): a silently-blank widget is precisely
what a human reviewer misses. Because validateWidgetBindings runs only in the
CLI author path (`objectstack compile`/`validate`/`doctor`/`lint`, never in
Studio's runtime authoring), this fails the AI/code build in CI without
touching Studio. It only fails builds that are already broken (the widget
renders nothing regardless), so it surfaces an existing defect rather than
introducing a new gate. Errors are not suppressible.

Framework examples/fixtures carry no legacy-key dashboards, so nothing
regresses. Tests: 3 new cases (unrenderable→error, object-bound→warning,
error-not-suppressible); full suite 40 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LddW4NaQBdf5FTEnBPpnUJ
@github-actions github-actions Bot added size/m and removed size/s labels Jul 18, 2026
@os-zhuang os-zhuang changed the title feat(lint): warn on legacy pre-ADR-0021 dashboard analytics keys (#1878/#1894) feat(lint): catch legacy pre-ADR-0021 dashboard analytics keys at author time (#1878/#1894) Jul 18, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review July 18, 2026 20:43
@os-zhuang
os-zhuang merged commit 78b74b4 into main Jul 18, 2026
21 of 22 checks passed
@os-zhuang
os-zhuang deleted the claude/metadata-property-liveness-audit-sj47n1 branch July 18, 2026 20:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants