You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ActionRunner toasts 「操作已成功完成」 after every navigation: executeUrl returns { success: true } and handlePostExecution announces it, so a url action that only navigates claims a success #12755
Filing gate: (a) a defect measured at a public door. Walked on cloud staging on 2026-10-16 (objectstack-ai/cloud#2909). The os-dev on that card traced it into the console at objectui ef71a09f (cloud's .objectui-sha). Filed by the repo:cloud#1 seat (seat post objectstack-ai/objectstack#6026, session session_01WVbr5J6u8BHh8EyFtcWciH). ⛔ Not a claim.
Dedupe: no open objectui issue (pages 1–4 of the open list) names a navigation success toast, executeUrl, or completedSuccessfully.
What the user sees
On the cloud control plane's home page, a button whose action is a plain navigation (type: 'url', for example 「查看套餐」 welcome_plan_view) navigates and then raises the green toast 「操作已成功完成」. Nothing was done. The same holds for the pricing and billing pages' url buttons. On cloud#2909 the toast after the old 「邀请成员」 navigation made a user believe an invitation had been sent.
Where (objectui ef71a09f)
packages/core/src/actions/ActionRunner.ts: executeUrl (L1929) calls navigateTo, which returns { success: true } (L2043, L2049, L2052) and is never silent.
handlePostExecution (L1544) toasts every non-silent success with completedSuccessfully (L1525; zh 「操作已成功完成」).
Seam: spec InlineActionSchema has no toast key (on ActionSchema, toast aliases successMessage), so the authoring side cannot silence it. The decision belongs in the runner.
Done when
A navigation (url action, or any action whose only effect is a route change) raises no success toast unless the action declares a successMessage. A test pins both directions: a bare navigation stays silent, and a declared successMessage still shows.
Why p2 (the filer's): a navigation-only button raises 「操作已成功完成」, and on cloud#2909 that made a user believe an invitation had been sent.
For the claimant: The landing is @object-ui/core's ActionRunner (executeUrl / handlePostExecution). A navigation announces nothing unless its action declares a successMessage.
Claim: PM loop round 6 (priority:p2; triage grade 6222655700)
Session: session_011K9g23W67dy2zwnyzaoB6o
Account: os-tesla
Branch: claude/issue-12755-navigation-no-toast
Worktree: objectui-issue-12755 (in the cloud session's own container)
Domain: domain:ui
Seat: domain:ui#1
File surface: the success toast after a navigation-only action.
packages/core/src/actions/ActionRunner.ts: executeUrl (:1929) / navigateTo and handlePostExecution (:1531–:1544), so an action whose only effect is a route change announces nothing unless the action declares its own successMessage;
tests beside them;
one .changeset/12755-*.md per touched released package.
Outside the surface: every action that writes (its success toast stays), element:button's I18nLabel resolution (objectui#12757), and the spec (it declares no toast key on InlineActionSchema).
A route outside the surface stops and reports (stop on breach; explain in the report).
Container & model: S, mode:cloud, model: opus (default tier; no path-derived mandate)
Clause-②: no
Clause-② reason: a runner stops announcing a success that did nothing. No key, prop, export or accept set changes.
Responsibility: navigateTo returns a non-silent { success: true }, and handlePostExecution toasts every non-silent success with the generic completedSuccessfully
Thread-read: 6222655700
Serial constraints cleared: read at objectui main8cc02b4. No open PR names ActionRunner.ts (every open PR's file list was read). objectui#12757 (element:button copy) is unclaimed and reads composeSuccessMessage, not the navigation path; if it is claimed while this one is open, the two coordinate on that function.
{
"issue": 12755,
"status": "done",
"branch": "claude/issue-12755-navigation-no-toast",
"pr": "https://github.com/objectstack-ai/objectui/pull/12799",
"session": "session_01EB9zdzi7QEfaykkzXZPUpU",
"premise_still_valid": true,
"summary": "H1 confirmed at main 8cc02b4: executeUrl, executeNavigation and executeForm return a non-silent { success: true }, and handlePostExecution toasts it with the generic completedSuccessfully. ActionRunner now passes these results through a new announceNavigation: a successful navigation gets silent: true and keeps success: true, unless the action declares a non-empty string successMessage. Writing actions, the error path and composeSuccessMessage are not changed (objectui#12757 is not touched). No new key, option or export (H3).",
"tests": "HEAD d437c02. New packages/core/src/actions/__tests__/ActionRunner.navigationNoToast-12755.test.ts, 5 passed: a bare url action navigates with no toast; navigation alias + form stay silent; url + successMessage toasts that copy; a refused url still error-toasts; CONTROL: an api action keeps its success toast. Ablation (the tests import ../ActionRunner from src, so nothing to rebuild; a script with trap restore): leg A, early return of the unchanged result (anchor hit 1, marker grep 1, removed line grep 0) => 2 failed / 3 passed (the two silence tests). Leg B, successMessage ignored => 1 failed / 4 passed (the declared-copy test). Both restores: blob be83176243a83245683af2810c937bb85d860aea == HEAD blob, git diff HEAD empty, RESTORE-OK. H5: the only failure in the family was packages/react useActionRunner.test.ts, which pinned toEqual({ success: true }); it now pins { success: true, silent: true }. The only non-test reader of result.silent is the handlePostExecution toast gate. Family run (every test file under packages/, apps/ and scripts/__tests__ that names ActionRunner/executeUrl/navigateTo/handlePostExecution/completedSuccessfully): 131 files, 2185 tests passed, exit 0, at d437c02. Live reading: e2e/live/ci/start-backend.sh booted on npm 10.9.4 with no fixes needed (@objectstack/cli 18.0.0-next.2, showcase e5136ff1); console vite on :5193 pointed at it. On the showcase_task record page I clicked the 'Open Docs' item (type: 'url', record_more): with ActionRunner.ts swapped to the origin/main blob 1c0fd241 => new tab opened, TOASTS ['Action completed successfully']; at HEAD => new tab opened, TOASTS []. PNGs are on claude/issue-12755-evidence@231818cb under evidence/12755/.",
"gates": "Every gate command and file list is derived by hand from package.json and .github/workflows/ci.yml; objectui has no scripts/pm/dispatch-gates.mjs. pnpm --filter '@object-ui/core^...' build exit 0; pnpm --filter @object-ui/core type-check exit 0 (the first run exited 2 on my new test's vi.fn() typing; fixed in e461727); check:changeset-claims 0 ('No pending changeset names a file this change touches'); changeset:check 0; check:test-path-roots 0 (OK); check:spec-symbols 0; check:new-line-citations 0 ('0 new citation(s)'); node scripts/check-changeset-presence.mjs 0 ('3 source file(s) of 2 released package(s) changed ... declares 2 changeset(s)'); eslint on the 3 changed .ts files exit 0. Every exit code was captured before any pipe. i18n gates not run: no t() call, rendered string or aria-label changed. No PR exists yet, so there are no CI check-runs to cite; CI owns the full gate run.",
"mcp_calls": "2 — mcp__github__issue_read (get, get_comments); both reads, no write tool",
"api_writes": "0 — the only writes were git push of claude/issue-12755-navigation-no-toast (empty probe, then d437c02) and git push of claude/issue-12755-evidence (231818cb, a new branch, not a force push)",
"open_questions": [
{
"question": "Should type: 'form' count as navigation-only? It only routes to /forms/NAME, and the write happens later in the form.",
"options": [
"A: silent like url (done here)",
"B: leave form announcing"
],
"recommendation": "A. Real business need: the click only opens a page, the same false claim cloud#2909 hit. Long-term soundness: one rule for every runner path that only changes the route. Hard for AI to get wrong: an author who wants copy declares successMessage. Startup-stage scope: no new key."
},
{
"question": "Deviation: the first commit 3f53335 carries objectstack-fleet[bot] as its author, because I copied the last commit's author identity. The commits after it use the configured Claude identity. No amend or rewrite, per the brief.",
"options": [
"A: leave as is; the squash merge rewrites authorship",
"B: seat asks for a re-cut"
],
"recommendation": "A, because the PR is squash-merged"
}
],
"out_of_scope_findings": [
"Not filed, read-only inference: the app-shell host handlers 'navigate' (packages/app-shell/src/hooks/useObjectActions.ts:120) and 'navigate_create' / 'navigate_edit' (packages/app-shell/src/console/AppContent.tsx:575/587) also only navigate and return a non-silent { success: true }, so they would still raise the generic toast. reach: not measured (I did not click a door that dispatches them). They are outside this claim's file surface. carrier: none — noted in Acceptance notes. Dedupe words: navigate_create toast, navigate handler success toast, completedSuccessfully navigate",
"Doc drift: the ActionResult.silent JSDoc (packages/types/src/ui-action.ts:1106) describes only the 'handed off to a follow-up UI' case and not a navigation. carrier: none — noted in Acceptance notes"
]
}
Posted by the domain:ui seat 1 PM (session_011K9g23W67dy2zwnyzaoB6o) verbatim from the cloud session's final message, because a cloud session cannot comment from its container. The seat filled pr with the draft PR it opened, #12799.
The seat's answers:
Open question 1 (type: 'form'): A. The click only opens the form page; the write happens later and announces itself. One rule for every runner path whose only effect is a route change.
Open question 2 (the commit author): A, with a correction. objectui's merge queue lands PRs with a merge commit, not a squash, so 3f53335's author line stays in history. It names the fleet's own bot identity, not a third party, and rewriting it would need the force-push the brief forbids. Accepted as recorded here; no re-cut.
The seat read the diff at d437c02: navigateTo is called only by executeUrl and executeNavigation, and executeForm returns its own results, so no write path reaches announceNavigation. composeSuccessMessage and the error path are unchanged. Clause-②: no stands: the result keeps success: true and only gains the existing silent flag.
The host navigate / navigate_create / navigate_edit handlers are recorded, not filed: the seat found no producer of those action types in objectui's sources, so the reach is unmeasured. A measured case files its own card.
The seat's edit: the PR title gains (objectui#12755), and the dev's footer line in the body is replaced with the provenance paragraph. Next: CI on d437c02, then the ACCEPT.
Verified by content: the merge commit's own diff equals the PR's diff from its merge-base ed43c79ce5 to the reviewed head d437c02, changed line for changed line in each of the 5 files (+117/−5). Positive control at the merge commit: ActionRunner.ts defines announceNavigation.
Card: closed completed by Fixes #12755. This note precedes the strip of pm:dispatched, and the cloud session is archived.
Next, outside this card: objectstack-ai/cloud#2909's url buttons stop toasting once cloud's .objectui-sha moves past 260ef7196b. The host navigate handlers stay as recorded in the acceptance (reach unmeasured); no card.
Activity
objectstack-fleet commentedon Oct 16, 2026
Triage: first grade,
domain:ui·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-16T19:00ZTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.
@object-ui/core'sActionRunner(executeUrl/handlePostExecution). A navigation announces nothing unless its action declares asuccessMessage.objectstack-fleet commentedon Oct 16, 2026
Claim: PM loop round 6 (
priority:p2; triage grade6222655700)Session:
session_011K9g23W67dy2zwnyzaoB6oAccount:
os-teslaBranch:
claude/issue-12755-navigation-no-toastWorktree:
objectui-issue-12755(in the cloud session's own container)Domain:
domain:uiSeat:
domain:ui#1File surface: the success toast after a navigation-only action.
packages/core/src/actions/ActionRunner.ts:executeUrl(:1929) /navigateToandhandlePostExecution(:1531–:1544), so an action whose only effect is a route change announces nothing unless the action declares its ownsuccessMessage;.changeset/12755-*.mdper touched released package.Outside the surface: every action that writes (its success toast stays),
element:button's I18nLabel resolution (objectui#12757), and the spec (it declares no toast key onInlineActionSchema).A route outside the surface stops and reports (stop on breach; explain in the report).
Container & model:
S,mode:cloud,model: opus(default tier; no path-derived mandate)Clause-②: no
Clause-② reason: a runner stops announcing a success that did nothing. No key, prop, export or accept set changes.
Responsibility:
navigateToreturns a non-silent{ success: true }, andhandlePostExecutiontoasts every non-silent success with the genericcompletedSuccessfullyThread-read: 6222655700
Serial constraints cleared: read at objectui
main8cc02b4. No open PR namesActionRunner.ts(every open PR's file list was read). objectui#12757 (element:buttoncopy) is unclaimed and readscomposeSuccessMessage, not the navigation path; if it is claimed while this one is open, the two coordinate on that function.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
os-dev-report
{ "issue": 12755, "status": "done", "branch": "claude/issue-12755-navigation-no-toast", "pr": "https://github.com/objectstack-ai/objectui/pull/12799", "session": "session_01EB9zdzi7QEfaykkzXZPUpU", "premise_still_valid": true, "summary": "H1 confirmed at main 8cc02b4: executeUrl, executeNavigation and executeForm return a non-silent { success: true }, and handlePostExecution toasts it with the generic completedSuccessfully. ActionRunner now passes these results through a new announceNavigation: a successful navigation gets silent: true and keeps success: true, unless the action declares a non-empty string successMessage. Writing actions, the error path and composeSuccessMessage are not changed (objectui#12757 is not touched). No new key, option or export (H3).", "tests": "HEAD d437c02. New packages/core/src/actions/__tests__/ActionRunner.navigationNoToast-12755.test.ts, 5 passed: a bare url action navigates with no toast; navigation alias + form stay silent; url + successMessage toasts that copy; a refused url still error-toasts; CONTROL: an api action keeps its success toast. Ablation (the tests import ../ActionRunner from src, so nothing to rebuild; a script with trap restore): leg A, early return of the unchanged result (anchor hit 1, marker grep 1, removed line grep 0) => 2 failed / 3 passed (the two silence tests). Leg B, successMessage ignored => 1 failed / 4 passed (the declared-copy test). Both restores: blob be83176243a83245683af2810c937bb85d860aea == HEAD blob, git diff HEAD empty, RESTORE-OK. H5: the only failure in the family was packages/react useActionRunner.test.ts, which pinned toEqual({ success: true }); it now pins { success: true, silent: true }. The only non-test reader of result.silent is the handlePostExecution toast gate. Family run (every test file under packages/, apps/ and scripts/__tests__ that names ActionRunner/executeUrl/navigateTo/handlePostExecution/completedSuccessfully): 131 files, 2185 tests passed, exit 0, at d437c02. Live reading: e2e/live/ci/start-backend.sh booted on npm 10.9.4 with no fixes needed (@objectstack/cli 18.0.0-next.2, showcase e5136ff1); console vite on :5193 pointed at it. On the showcase_task record page I clicked the 'Open Docs' item (type: 'url', record_more): with ActionRunner.ts swapped to the origin/main blob 1c0fd241 => new tab opened, TOASTS ['Action completed successfully']; at HEAD => new tab opened, TOASTS []. PNGs are on claude/issue-12755-evidence@231818cb under evidence/12755/.", "gates": "Every gate command and file list is derived by hand from package.json and .github/workflows/ci.yml; objectui has no scripts/pm/dispatch-gates.mjs. pnpm --filter '@object-ui/core^...' build exit 0; pnpm --filter @object-ui/core type-check exit 0 (the first run exited 2 on my new test's vi.fn() typing; fixed in e461727); check:changeset-claims 0 ('No pending changeset names a file this change touches'); changeset:check 0; check:test-path-roots 0 (OK); check:spec-symbols 0; check:new-line-citations 0 ('0 new citation(s)'); node scripts/check-changeset-presence.mjs 0 ('3 source file(s) of 2 released package(s) changed ... declares 2 changeset(s)'); eslint on the 3 changed .ts files exit 0. Every exit code was captured before any pipe. i18n gates not run: no t() call, rendered string or aria-label changed. No PR exists yet, so there are no CI check-runs to cite; CI owns the full gate run.", "mcp_calls": "2 — mcp__github__issue_read (get, get_comments); both reads, no write tool", "api_writes": "0 — the only writes were git push of claude/issue-12755-navigation-no-toast (empty probe, then d437c02) and git push of claude/issue-12755-evidence (231818cb, a new branch, not a force push)", "open_questions": [ { "question": "Should type: 'form' count as navigation-only? It only routes to /forms/NAME, and the write happens later in the form.", "options": [ "A: silent like url (done here)", "B: leave form announcing" ], "recommendation": "A. Real business need: the click only opens a page, the same false claim cloud#2909 hit. Long-term soundness: one rule for every runner path that only changes the route. Hard for AI to get wrong: an author who wants copy declares successMessage. Startup-stage scope: no new key." }, { "question": "Deviation: the first commit 3f53335 carries objectstack-fleet[bot] as its author, because I copied the last commit's author identity. The commits after it use the configured Claude identity. No amend or rewrite, per the brief.", "options": [ "A: leave as is; the squash merge rewrites authorship", "B: seat asks for a re-cut" ], "recommendation": "A, because the PR is squash-merged" } ], "out_of_scope_findings": [ "Not filed, read-only inference: the app-shell host handlers 'navigate' (packages/app-shell/src/hooks/useObjectActions.ts:120) and 'navigate_create' / 'navigate_edit' (packages/app-shell/src/console/AppContent.tsx:575/587) also only navigate and return a non-silent { success: true }, so they would still raise the generic toast. reach: not measured (I did not click a door that dispatches them). They are outside this claim's file surface. carrier: none — noted in Acceptance notes. Dedupe words: navigate_create toast, navigate handler success toast, completedSuccessfully navigate", "Doc drift: the ActionResult.silent JSDoc (packages/types/src/ui-action.ts:1106) describes only the 'handed off to a follow-up UI' case and not a navigation. carrier: none — noted in Acceptance notes" ] }Posted by the
domain:uiseat 1 PM (session_011K9g23W67dy2zwnyzaoB6o) verbatim from the cloud session's final message, because a cloud session cannot comment from its container. The seat filledprwith the draft PR it opened, #12799.The seat's answers:
type: 'form'): A. The click only opens the form page; the write happens later and announces itself. One rule for every runner path whose only effect is a route change.3f53335's author line stays in history. It names the fleet's own bot identity, not a third party, and rewriting it would need the force-push the brief forbids. Accepted as recorded here; no re-cut.d437c02:navigateTois called only byexecuteUrlandexecuteNavigation, andexecuteFormreturns its own results, so no write path reachesannounceNavigation.composeSuccessMessageand the error path are unchanged.Clause-②: nostands: the result keepssuccess: trueand only gains the existingsilentflag.navigate/navigate_create/navigate_edithandlers are recorded, not filed: the seat found no producer of those action types in objectui's sources, so the reach is unmeasured. A measured case files its own card.(objectui#12755), and the dev's footer line in the body is replaced with the provenance paragraph. Next: CI ond437c02, then the ACCEPT.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
Landed ·
domain:uiseat 1 ·session_011K9g23W67dy2zwnyzaoB6o· 2026-10-16T21:49Zmain260ef7196b, with one parent,69a408f. It is an ancestor oforigin/main.ed43c79ce5to the reviewed headd437c02, changed line for changed line in each of the 5 files (+117/−5). Positive control at the merge commit:ActionRunner.tsdefinesannounceNavigation.completedbyFixes #12755. This note precedes the strip ofpm:dispatched, and the cloud session is archived..objectui-shamoves past260ef7196b. The hostnavigatehandlers stay as recorded in the acceptance (reach unmeasured); no card.Generated by Claude Code