Skip to content

ActionSchema.onSuccess and a handler-returned redirectUrl are both reachable on one type: 'script' action, and the spec rules neither — renderer-side precedence is deciding it today #11519

Description

@os-zhuang

Filed from the objectui domain:ui execution seat, as the ruled durable half of a question returned by objectui#5221 (PR objectstack-ai/objectui#5933). Filed unassigned.

The gap

Two independent channels can name a post-success destination for the same action:

  1. DeclaredActionSchema.onSuccess ({ navigate, openIn }, openIn defaulting to 'self'), validated by this repo's refine, visible in metadata.
  2. Returned — a handler's { redirectUrl } at runtime, whose own default keeps a new tab.

The spec rules each surface's default in isolation. It says nothing about precedence when one action carries both, and both are reachable on a type: 'script' action.

Doing both fires two navigations, the second racing a page already unloading — so a renderer cannot decline to pick. objectui#5933 therefore picked one to ship a coherent PR: the declared onSuccess block wins, the wrapper skips its redirectUrl hop and only tidies the pre-opened tab, marked at the line that does it.

Why that interim choice is not the fix

The alternative — handler-returned redirectUrl wins — was rejected there because it makes an author's declared hop silently do nothing whenever the handler happens to return a redirectUrl: a declaration that type-checks, passes spec validation, appears in metadata, and never fires, with no diagnostic. That is the declared != enforced shape the platform rejects, and it is especially hard to notice from an AI-authored metadata app, which cannot see a handler's return value at authoring time.

But the chosen order is still renderer-side precedence over a case the contract does not mention. Nothing stops a second renderer from reading the same two inputs and picking the other order, and nothing would say which is wrong. Precedence that lives only in one renderer's implementation is precedence that drifts.

Proposed shape

Make an action carrying both a declared onSuccess block and a handler that can return redirectUrl an authoring-time refusal — one destination declared in one place, refused loudly at parse rather than resolved silently at render.

Two things to settle before implementing, neither of which objectui can answer:

  • Whether "can return redirectUrl" is even statically knowable for a type: 'script' action at parse time. If it is not, the refusal may have to be a runtime diagnostic on the doubled case rather than a parse-time refine — which is a weaker but still legible answer, and better than silent precedence.
  • Whether the durable answer is refusal at all, or an explicit precedence field. Refusal is the stronger guard; an explicit field is the smaller change. This card does not decide it.

Reachability, measured — this is not urgent

  • No metadata in the objectui repo carries both.
  • The reachable producers of redirectUrl are cloud SSO handoffs, which would not also declare a static navigate template.

So this is a contract hole worth closing deliberately, not a live defect. It is filed rather than expanded into objectui#5933's scope for exactly that reason.

References

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions