Repository navigation
feat(spec,console): a type: 'flow' action may declare onSuccess, and the console navigates after a run that completes - #26011
Conversation
Claude-Session: https://claude.ai/code/session_013w86pS2SMm6BU2PfGQ3vJ7 Co-authored-by: Claude <noreply@anthropic.com>
… gate for flow onSuccess Claude-Session: https://claude.ai/code/session_013w86pS2SMm6BU2PfGQ3vJ7 Co-authored-by: Claude <noreply@anthropic.com>
…, so the onSuccess hop skips it Claude-Session: https://claude.ai/code/session_013w86pS2SMm6BU2PfGQ3vJ7 Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013w86pS2SMm6BU2PfGQ3vJ7 Co-authored-by: Claude <noreply@anthropic.com>
…nner and types edits Claude-Session: https://claude.ai/code/session_013w86pS2SMm6BU2PfGQ3vJ7 Co-authored-by: Claude <noreply@anthropic.com>
Resolves the flowResponse.test.ts import conflict (both sides' imports kept) and regenerates the reference docs and the sdui manifest record from the merged tree. Claude-Session: https://claude.ai/code/session_013w86pS2SMm6BU2PfGQ3vJ7 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 3 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 145 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 2f888ec3ef7d26d0621e43ee63b03c36ed1f69d2 && git checkout 2f888ec3ef7d26d0621e43ee63b03c36ed1f69d2
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 81bba6c3f5be5b6cbabf76511383940349f23b15 a3f1f482ad01eb653cd8837dd88a2b32f56e2ae7 && git checkout -B drift-repro 81bba6c3f5be5b6cbabf76511383940349f23b15 && git merge --no-ff a3f1f482ad01eb653cd8837dd88a2b32f56e2ae7
node scripts/docs-audit/affected-docs.mjs --json 81bba6c3f5be5b6cbabf76511383940349f23b15
|
Contract reviewServed-tier: Inputs read: card #25800 body and its four comments (triage 6398521414, premise 6409899481, claim 6410040122, os-dev-report 6412203410); PR #26011 body, 30-file list and net diff; the 63 check-runs on the head: 58 success, 5 skipped (the two opt-in harnesses, the live-PG Temporal conformance, Dogfood Verify CLI and the dogfood matrix placeholder), 0 failure. Among the greens: Check Changeset, Governed Surface Queue Guard, Spec property liveness, Lint and Repo Gates, Type Check (workspace, source, consumer, debt ledger), Test Core 1-8, Test UI 1-16, Build Docs, Flag docs affected by code changes. ① Derived judgments
② Semver levelChangeset Clause-②: yes ③ Boundary flagsDev report 6412203410 on 9cb24ac:
Implemented-by: VERDICT: PASS |
席位核对ACCEPT · domain:spec seat 2 · 2026-10-26T10:37Z · head
|
Only the generated sdui manifest record conflicted; took main's side and re-recorded it from the merged tree. Claude-Session: https://claude.ai/code/session_013w86pS2SMm6BU2PfGQ3vJ7 Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Re-review after a merge-forward. Head d8570af is a 2-parent commit: parents eaebe2e (the head PASS record 6413937921 judged) and b4199c9 (origin/main), made after a merge-queue conflict. Verified delta, one git read command, restricted to the PR's 30 files: Inputs read: card #25800 body and its five comments (triage 6398521414, premise 6409899481, claim 6410040122, os-dev-report 6412203410, ACCEPT 6413972897; no ruling newer than the previous record); PR #26011 body and 30-file list; the merge-forward delta above; the 63 check-runs on head d8570af: 58 success, 5 skipped (the two opt-in harnesses, the live-PG Temporal conformance, Dogfood Verify CLI and the dogfood matrix placeholder), 0 failure. Among the greens: Check Changeset, Governed Surface Queue Guard, Spec property liveness, Lint and Repo Gates (which holds check-sdui-manifest and the api-surface family), Type Check (workspace, source, consumer, debt ledger), Test Core 1-8, Test UI 1-16, Build Docs, Flag docs affected by code changes, Check PR Size. ① Derived judgments
② Semver levelCARRIED from 6413937921: the changeset bumps Clause-②: yes ③ Boundary flagsCARRIED from 6413937921:
Implemented-by: VERDICT: PASS |
|
Seat 2 · re-armed after the merge-forward to |
Only the generated sdui manifest record conflicted; took main's side and re-recorded it from the merged tree. Claude-Session: https://claude.ai/code/session_013w86pS2SMm6BU2PfGQ3vJ7 Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Re-review after a second merge-forward. Head 1ea8dd1 is a 2-parent commit: parents d8570af (the head PASS record 6415795343 judged) and 1bbb7bf (origin/main, #26019 landed), made after a second merge-queue conflict. Verified delta, git read commands only:
Inputs read: card #25800 body and its five comments (triage 6398521414, premise 6409899481, claim 6410040122, os-dev-report 6412203410, ACCEPT 6413972897; no ruling newer than the previous record); PR #26011 body and 30-file list; the merge-forward delta above; the 63 check-runs on head 1ea8dd1, polled until every run completed (last at 13:47Z): 58 success, 5 skipped (the two opt-in harnesses, the live-PG Temporal conformance, Dogfood Verify CLI and the dogfood matrix placeholder), 0 failure. Among the greens: Check Changeset, Governed Surface Queue Guard, Spec property liveness, Lint and Repo Gates, Type Check (workspace, source, consumer, debt ledger), Test Core 1-8 (4/8 and 5/8 finished last), Test UI 1-16, Build Docs, Flag docs affected by code changes, Check PR Size. ① Derived judgments
② Semver levelCARRIED from 6413937921 via 6415795343: the changeset bumps Clause-②: yes ③ Boundary flagsCARRIED from 6413937921 via 6415795343:
Implemented-by: VERDICT: PASS |
|
Seat 2 · re-armed after the second merge-forward to |
Takes main's per-package sdui manifest record layout and re-records the two registry packages this branch touches (core, types) from the merged tree. Claude-Session: https://claude.ai/code/session_013w86pS2SMm6BU2PfGQ3vJ7 Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Re-review after a third merge-forward. Head 5dc4881 is a 2-parent commit: parents 1ea8dd1 (the head PASS record 6417606265 judged) and 601c773 (origin/main, 23 commits past 1bbb7bf, #26120 among them: the single scripts/sdui-manifest.record.json digest became one record per ui registry package under scripts/sdui-manifest.sources/). Verified delta, git read commands only:
Inputs read: card #25800 body and its five comments (triage 6398521414, premise 6409899481, claim 6410040122, os-dev-report 6412203410, ACCEPT 6413972897; no ruling newer than the previous record); PR #26011 body and 31-file list; the merge-forward delta above; the 63 check-runs on head 5dc4881, polled every 60s until every run completed (last at 14:59Z): 58 success, 5 skipped (the two opt-in harnesses, the live-PG Temporal conformance, Dogfood Verify CLI and the dogfood matrix placeholder), 0 failure. Among the greens: Check Changeset, Governed Surface Queue Guard, Spec property liveness, Lint & Repo Gates, Lint · repo & tooling gates, TypeScript Type Check with its four lanes (workspace, source, consumer, debt ledger), Test Core 1-8, Test UI 1-16, Build Core, Build Docs, Lint UI, Type Check UI, Build & E2E UI, Flag docs affected by code changes, Check PR Size. The whole diff was not re-read; the carried judgments rest on (a) and (b). ① Derived judgments
② Semver levelCARRIED from 6413937921 via 6415795343 and 6417606265: the changeset bumps Clause-②: yes ③ Boundary flagsCARRIED from 6413937921 via 6415795343 and 6417606265:
Implemented-by: VERDICT: PASS |
|
Seat 2 · re-armed after the third merge-forward to |
Resolves packages/spec/liveness/action.json by hand: main's in-repo evidence, evidenceScope and producer for onSuccess.navigate, with this branch's #25800 note sentence (already pointing at in-repo ui/ paths) kept on main's note. Claude-Session: https://claude.ai/code/session_013w86pS2SMm6BU2PfGQ3vJ7 Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Re-review after a fourth merge-forward with one hand-resolved conflict. Head 7913854 is a 2-parent commit: parents 5dc4881 (the head PASS record 6419294223 judged) and 7111e14 (origin/main, 16 commits past 601c773, f79b9d5 among them: the renderer's liveness evidence moved in-repo under ui/). Verified delta, git read commands only (PR head read as refs/heads/pr26011 = 7913854):
Inputs read: card #25800 body and its five comments (triage 6398521414, premise 6409899481, claim 6410040122, os-dev-report 6412203410, ACCEPT 6413972897; no ruling newer than the previous record); PR #26011 body and 31-file list; the merge-forward delta above; the previous records 6413937921, 6415795343, 6417606265 and 6419294223 and the seat notes beside them; the 63 check-runs on head 7913854, polled every 60s until every run completed (last at 16:07Z): 58 success, 5 skipped (the two opt-in harnesses, the live-PG Temporal conformance, Dogfood Verify CLI and the dogfood matrix placeholder), 0 failure. Among the greens: Check Changeset, Governed Surface Queue Guard, Spec property liveness, Lint & Repo Gates, Lint · repo & tooling gates, TypeScript Type Check with its four lanes, Test Core 1-8, Build Core, Lint UI, Type Check UI, Build & E2E UI, Flag docs affected by code changes, Check PR Size. The whole diff was not re-read; the carried judgments rest on (a) and (b). ① Derived judgments
② Semver levelCARRIED from 6413937921 via 6415795343, 6417606265 and 6419294223: the changeset bumps Clause-②: yes ③ Boundary flagsCARRIED from 6413937921 via 6415795343, 6417606265 and 6419294223:
Implemented-by: VERDICT: PASS |
|
Seat 2 · fourth merge-forward to |
Takes main's scripts/sdui-manifest.sources/core.json and re-records it from the merged tree; regenerates content/docs/references/data/object.mdx, which the merge deferred. Claude-Session: https://claude.ai/code/session_013w86pS2SMm6BU2PfGQ3vJ7 Co-authored-by: Claude <noreply@anthropic.com>
|
Seat note (domain:spec seat 2, session_01RyMY3prh9GRva1Tt37Di3i): the
Plan: once #26231 lands, this branch takes main forward and CI re-runs; auto-merge is re-armed after the re-review record on that head and green CI. No change is pushed here for this failure. |
Brings in #26231 (the ObjectSchema corpus guards re-pointed to 48); merged clean, nothing deferred for regeneration. Claude-Session: https://claude.ai/code/session_013w86pS2SMm6BU2PfGQ3vJ7 Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Re-review after the fifth and sixth merge-forwards, kept short. This head is reached in two hops from 7913854 (the PASS record 6420886973 judged): 0b9b772 merged origin/main at df8aac4 (18 commits past 7111e14, #26033 among them), and a3f1f48 merged origin/main at a1477de (9 commits past df8aac4, #26231 among them). Verified delta, git read commands only (PR head read as refs/pull/26011/head = a3f1f48; the brief named 0b9b772, which was superseded while its check-runs were still being polled, so this record names the head that stands and judges both hops):
The intermediate head 0b9b772 completed 62 check-runs with two reds, Inputs read: card #25800 body and its five comments (triage 6398521414, premise 6409899481, claim 6410040122, os-dev-report 6412203410, ACCEPT 6413972897; no ruling newer than the previous record); PR #26011 body (unchanged since 6420886973) and 31-file list; the two merge-forward deltas above; the previous records 6413937921, 6415795343, 6417606265, 6419294223 and 6420886973 and the seat notes beside them (the newest, 6422403296); the check-runs on 0b9b772 (62, all completed: 55 success, 5 skipped, the 2 base-reds above) and the 63 check-runs on head a3f1f48, polled every 60s until every run completed (last at 17:42Z): 58 success, 5 skipped (the two opt-in harnesses, the live-PG Temporal conformance, Dogfood Verify CLI and the dogfood matrix placeholder), 0 failure. Among the greens: Check Changeset, Governed Surface Queue Guard, Spec property liveness, Lint & Repo Gates, Lint · repo & tooling gates, Lint · docs & code guards, TypeScript Type Check with its four lanes, Test Core 1-8, Build Core, Build Docs, Lint UI, Type Check UI, Build & E2E UI, Test UI 1-16, Flag docs affected by code changes, Check PR Size. The whole diff was not re-read; the carried judgments rest on (a) and (b). ① Derived judgments
② Semver levelCARRIED from 6413937921 via 6415795343, 6417606265, 6419294223 and 6420886973: the changeset bumps Clause-②: yes ③ Boundary flagsCARRIED from 6413937921 via 6415795343, 6417606265, 6419294223 and 6420886973:
Implemented-by: VERDICT: PASS |
Requested by Steedos · project thread
Fixes #25800
Clause-②: yes
Metadata-protocol: added
Summary
A
type: 'flow'action that creates a record could not take the user to it:ActionSchemarefusedonSuccessbesidetype: 'flow', and the page action rows refused it beside aflowexecutor. This PR admitsflowinto the one executor set both read (ON_SUCCESS_EXECUTORSinpackages/spec/src/ui/action-on-success-executor.ts), rewords the refusal prose forurl,navigation,modalandformto name the three executors, opens the Studio action form'sonSuccessrow to a flow action, and regenerates the reference docs.On the console side, the post-success hop fires after a flow run that completes and never after one that pauses at a screen or ends refused. On a completed run,
${result.*}reads the run's answer (AutomationResult), so${result.output.VAR}resolves to one of the flow'sisOutputvariables:Mechanism-assumption correction: why
silentcannot mark a hand-offThe dispatch assumed the ActionRunner needed no change: the launch judge's
pausedandrefusedarms already answersilent: true, so it looked as if the hop could be keyed off that. Measured, it cannot.silentis a fact about the toast alone, and thedonearm sets it too. When the flow's ownsuccessMessagewins the toast (objectui#12274),judgeFlowLaunchreturns{ success: true, data, reload, silent: true }for a run that completed. A runner that skipped the hop onsilentwould therefore drop the hop for every completed flow that authors its own success copy, which is exactly the record-creating flow this card is about. The three success arms are indistinguishable onsuccessandsilent, so the runner needs a fact of its own.That fact is the new
ActionResult.handedOff(ui/packages/types/src/ui-action.ts): the success is a hand-off to a follow-up surface, not a completion.judgeFlowLaunchsets it on thepausedandrefusedarms, andActionRunner.handlePostExecutiongates the hop onresult.success && !result.handedOff && action.onSuccess. The seat approved the file-surface amendment (types, core, app-shell) before the console half was written.Each launch arm and its hop
judgeFlowLaunchinui/packages/app-shell/src/utils/flowResponse.tsnow states the hop conclusion for every arm in its docblock, and each conclusion is pinned by a test that runs the realActionRunner:failedsuccess: falsepausedsuccess: true,silent,handedOffFlowRunnerfinishing the run later does not hop either.refusedsuccess: true,silent,handedOffdonesuccess: true,data=AutomationResult(silentwhen the flow's copy wins)${result.*}readsdata;${result.output.VAR}is anisOutputvariable. NothandedOff, whethersilentor not.Landing point and surface delta
The claim named the spec half (
action-on-success-executor.ts,action.zod.ts,component.zod.ts,action.form.ts, their tests, the liveness ledger, the reference docs) and the console tests. The correction above added three source files to the surface, approved by the seat:ui/packages/types/src/ui-action.ts(handedOff),ui/packages/core/src/actions/ActionRunner.ts(the gate) andui/packages/app-shell/src/utils/flowResponse.ts(the arms). Following from those:scripts/sdui-manifest.record.jsonis re-recorded because the registry sources moved;sdui.manifest.jsonitself is byte-identical (106 components). No conflict with feat(spec,analytics,lint,platform-objects,app-shell): a dataset measure can aggregate the time between two datetime fields of each record #25903 arose, so main was not merged.packages/lint/src/validate-predicate-path-refs.test.tsrecounts the predicate census (63) because the form gate is now spelleddata.type in ['api','script','flow'].useConsoleActionRuntime.*,RecordDetailView.*) that pin the paused or refused result withtoEqualnow includehandedOff: true.Premise check: what
${result.output.VAR}readsThe card reported a run answering
output: {}. The runtime is not dropping anything:AutomationResult.outputis built from the flow'sisOutputvariables only (packages/services/service-automation/src/engine.ts, the "Collect output variables" loop at about line 5643), and both the trigger route and the action door (dispatchFlowAction,packages/runtime/src/action-execution.ts) serve that answer. Acreate_recordnode writes the record object into itsoutputVariable, but the variable reachesoutputonly when the flow declares itisOutput: true. The emptyoutputis a flow-authoring gap in the reporting app: declare the variableisOutput: trueand pointoutputVariableat it. The spec docblock and the changeset now say so, and a test pins that an emptyoutputresolves the template to/apps/clm/clm_contract/record/rather than throwing.Tests
Measured on this branch. The spec and ui core/types suites ran at
344ac6f5, which differs from the head only inscripts/sdui-manifest.record.json; the app-shell suite and the type-checks ran at the head,9cb24ac6.pnpm --filter @objectstack/spec test: Test Files 722 passed (722), Tests 21877 passed, 1 todo.ui/vitest overpackages/coreandpackages/types: Test Files 601 passed (601), Tests 14680 passed, 27 skipped.ui/vitest overpackages/app-shell: Test Files 1721 passed, 1 skipped (1722); Tests 15875 passed, 9 skipped.pnpm run type-checkinui/packages/types,ui/packages/coreandui/packages/app-shell(after building the app-shell dependency closure): exit 0, 0 errors each.ActionRunner.onSuccessNavigation.test.ts(reads${result.output.renewal.id}to/apps/clm/clm_contract/record/ctr_18; asilentcompleted run still hops; ahandedOffsuccess does not, with a positive control on the same runner) and aflowResponse.test.tsblock composinginterpretFlowResponse,judgeFlowLaunchand the realActionRunnerfor all four arms plus the empty-outputcase.action-on-success.test.tsandcomponent-action-row-on-success-executor.test.tsmoveflowfrom refused to accepted and parse the renewal template.Ablation
scripts/ablation-replace.mjsreplaced the runner gateif (result.success && !result.handedOff && action.onSuccess) {withif (result.success && action.onSuccess) {(anchor 1 to 0, blob3aebb3cab4eatoac1fc1dff4a2) and ran the two new test files: Test Files 2 failed (2), Tests 3 failed, 70 passed. The three reds are exactly the hand-off pins: the core "handed-off success performs no hop" test, and the paused and refused composition tests. The file was restored to its HEAD blob3aebb3cab4eawithgit diff HEADempty. This was a one-time proof; no permanent test file was added for it.Gates
Derived with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackat9cb24ac6(125 commands), each run with its exit code captured before any pipe, then reconciled with--ran: "125 derived famil(ies) accounted for — 123 run, 2 NOT-MEASURED". The 123 that ran exited 0, among themcheck:generated,check:api-surface,check:authorable-surface,check:docs,check:liveness,check:exported-any,check-sdui-manifest,check:type-check-debt(re-measured under the verify lock: "26 raw tsc error(s) total, none above its recorded number") andcheck:nul-bytes.Not measured locally, left to CI:
check:dual-build-cjs-loads(needs a full workspacepnpm build) andcheck:i18n(needs the CLI's build closure). Both refused on their prerequisite with exit 3 before reading anything; this diff adds no i18n key and changes no package's build shape.Two environment notes.
check-plugin-teardown-shape --self-testreads a fixture pinned to commit621a4876, which this shallow clone lacked; after fetching that one commit it exits 0. And an earlier sweep ran unlocked while the console manifest regeneration rebuiltpackages/spec/dist, which produced spuriouscheck:generatedandcheck:exported-anyreds; that sweep was discarded and the numbers above come from the clean rerun.Acceptance notes
refreshAfter: truesetsresult.reload, and an authoredchainruns. Neither is new, and neither is the hop this card asked about. Noted, not filed.onSuccesscan never fire. A publish-time hint for that pairing would catch the mistake earlier; noted, not filed.Generated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_013w86pS2SMm6BU2PfGQ3vJ7