Filed by the objectstack domain:spec seat (os-elon, session_016D9wdJR14KKCxz1WgdAzcw) — the downstream card pre-registered in objectstack#9566's ACCEPT (comment 5328433458). Duplicate-searched: objectui#5034 is the plugin-form navigateOnSuccess key (different key, different call sites, itself blocked on objectui#4989) — deliberately NOT this card.
Upstream contract (landed)
Blocked-by: objectstack-ai/objectstack#9566 · Blocked-by: objectstack-ai/objectstack#9474 — both satisfied: the spec half merged 2026-08-18T14:15Z as objectstack PR #9601 (squash 07e630e). The ruled shape (maintainer 「9566 同意」, recorded on objectstack#9566):
ActionSchema.onSuccess — closed strict object { navigate: string (route/URL template), openIn: 'self' | 'newTab' }, refine-scoped to action types api | script; materialized .default('self') so parse output always carries the resolved member (the console branch needs no fallback of its own).
- Interpolation scope for the
navigate template: ${param.*} + ${ctx.*} + ${result.*} (NEW — the server response).
- Defaults split by surface: schema-declared
onSuccess ⇒ 'self' (SPA route hop, popup-blocker immune); the shipped handler-return convention { redirectUrl } WITHOUT openIn keeps its 17.0.0 new-tab behavior — no silent flip; a handler may return openIn: 'self' explicitly.
- ⚠️ Spelling tripwire, pinned both ways in spec: the ruled enum value is
'newTab'; the shipped top-level openIn (type 'url', 17.0.0) spells 'new-tab'. Spec refuses the crossover spelling with an issue.input-keyed error in each direction — don't "harmonize" as a rider here.
Scope (from the pre-registration)
consoleServerAction.ts: SPA-navigation branch honoring schema onSuccess (and a handler-returned openIn: 'self') — route hop via the SPA router, not window.open/window.location.
executeAPI navigation handling for api-type actions.
interpolateTarget (or the console's interpolation impl) gains the result scope member.
Dispatch precondition (for the objectui seat)
objectui's @objectstack/spec pin must cover objectstack 07e630e (PR #9601's squash) — verify ancestor relation via REST compare before dispatch, not local merge-base.
On landing
File/trigger the objectstack follow-up: packages/spec/liveness/action.json's onSuccess.navigate / onSuccess.openIn entries amend planned → live, citing the console read sites (the amend-on-landing instruction is recorded in objectstack#9566's dev report).
Customer ref: steedos-labs/os-project-titanwind-ehr#1172 (clone-then-jump leaves the user on the old record).
Filed by the objectstack
domain:specseat (os-elon,session_016D9wdJR14KKCxz1WgdAzcw) — the downstream card pre-registered in objectstack#9566's ACCEPT (comment 5328433458). Duplicate-searched: objectui#5034 is the plugin-formnavigateOnSuccesskey (different key, different call sites, itself blocked on objectui#4989) — deliberately NOT this card.Upstream contract (landed)
Blocked-by: objectstack-ai/objectstack#9566·Blocked-by: objectstack-ai/objectstack#9474— both satisfied: the spec half merged 2026-08-18T14:15Z as objectstack PR #9601 (squash07e630e). The ruled shape (maintainer 「9566 同意」, recorded on objectstack#9566):ActionSchema.onSuccess— closed strict object{ navigate: string (route/URL template), openIn: 'self' | 'newTab' }, refine-scoped to action typesapi|script; materialized.default('self')so parse output always carries the resolved member (the console branch needs no fallback of its own).navigatetemplate:${param.*}+${ctx.*}+${result.*}(NEW — the server response).onSuccess⇒'self'(SPA route hop, popup-blocker immune); the shipped handler-return convention{ redirectUrl }WITHOUTopenInkeeps its 17.0.0 new-tab behavior — no silent flip; a handler may returnopenIn: 'self'explicitly.'newTab'; the shipped top-levelopenIn(type'url', 17.0.0) spells'new-tab'. Spec refuses the crossover spelling with anissue.input-keyed error in each direction — don't "harmonize" as a rider here.Scope (from the pre-registration)
consoleServerAction.ts: SPA-navigation branch honoring schemaonSuccess(and a handler-returnedopenIn: 'self') — route hop via the SPA router, notwindow.open/window.location.executeAPInavigation handling forapi-type actions.interpolateTarget(or the console's interpolation impl) gains theresultscope member.Dispatch precondition (for the objectui seat)
objectui's
@objectstack/specpin must cover objectstack07e630e(PR #9601's squash) — verify ancestor relation via REST compare before dispatch, not local merge-base.On landing
File/trigger the objectstack follow-up:
packages/spec/liveness/action.json'sonSuccess.navigate/onSuccess.openInentries amendplanned→live, citing the console read sites (the amend-on-landing instruction is recorded in objectstack#9566's dev report).Customer ref: steedos-labs/os-project-titanwind-ehr#1172 (clone-then-jump leaves the user on the old record).