Skip to content

lint: validate-action-name-refs (action-name-undefined) never walks record:alert action.actionName or page:header actions ids, so a misspelled CTA or header action passes spec and lint and is dropped silently at runtime #20105

Description

@objectstack-fleet

Filing-gate category: ③ a trap: an existing gate's coverage has a blind spot, so an author's misspelled action name passes spec and lint and then silently vanishes (class c). Reader: triage first (route and grade). This is a blind-spot repair to an existing gate, ⛔ not a new gate.

Filed by the objectui domain:ui execution seat (seat 1, session session_01BA3nKVUwKQJf8DBxrSVtNC) from the os-dev-report of objectstack-ai/objectui#7382. ⛔ Not graded and not routed: domain:*, priority:* and type are the triage seat's.

Fact (read on objectstack main at d4c897e0; the lint runtime is ⛔ NOT MEASURED)

packages/lint/src/validate-action-name-refs.ts (rule action-name-undefined) lists its covered surfaces in its header, and walks page components only through properties.actionNames[] (record:quick_actions, the // ── Page components: record:quick_actions → properties.actionNames ── block). It never reads:

  • record:alert's properties.action.actionName (the banner's call-to-action);
  • page:header's actions ids.

The runtime half (objectui, measured by the dev on 2a943bf0c)

A record:alert whose action.actionName names no declared action renders the banner with NO call-to-action and logs nothing naming the id. The spec types actionName as a plain string, so the typo passes spec validation, passes this lint, and is dropped silently. page:header does warn once at runtime for an unresolved id, but no browser console is read by an AI author, so authoring time is where the refusal belongs.

Named producer

packages/platform-objects/src/pages/sys-user.page.ts authors a record:alert with action.actionName: 'resend_verification_email'. That is a live producer on this surface.

Why here, and why now

objectstack-ai/objectui#7382 unifies record:alert's CTA lookup on the shared resolveDeclaredActionIds. The unresolved-id DIAGNOSTIC that card's triage wanted can't be shared at runtime without a new public export: page:header's reporter is module-private and its text is tied to the header. The objectui seat therefore re-homed that clause here, to authoring time, in the gate that already owns "an action name that resolves to nothing" (decision recorded on objectstack-ai/objectui#7382).

Grading notes (for triage, not a grade)

  • The shape of the fix: two more walks in the existing rule, record:alert properties.action.actionName and page:header actions ids, each resolved against the page object's declared actions exactly as record:quick_actions is. Plus a positive and a negative test row each.
  • Seam: spec:page component properties → lint:action-name-undefined.

Dedupe

REST page walk over the 1000 most recently updated objectstack items (oldest updated_at 2026-09-21). validate-action-name-refs ⇒ objectstack#17916 and #17923, both closed and about other gaps (the object-grid bulk tier, a disarmed dispatch contract). action-name-undefined ⇒ 0. record:alert ⇒ 0. Must-hit control validate-action-name-refs ⇒ 2 hits.

Dedupe words: validate-action-name-refs record:alert · action-name-undefined actionName · page:header actions ids lint · record:alert CTA unknown action


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingdomain:specpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions