Repository navigation
decision: a flow action that runs straight through should show the flow's own successMessage, as the paused path now does? #12274
Description
Filing gate ②: a decision only the maintainer can make. It is a product reading of a declared field on one console path, and the contract review of objectui#12246 escalated it to the dispatching seat for a card or the decision box (6125257205, ③).
- Who acts after the ruling: the
domain:uiseat that dispatches it (@object-ui/app-shell,utils/flowResponse.tsand the action runner's success toast). - Raised by:
domain:uiseat 2 (seat post objectui#9771),session_01G5TSaEwbEQsKMjhzTB4rEd, from objectui#12234's dev report (6124232882, out-of-scope finding 2). - Dedupe: REST issue list of objectui, all states, updated since 2026-08-01 (710 issues), matched for
successMessage+straight-through|done arm|judgeFlowLaunch|flow…success: 4 hits. None asks this. The nearest is objectui#12234 (closed, the paused path).
维护者速读
一个按钮动作启动流程时,有两种走法。流程中途停下来让用户填表,最后弹的提示是「动作自己的提示 → 流程自己的提示 → 通用句」,这是 objectui#12246 刚定的顺序。流程一口气跑完,弹的是「动作自己的提示,或通用默认句」,流程自己声明的 successMessage 被丢掉了。结果同一个流程,作者写的完成语有时显示、有时不显示。选项:A 两条路用同一个顺序(推荐);B 保持现状。选哪个?
os-decision-facets
- ① 项目长远合理性:A 收窄特例——两条路径一个顺序;spec 写明
successMessage「每次终止运行都携带」,A 让已声明的字段在两条路上都兑现。 - ② 实际业务拉动:今天无人报告;未实测有哪个流程同时声明了
successMessage、又由直通动作启动。零拉动但改动小。 - ③ 防 AI 犯错:AI 写了流程的
successMessage,在一条路上看得到、另一条路上静默丢失,这是静默容忍;A 消除这种静默丢失。 - ④ 创业阶段不扩散:A 不新增任何键或界面,只读已声明的字段;B 让一个已发布字段在一条路径上不兑现。
Prior rulings read: FlowSchema.successMessage every terminal run → 1 hit (objectstack packages/spec/src/automation/flow.zod.ts:1048-1063, #9414's triage, which rejected reading it as screen-flow-only); ADR none; thread: objectui#12234.
One-line problem
When a flow-backed action runs its flow straight through, with no screen, the console never shows the flow's own successMessage. It shows the action's message or a generic one. The paused path now shows action, then flow, then the generic sentence.
Measured (objectui main 7af0ab37; objectstack spec as checked out)
packages/app-shell/src/utils/flowResponse.ts:judgeFlowLaunchreads the servedsuccessMessageinto thedoneoutcome (:337-339). Thedonearm of the launch handler then returns{ success: true, data, reload }(:417-419), which drops it. The action runner toasts the action's ownsuccessMessageif declared, otherwise its default.- The paused path:
FlowRunner's terminal toast readsinvokingActionMessage(state) || outcome.successMessage || flowRunner.completed(objectui#12246,main360cf32). - The spec,
FlowSchema.successMessage: "carried on AutomationResult for every terminal run (not only screen flows) … treat the screen-flow toast as one consumer, not the whole contract".
Options
| what | customer-visible result | work | |
|---|---|---|---|
| A | the straight-through path uses the paused path's order: the action's message, then the flow's successMessage, then the default |
an author's flow completion text shows whichever way the run goes | domain:ui · 1 PR · precedent objectui#12246 (+636/−5, mostly tests) · patch if no published type moves, otherwise a declared widening and a contract-tier review |
| B | leave as is | the flow's text shows only when the run paused first | none |
In business terms. A gives one rule: what the author wrote is what the user reads. B keeps an outcome that depends on whether the flow happened to ask for input.
Recommendation
A. It honours a declared, documented field on the path that drops it, with the precedence already ruled for the paused path, and it adds no surface. Fallback: B. Confidence gap: who declares a flow successMessage behind a straight-through action today was not measured (HotCRM's flow sources were not read for this). The action runner's exact default text on that path was read from the review, not re-rendered.
Self-check: judged on ① alone, A. Do ② ③ ④ flip it? No.
After the ruling
- A: this seat files one
domain:uicard. Its acceptance: on a straight-through launch, the success toast reads the action's message, then the flow'ssuccessMessage, then the default. It is pinned on a real render beside objectui#12246's paused-path pins, andrefusedand failed runs still show no success toast. - B: this card closes
not_planned, citing the ruling.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 12, 2026
Triage: decision-box entry check. Not a product fork: it honours a declared field with an already-ruled precedence.
bug·priority:p3·domain:ui·area:workflow, intopm:queueTriage seat (seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-12T21:57Z. ⛔ Not a claim, ⛔ not a dispatch.FlowSchema.successMessageis declared for "every terminal run (not only screen flows)". The straight-through path drops it, so this is a declared contract the renderer does not honour (class b). The precedence (action, then flow, then default) is already set for the paused path (fix(app-shell): a flow action whose run pauses closes with the action's own successMessage (objectui#12234) #12246). Nothing here is a fork. B would keep a known contract break.successMessage, then the default, through the paused path's one rule. ⛔ Not a second copy.needs-user-decisionis removed.objectstack-fleet commentedon Oct 12, 2026
Claim: PM loop round 3 (triage
6133357796: the card's A; a straight-through flow launch's success toast reads the action's message, then the flow'ssuccessMessage, then the default, through the paused path's one rule, ⛔ not a second copy)Session:
session_01CsyMRsFJBKNEMa4oPY1b5zAccount:
zhuangjianguo(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-12274-flow-done-success-messageWorktree:
objectui-issue-12274Domain:
domain:uiSeat:
domain:ui#1File surface: the straight-through flow launch and the one precedence rule, read on objectui
main1fb1cedat 2026-10-12T22:57Z (stop on breach; explain in the report):packages/app-shell/src/utils/flowResponse.ts.judgeFlowLaunchreads the servedsuccessMessageinto thedoneoutcome, and the launch handler'scase 'done'returns{ success: true, data, reload }without it.packages/app-shell/src/views/FlowRunner.tsx(invokingActionMessage(state) || outcome.successMessage || flowRunner.completed, from objectui#12246). It is shared or extracted, ⛔ never re-typed.@object-ui/core'sActionRunnersuccess toast (outcomeMessages, thensuccessMessage, then the default).@object-ui/types'sActionResultcarries no message member today..changeset/12274-flow-done-success-message.md.Container & model:
M,mode:subagent,model: default tier — dispatch-gates --tier --repo objectstack-ai/objectui: "no path-derived mandate"Clause-②: yes
Clause-② reason: one route carries the flow's message to the runner's toast through a new member of
@object-ui/types's publishedActionResult, which widens the published surface; the other route has the console toast through the shared rule with no type change. The dev has not chosen yet, so the claim declaresyes, and an at-tier contract review runs before the queue whichever route lands.Responsibility:
objectui's console flow launch (@object-ui/app-shell flowResponse), whose straight-through done arm drops the served successMessage | the paused path already honours it (objectui#12246), and the spec declares FlowSchema.successMessage for every terminal run | every user who triggers a flow-backed action whose flow declares a successMessage and runs without a screen; no reach measured today (the card's facet ②)Thread-read: 6133357796
Serial constraints cleared: read at 2026-10-12T22:57Z on objectui
main1fb1ced. No open PR touchesflowResponse.ts,FlowRunner.tsx,ActionRunner.tsorui-action.ts(open: objectui#12253, ci(spec-main-shape-gate): drop the merge_group trigger now the context is out of the required set (objectui#12252) #12262, ci(type-check): the affected speed builds the packages the repo-root setup program imports (objectui#12272) #12277). Dispatched in the same wave as objectui#12273, whose surface (AppHeader.tsxand the language packs) is disjoint.Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
os-dev-report
{
"issue": 12274,
"status": "done",
"branch": "claude/issue-12274-flow-done-success-message",
"pr": "#12281",
"head": "ea9415a89de9e75f79afe068a0da9562fe57a870",
"session": "session_01CsyMRsFJBKNEMa4oPY1b5z",
"premise_still_valid": true,
"summary": "A straight-through flow launch now closes with the flow's own successMessage when the invoking action declares none. Before, judgeFlowLaunch's done arm handed the ActionRunner a plain success, and the runner's toast has no rung for the flow's copy. The paused path's author-copy precedence (the action's successMessage, then the flow's) is now one shared function, flowSuccessCopy in utils/flowResponse.ts. FlowRunner's terminal toast and judgeFlowLaunch's done arm both call it; FlowRunner's private invokingActionMessage is deleted, not copied. Route (b), with no published surface. When the action's copy wins, or neither copy exists, the done result is byte-identical to before, so the runner speaks the action's copy (outcomeMessages and ${result.} filling intact) or its default. When the flow's copy wins, the result goes silent and the judgement carries successToast, which launchConsoleFlow (utils/flowLaunch.ts, shared by both hosts) speaks once through sonner, as FlowRunner does. Refused and failed runs never reach the done arm and show no success toast. Mechanism assumptions 1, 3 and 4 were confirmed. Assumption 2 is implemented for the author's copy; each end keeps its own default sentence (see open_questions).",
"tests": "Code at 48f2b79; ea9415a adds only one guide line. New pins beside objectui#12246's: useConsoleActionRuntime.flowDoneSuccessMessage-12274 (6 tests, real runtime, action door and trigger door) and RecordDetailView.flowDoneSuccessMessage-12274 (5 tests, real record page). Each asserts the full toast.success text list for (i) the action's message wins over the flow's, (ii) only the flow's copy, shown once, (iii) neither, so the runner default, (iv) refused and failed, so no success toast. flowResponse.test.ts gains 9 unit tests. Narrowed regression run in two halves under the lock, at 48f2b79: 174 files, every test file under packages/app-shell/src and apps/console/src whose name matches FlowRunner, useConsoleActionRuntime, flowResponse, flowLaunch, RecordDetailView, flow-envelope, FlowRunsPage, FlowRefusal, DeclaredActionsBar, PageView., ScreenView or consoleServerAction, or that names one of those modules. Readings: 'Test Files 89 passed (89)' / 'Tests 779 passed (779)' and 'Test Files 85 passed (85)' / 'Tests 631 passed (631)', VERDICT command-exit 0 both. At ea9415a, the 37 scripts/tests files that read content/docs: 'Test Files 37 passed (37)'. Ablation 1 at 48f2b79, via ablation-replace.mjs: the done arm's flow branch was replaced by a plain return; anchor 1 to 0, blob 1e520837 to 78058778, restored to the HEAD blob with git diff HEAD empty. The predicted direction held: 5 failed, 49 passed. Red: pin (ii) in both hosts, the trigger-door pin and two done-arm unit tests, e.g. "expected [ 'Action completed successfully' ] to deeply equal [ 'Escalation recorded' ]". Ablation 2: the successToast line in flowLaunch.ts was deleted; anchor 1 to 0, blob 8e8edd6b to 7215ca22, restored to HEAD. 3 failed, 51 passed; only the three host pins went red, "expected [] to deeply equal [ 'Escalation recorded' ]". No dist was involved: the subjects are imported by relative path. A first run of ablation 1 at 838ea1a was also red, 5 of 54, but its host pins failed on the result shape before reaching the toast. The assertions were reordered (48f2b79) and the leg re-run; that re-run is the reading that counts.",
"mcp_calls": "0",
"api_writes": "3 REST writes in 2 fleet-write relay dispatches, each sent as POST /repos/objectstack-ai/objectstack/dispatches. (1) pr_create: POST /repos/objectstack-ai/objectui/pulls (draft), then POST /repos//issues/12281/assignees (zhuangjianguo). Read back 12188 of 12188 bytes identical, draft true, assignee zhuangjianguo. (2) This os-dev-report comment: POST /repos//issues/12274/comments. Also 3 git pushes (not REST): the empty-branch probe, 1fb1ced..838ea1a and 838ea1a..ea9415a, none forced. No label write: nothing published moved, so needs:contract-review is not hung. No PR body PATCH.",
"open_questions": [
{
"question": "Should a straight-through run with no copy at all (neither the action nor the flow declares a successMessage) also close on the flow-completed sentence ('Flow "LABEL" completed'), making the two ends' default identical? Mechanism assumption 2 called the whole paused expression, default included, the one rule. This PR shares the author-copy precedence and keeps each end's own default, reading the card's own words for this path: 'the action runner toasts the action's own successMessage if declared, otherwise its default'.",
"options": [
"A keep each end's default (implemented): the straight-through toast reads 'Action completed successfully', the paused one the flow-completed sentence. No further work.",
"B unify the default to the flow-completed sentence: move FlowRunner's label-localization helpers (activeFlowsBundle, displayFlowLabel) to a shared module, give both hosts' launch path the i18n instance, and change the most common straight-through flow toast. About one more PR across flowLaunch.ts and both hosts, with pins to update."
],
"recommendation": "A. Business need: no one reported the default text, and the card is about the flow's declared copy being dropped, which this PR fixes. Long-term soundness: the declared field is honoured on both ends through one function, and the default is chrome, not contract. Guarding against AI errors: neither option adds a key, and an AI that declares a flow successMessage now sees it on both paths. Start-up focus: B grows the change for an undeclared preference. B stays open if the maintainer wants the two defaults identical."
}
],
"out_of_scope_findings": [
"carrier: no carrier · noted, not filed. ${result.} filling still differs between the ends: a straight-through action copy is filled by the runner's rung, while a paused one is inserted as written (objectui#12246). The spec declares ${result.*} for type api and script only. The PR's Acceptance notes record it; this PR changes neither end.",
"carrier: no carrier · noted, not filed. The flow-copy toast is spoken through sonner directly, as FlowRunner's terminal toast is, so the runtime-only ActionDef.toast options (showOnSuccess, duration) do not apply to it. They do not apply on the paused end either, and the spec aliases an authored toast to successMessage. Recorded in the Acceptance notes."
],
"files_changed": [
".changeset/12274-flow-done-success-message.md",
"content/docs/guide/architecture-overview.md",
"packages/app-shell/src/hooks/tests/useConsoleActionRuntime.flowDoneSuccessMessage-12274.test.tsx",
"packages/app-shell/src/utils/tests/flowResponse.test.ts",
"packages/app-shell/src/utils/flowLaunch.ts",
"packages/app-shell/src/utils/flowResponse.ts",
"packages/app-shell/src/views/FlowRunner.tsx",
"packages/app-shell/src/views/RecordDetailView.flowDoneSuccessMessage-12274.test.tsx"
],
"deviations": [
"File surface: packages/app-shell/src/utils/flowLaunch.ts is added. It is the only caller of judgeFlowLaunch and the only place the action's copy exists, so flowResponse.ts alone cannot repair the drop. It is also the one module both hosts share, so the toast is spoken once and neither host is edited. No open PR touched it when read: 6 open PRs, none touching flowLaunch, flowResponse, FlowRunner, ActionRunner.ts or ui-action.ts; control: the scan listed objectui#12277's 4 files.",
"File surface: content/docs/guide/architecture-overview.md is added, one table cell stating the precedence (AGENTS.md commandment #2, docs-driven).",
"Clause-②: the claim declared yes; the PR body line reads 'Clause-②: no', as the final diff measures it. No published TypeScript member is added or changed: the edited exports live in utils/flowResponse.ts, which the package's exports map (only . and ./styles.css) does not reach. On the built dist, no declaration file other than utils/flowLaunch.d.ts names it, and the built views/FlowRunner.d.ts carries none of FlowRunner.tsx's edits. The changeset is @object-ui/app-shell patch.",
"Mechanism assumption 2: the shared rule covers the author's copy (action, then flow); the default sentence stays each end's own, not the paused expression's flowRunner.completed. Raised as open_questions[0].",
"Behaviour change beyond the card, small: on the paused end, a whitespace-only flow successMessage now counts as no copy (the shared predicate), so the flow-completed sentence shows instead of a blank toast. Pinned at unit level and named in the PR's Acceptance notes."
],
"gates": [
{
"command": "bash os-verify-lock.sh -c "pnpm exec turbo run build --filter='@object-ui/app-shell^...' --concurrency=2"",
"exit": 0,
"verdict": "Tasks: 28 successful, 28 total (28 cached); VERDICT command-exit 0",
"at": "1fb1ced, before editing"
},
{
"command": "pnpm --filter @object-ui/app-shell type-check",
"exit": 0,
"verdict": "echoed 'tsc --noEmit && tsc -p tsconfig.test.json', no diagnostics; tsc -p tsconfig.test.json --listFilesOnly lists the 3 touched test files",
"at": "48f2b79"
},
{
"command": "bash os-verify-lock.sh -c 'pnpm exec vitest run --maxWorkers=2 FILES' (narrowed set, half 1 of 2)",
"exit": 0,
"verdict": "Test Files 89 passed (89); Tests 779 passed (779); VERDICT command-exit 0",
"at": "48f2b79"
},
{
"command": "bash os-verify-lock.sh -c 'pnpm exec vitest run --maxWorkers=2 FILES' (narrowed set, half 2 of 2)",
"exit": 0,
"verdict": "Test Files 85 passed (85); Tests 631 passed (631); VERDICT command-exit 0",
"at": "48f2b79"
},
{
"command": "ablation 1: ablation-replace.mjs on flowResponse.ts done arm, wrapping vitest on the 3 touched test files",
"exit": 1,
"verdict": "5 failed, 49 passed as predicted; restored: blob == HEAD (1e5208373626) and git diff HEAD empty",
"at": "48f2b79"
},
{
"command": "ablation 2: ablation-replace.mjs --delete on flowLaunch.ts successToast line, wrapping the same vitest run",
"exit": 1,
"verdict": "3 failed, 51 passed as predicted; restored: blob == HEAD (8e8edd6b26a0) and git diff HEAD empty",
"at": "48f2b79"
},
{
"command": "pnpm exec eslint --format json (the 6 touched source and test files)",
"exit": 0,
"verdict": "6 results, 0 errors, 32 warnings (no-explicit-any, or pre-existing); proven narrowing: the root config covers all 6 and ignores none, no type-aware linting, no rule reads the file system",
"at": "48f2b79"
},
{
"command": "pnpm check:eager-closure (after apps/console vite build)",
"exit": 0,
"verdict": "Console eager closure is 3131.3 KB gzipped across 72 of 2255 chunks (budget: 3204.6 KB, headroom: 73.2 KB)",
"at": "48f2b79"
},
{
"command": "pnpm check:new-line-citations",
"exit": 0,
"verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only",
"at": "ea9415a"
},
{
"command": "pnpm check:control-bytes",
"exit": 0,
"verdict": "check-control-bytes: OK",
"at": "ea9415a"
},
{
"command": "node scripts/check-changeset-presence.mjs",
"exit": 0,
"verdict": "6 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s): .changeset/12274-flow-done-success-message.md.",
"at": "ea9415a"
},
{
"command": "node scripts/check-changeset-no-major.mjs",
"exit": 0,
"verdict": "No changeset declares a
majorbump.","at": "ea9415a"
},
{
"command": "pnpm check:changeset-claims",
"exit": 0,
"verdict": "No pending changeset names a file this change touches.",
"at": "ea9415a"
},
{
"command": "pnpm check:doc-fences / check:doc-json / check:doc-types",
"exit": 0,
"verdict": "all three OK",
"at": "ea9415a"
},
{
"command": "pnpm check:doc-snippets",
"exit": 0,
"verdict": "Semantic phase: 788 of 788 block(s) judged, 0 failed (after its scoped build, 35 of 35 cached; the first attempt answered PRECONDITION NOT MET, exit 2, not a red)",
"at": "ea9415a"
},
{
"command": "bash os-verify-lock.sh -c 'pnpm exec vitest run (37 scripts/tests files that read content/docs)'",
"exit": 0,
"verdict": "Test Files 37 passed (37); Tests 1984 passed (1984)",
"at": "ea9415a"
},
{
"command": "pnpm check:phantom-deps / check:esm-specifiers / check:self-import / check:test-path-roots / check:vi-mock-specifiers / check:vi-mock-inherit / check:vi-mock-override-shape / check:pending-changeset-literals / check:handler-key-reads / check:action-forward-parity / check:unreferenced-sources / check:i18n-keys / check:metadata-write-doors",
"exit": 0,
"verdict": "all 13 OK",
"at": "48f2b79"
},
{
"command": "node scripts/check-governed-queue-guard.mjs --test (the 8 changed paths)",
"exit": 0,
"verdict": "NOT GOVERNED, 8 path(s) checked against 5 governed surface(s); none matched",
"at": "ea9415a"
}
],
"gate_derivation": "Hand-derived from objectui's package.json and .github/workflows, since objectstack's dispatch-gates.mjs answers for objectstack only. CI owns the full test suite and the repo-wide lint.",
"ci": "not waited on (CI convergence is the PM's)",
"line_budget": "n/a (no skills/** or ledger touched)",
"published_surface": "none moves; needs:contract-review not hung",
"cleanup": "worktree /home/user/objectui-issue-12274 removed without --force after rm -rf of its node_modules; no server or monitor was started"
}
Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
Seat ACCEPT: objectui PR #12281 at
ea9415a·domain:uiseat 1 ·session_01CsyMRsFJBKNEMa4oPY1b5z· 2026-10-12T23:42ZVerdict: ACCEPT. Reviewed on GitHub against the claim
6134218617and triage6133357796, not against the report6134703066. It is gated on the at-tier contract review the claim'sClause-②: yesdeclaration owes; the seat hangsneeds:contract-reviewon the PR in this act, and the review runs once CI on this head has converged.PR form.
main, assigneezhuangjianguo. Line 1 isFixes #12274and line 2 isClause-②: no; a scan of the whole body found no other closing verb next to a card number.check-governed-merges --prreads NOT governed, 666 lines.The line-2
noagainst the claim'syes. The claim declaredyesbefore the route was chosen, because route (a) would have added a member to@object-ui/types'ActionResult. The dev took route (b) and measured that no published member moves:flowResponse.tsandflowLaunch.tssit outside@object-ui/app-shell'sexports(.and./styles.css). The declaration limb still binds the queue, so the at-tier review confirms or refutes thatnoon the diff.The diff, read.
flowSuccessCopy(actionMessage, flowMessage)inutils/flowResponse.tsis the action's copy, then the flow's, under oneusableCopypredicate.FlowRunner's terminal toast now calls it, and its privateinvokingActionMessageis deleted, not copied.judgeFlowLaunch'sdonearm calls it. When the flow's copy wins, the result goessilentand carriessuccessToast, whichlaunchConsoleFlowspeaks once for both hosts. When the action's copy wins, or neither exists, thedoneresult is unchanged, so the runner's own rungs and default apply as before.done, so there is no success toast on either path. That matches triage's direction.The dev's open question (each end's default sentence), answered by the seat, not escalated.
successMessage, then the default". On this path the card names the default as the runner's own ("otherwise its default").The changeset and docs, sentence by sentence.
@object-ui/app-shellpatch: "closes with the flow's ownsuccessMessagewhen the action declares none", "When the action declares a message, the straight-through toast is unchanged", "When neither does, each path keeps its own default text", "A refused or failed run still shows no success toast" and "No exported type or prop changes" (the at-tier review re-reads this last one). Each sentence is true of the diff.architecture-overview.mdtable cell restates the same precedence.Accepted deviations.
utils/flowLaunch.tswas added to the surface. It is the one caller ofjudgeFlowLaunch, the one place the action's copy exists, and shared by both hosts.successMessagenow counts as no copy (the shared predicate). This is pinned at unit level and named in the PR.Evidence, as reported. Pins in both hosts and on both doors cover cases (i)–(iv), plus 9 unit tests. Ablation 1 (the done arm's flow branch) turns 5 red, and ablation 2 (the
successToastline) turns 3 red; both were restored blob-equal to HEAD. The two out-of-scope notes (the${result.*}filling asymmetry, and the runtime-onlyActionDef.toastoptions) are Acceptance notes with no carrier.Next (the seat's).
ea9415ais converging.needs:contract-review, thenpr_ready+automerge_enable.Implemented-by:
claude/issue-12274-flow-done-success-message(mode:subagent dev of this seat)Reviewed-by:
session_01CsyMRsFJBKNEMa4oPY1b5zGenerated by Claude Code
objectstack-fleet commentedon Oct 13, 2026
Landed: objectui PR #12281 →
mainbfca2a2·domain:uiseat 1 ·session_01CsyMRsFJBKNEMa4oPY1b5z· 2026-10-13T00:19Zcompletedby the PR'sFixes #12274.mainbfca2a2are blob-identical to the head the contract review judged,ea9415a(record6134949056, PASS).pm:dispatchedremoved (read back);domain:ui,area:workflow, type and priority stay.@object-ui/app-shellpatch) rides the next objectui release.main: a flow that endsdonewith its own success copy gets exactly one success toast, the flow's own sentence, from both doors (the record-detail launch and the console action runner). An author-written actionsuccessMessagestill wins over the flow's copy, through one sharedflowSuccessCopythatFlowRunneralso uses.6134754001(each end keeps its own default sentence), and the contract review agreed. Unifying the two defaults is a separate preference; it is put to the maintainer on the seat post, not filed.Generated by Claude Code