Skip to content

No app-declared action renders anywhere in the Console — six actions, four locations, zero buttons, all gates green #14145

Description

@os-warren

Found by booting a real ObjectStack application (objectstack-ai/duly) against published @objectstack/* 17.2.0 and driving the Console in Chromium. Filed here rather than in the app because nothing in the app can fix it.

The claim

An action declared in defineStack({ actions }) does not render in the Console at any location. Measured across six actions and four locations, with objectstack validate / build green and the actions registered under the keys executeAction dispatches on.

Location declared Surface Renders
list_toolbar — object-bound type: 'script' action object list toolbar ❌ New · Import · Edit inline · Filter · Group · Sort only
list_item grid row ⋯ menu ❌ Edit · Delete only
record_header record detail header ❌ Edit + ⋯ only
record_more record detail ⋯ overflow ❌ Share · Delete only
bulkActionDefs on the view (not an action) selection toolbar renders and works end to end

All four are members of ACTION_LOCATIONS in @objectstack/spec 17.2.0. The visible predicates match the records under test. Zero console errors, zero page errors, zero 4xx on every screen.

The last row is the control: a declarative bulk write on the view renders, executes, and persists. So the Console is not broken — it does not see actions metadata.

Likely root cause, measured separately

While investigating an unrelated startup warning in the same app, a developer measured that meta.loadMany('action') returns an empty array, and meta.load('action', <name>) is undefined for actions that are demonstrably live — the REST route resolves the very same actions through ql.registry.getItem('action', name) and dispatches them fine.

So there appear to be two stores: the runtime registry, which has the actions and executes them, and the metadata store the Console reads, which does not. That is consistent with every row of the table above.

(That measurement is on this repo's issue #14123, which reports the startup audit symptom of the same split. This report is the user-visible half: the buttons.)

Why this is worth prioritising

declared ≠ enforced is normally a silent-wrong-answer problem. Here it is a silent missing-feature problem, and the failure mode is unusually bad for a metadata platform:

  • the author writes the action, the schema accepts it, validate passes, build passes;
  • the handler registers, and an integration test that dispatches through the engine passes;
  • the button does not exist, and nothing anywhere says so.

In the app that found this, the affected actions are one-click task completion — the interaction the product is designed around. It shipped with 35 passing tests and no button. The team only found out by opening a browser.

Reproduce

npx create-objectstack@latest scratch && cd scratch
# add an object-bound action:
#   { name: 'x_ping', objectName: '<obj>', type: 'script', target: 'x_ping',
#     locations: ['list_toolbar', 'list_item', 'record_header', 'record_more'],
#     label: 'Ping' }
# register a handler for it in defineStack({ onEnable })
pnpm validate && pnpm build && pnpm dev
# open /_console/, navigate to the object, look for "Ping" in: the list toolbar,
# a row's ⋯ menu, the record header, the record's ⋯ overflow. It is in none of them.

Suggested direction

Whatever the resolution, the gap between "an action is dispatchable" and "an action is reachable" should not be silent. Either the Console reads the same registry the dispatcher does, or validate refuses an action whose declared locations no surface will render — the second is cheaper and is the ADR-0049 shape.

Related from the same app: #14092 (no declarative row-level field write, which is why these were hand-written script actions), #14123 (the startup-audit half of the registry split).

Unassigned and untriaged, per the single-producer rule for domain:*.

Activity

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:enginepriority:p1High: required for production / M2

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions