Skip to content

feat(lint): flag dead action/route references in dashboard header actions (#3367)#3383

Merged
os-zhuang merged 3 commits into
mainfrom
claude/dead-dashboard-header-refs-7zo1ut
Jul 21, 2026
Merged

feat(lint): flag dead action/route references in dashboard header actions (#3367)#3383
os-zhuang merged 3 commits into
mainfrom
claude/dead-dashboard-header-refs-7zo1ut

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

What

Closes #3367. Dashboard header actions[] and widget actionUrl can reference a script/modal action or a url route that exists nowhere. Nothing in os validate / os build flags them, so they ship as buttons that render and silently do nothing when clicked — a false affordance. This is ADR-0049's "declared ≠ enforced" gate applied to references rather than to properties.

Nothing in the protocol schema can express this: actionUrl is a free string, so { actionType: 'script', actionUrl: 'export_dashboard_pdf' } parses and ships even when no such action is defined.

Changes

  • @objectstack/lint — new pure validateDashboardActionRefs(stack) => Finding[] rule (validate-dashboard-action-refs.ts, exported from index.ts). Walks every dashboard header.actions[] and widget actionUrl.
  • @objectstack/cli — wired into both os validate and os build (compile), errors gate / warnings advisory, mirroring the existing validateWidgetBindings step.
  • docsvalidating-metadata.mdx: new "Dead action/route references" section, gate-table row, and step-output line.
  • changesetminor for the fixed group.

Resolution (mirrors the objectui runtime dispatch so lint flags exactly what would fail to resolve)

actionType resolves when… severity if dangling
script actionUrl names a defined action (stack.actions or an object's actions) error
modal a defined action, or the runtime <verb>_<object> convention (create_/new_/add_/edit_/update_ + a real object), or a bare object name error
url a relative in-app path whose objects/reports/dashboards/pages/views route exists in the stack warning
flow / api — (out of scope: engine/opaque targets)

External URLs (http(s)://, //), interpolated targets (${…}), and opaque routes are skipped to keep false positives near zero — the same conservative posture as the sibling lint-view-refs and validate-capability-references rules.

Severity rationale follows the issue's acceptance criteria: a dead script/modal target fails validation (it fails open at runtime as a dead button); an unresolved url route is at least warned (route resolution is app-context-dependent and a path may be served by another installed package or a host/console route).

Acceptance criteria

  • ✅ A dashboard action referencing an undefined script/modal action fails validation, naming the dashboard, button label, and unresolved target.
  • ✅ A url action pointing at a non-existent in-app route is warned.
  • ✅ Valid references (defined action / real route / <verb>_<object> against a real object) pass.
  • ✅ Fixture coverage for defined vs dangling targets (including the exact Flag dead action/route references in dashboard header actions (ADR-0049 for references) #3367 repro).

Tests

🤖 Generated with Claude Code

https://claude.ai/code/session_018KSiJuXDAi78CQD3Lv2TNJ


Generated by Claude Code

…ions

Dashboard header `actions[]` and widget `actionUrl` can name a script/modal
action or a url route that does not exist. Nothing in `os validate` / `os build`
flags them, so they ship as buttons that render and silently do nothing when
clicked — a false affordance. This applies ADR-0049's "declared ≠ enforced" gate
to references rather than properties (#3367).

New `validateDashboardActionRefs` rule in @objectstack/lint, wired into
`os validate` and `os build`:

- actionType 'script' | 'modal' → ERROR unless `actionUrl` resolves to a defined
  action (stack.actions or an object's actions). 'modal' also resolves via the
  runtime `<verb>_<object>` convention (create_/new_/add_/edit_/update_ + a real
  object) and bare object names, mirroring the objectui modalHandler.
- actionType 'url' → WARNING when a relative in-app path names an
  objects/reports/dashboards/pages/views route absent from the stack. External,
  interpolated (${…}), and opaque routes are skipped to keep false positives near
  zero — the same conservative posture as lint-view-refs / capability-references.

Covers dashboard `header.actions[]` and widget `actionUrl`. Fixture coverage for
defined vs dangling script/modal targets, the modal convention, and resolved vs
unresolved url routes, plus the #3367 repro. Docs + changeset included.

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

vercel Bot commented Jul 21, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 21, 2026 2:52pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/l labels Jul 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/cli, @objectstack/lint.

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

  • content/docs/ai/skills-reference.mdx (via packages/cli)
  • content/docs/api/client-sdk.mdx (via @objectstack/cli)
  • content/docs/api/data-flow.mdx (via @objectstack/cli)
  • content/docs/api/environment-routing.mdx (via @objectstack/cli)
  • content/docs/api/error-catalog.mdx (via @objectstack/cli)
  • content/docs/automation/hook-bodies.mdx (via packages/cli)
  • content/docs/deployment/backup-restore.mdx (via @objectstack/cli)
  • content/docs/deployment/self-hosting.mdx (via @objectstack/cli)
  • content/docs/getting-started/cli.mdx (via @objectstack/cli)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/cli)
  • content/docs/kernel/runtime-services/data-service.mdx (via packages/cli)
  • content/docs/kernel/runtime-services/index.mdx (via packages/cli)
  • content/docs/permissions/authentication.mdx (via @objectstack/cli)
  • content/docs/permissions/authorization.mdx (via @objectstack/lint)
  • content/docs/plugins/packages.mdx (via @objectstack/cli)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/cli)
  • content/docs/protocol/kernel/realtime-protocol.mdx (via @objectstack/cli)
  • content/docs/releases/implementation-status.mdx (via @objectstack/cli)
  • content/docs/releases/v16.mdx (via @objectstack/cli)

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.

The `os build` sample output in cli.mdx enumerates each compile step; the new
ADR-0049 dashboard action-reference check landed between the widget-binding and
SDUI-styling steps, so list it there too. Addresses the docs-drift advisory on
#3383. Docs-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018KSiJuXDAi78CQD3Lv2TNJ
@os-zhuang
os-zhuang marked this pull request as ready for review July 21, 2026 14:33
…-header-refs-7zo1ut

# Conflicts:
#	content/docs/getting-started/validating-metadata.mdx
#	packages/cli/src/commands/validate.ts
@os-zhuang
os-zhuang merged commit db160dd into main Jul 21, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the claude/dead-dashboard-header-refs-7zo1ut branch July 21, 2026 14:54
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/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Flag dead action/route references in dashboard header actions (ADR-0049 for references)

2 participants