Repository navigation
studio(automations): flow status shown by Studio disagrees with what runs — header Trigger reads flow.type, a published flow reads Status draft, unbound scheduled flows read On/active #11779
Description
Filing gate ① — product defect with a named location and a reproduction. reach: Studio → Automations, read against the server log and the published metadata of the same flows.
Who acts on it: objectui triage → the Studio / app-shell owner. ⛔ Not a claim. Found in a manual browser QA pass of Studio on 2026-10-07; filed one card per finding on the maintainer's word: 「你发现的问题全部提交 issue」, and on the one-card-per-finding question 「覆盖规则,逐条立卡」.
What happens
- Task Due Reminder (
schedule) is not bound on this deployment (OS_AUTOMATION_SCHEDULED_WORK_ENABLEDunset). The list row already carries the reason as a native hovertitle("disabled by deployment policy — package-authored scheduled work is off on this deployment …", from app-shell: Studio's Automations rail titles a policy-unbound schedule flow "Enabled · no trigger (run manually)", readingbound: falseas "no trigger" whereFlowRuntimeStatesays it cannot be read that way (objectui#9217 follow-up) #11281), but the visible label is still a green On, the canvas header reads Status: active, and Problems reads "No problems — this flow is structurally valid." Nothing visible without hovering says it will never run. - A record-triggered flow's header reads Trigger: autolaunched: it shows
flow.type, not the Start node'striggerType(record-after-update). - A published flow that runs has no
statuskey; the header reads Status: draft while the list reads On. - The bar says "Off by default · review before enabling", but a new flow's toggle starts Enabled.
Expected
One source of truth for state: the header shows the real trigger; published/enabled state reads the same in list and header; a flow the deployment will never run says so.
Suggested direction (triage to rule)
Header trigger from the Start node; one derived status used by list, header and Problems; render the unbound state visibly (e.g. a grey Not running here chip) from the per-flow binding the server already serves on GET /api/v1/automation/_status (objectstack-ai/objectstack#18235); align the default toggle with the "off by default" promise or change the copy.
Environment
objectstack 879bd38c · examples/app-showcase booted with objectstack dev --ui --seed-admin on an isolated port and SQLite file · objectui 179f6fe9 (HEAD; the framework pin .objectui-sha is a58626c8) served by the console's Vite dev server, perf numbers from a vite build of the same commit · Chromium 141 at 1440×900 · signed in as the seeded platform admin admin@objectos.ai unless stated.
Duplicate check
- Semantic issue search on objectstack-ai/objectui (open and closed), automations flow status header trigger autolaunched status draft scheduled flow not bound: 5 hits (0 open, 5 closed).
- Related, not the same defect:
- app-shell: Studio's Automations rail titles a policy-unbound schedule flow "Enabled · no trigger (run manually)", reading
bound: falseas "no trigger" whereFlowRuntimeStatesays it cannot be read that way (objectui#9217 follow-up) #11281 (closed) — closed 2026-10-01 (PR fix(app-shell): the Automations rail stops telling a flow with a declared trigger that it has "no trigger" (objectui#11281) #11305): fixed the dot TITLE for policy-unbound schedule flows; that card measured the dot text 'On' too. this card's 'unbound scheduled flows read On/active' is the residual -- verify on current main before filing; header Trigger / Status draft parts are new - Studio Automations pillar: on a read-only package the header enable switch stays clickable and the flow node inspector stays editable — edits are refused or silently discarded (residual of #2259) #11124 (closed) — same Automations header; different defect
- app-shell: Studio's Automations rail titles a policy-unbound schedule flow "Enabled · no trigger (run manually)", reading
- Positive control in the same run: related lists action id refusal notice shown to end users on objectstack-ai/objectui returned related lists: an action id the related object does not define draws a refusal notice above the list for whoever opens the record — an authoring fault shown to end users; scope it to authors/admins #11768: yes.
Dedupe words: flow status header autolaunched · status draft published flow · scheduled flow not bound shown on · off by default enabled
Filed by Claude Code (session session_01D76mrPJrSSdaKRxR2rvrMG) from that QA pass.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 7, 2026
Path: approvals and automation — the author sees what will run | 缺项 | P2
Triage: first grade,
bug·priority:p2·domain:ui·area:workflow·pm:queue. Direction as the body proposesTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-07T16:07Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: lands in the Studio Automations list, flow header and Problems panel ⇒
domain:ui; rationale: a Studio or console surface in objectui. Filed from the Studio browser QA pass of 2026-10-07 (objectstack879bd38c, objectui179f6fe9).GET /api/v1/automation/_statusserves ([finding] ruling G item 6's third surface has no platform half:_statuscarries no reason, so a policy-disabled flow is indistinguishable from a broken binding — and objectui#9217 is blocked on a card that does not exist objectstack#18235)Clause-②: no. Patch changeset in objectui.objectstack-fleet commentedon Oct 7, 2026
Claim: PM loop round 3
Session:
session_01CGZy1BGCjdN5cXqL9cnvB8Account:
os-support-aiBranch:
claude/issue-11779-flow-status-truthWorktree:
objectui-issue-11779Domain:
domain:uiSeat:
domain:ui#3File surface (on
d53fd02):packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx, the Automations pillar only:GET /automation/_status(FlowRuntimeState:4552,flowRailState:4586, the fetch at about:4733);doCreateFlow(:4793) for the new flow's enabled default;packages/app-shell/src/views/metadata-admin/previews/FlowPreview.tsx(the header pills at about:220–:221: Trigger readsflowType, Status readsstatus);packages/app-shell/src/views/metadata-admin/previews/flow-problems.ts(buildFlowProblems:227) andProblemsPanel.tsx, only if the unbound state shows there;engine.studio.auto.*/engine.flowPreview.*rows ofviews/metadata-admin/i18n.ts;.changeset/11779-*.md.Any file outside this list: the dev reports it before opening the PR (stop on breach; explain in the report)
Container & model:
M,mode:subagent,model: opus(dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate; default tier)Clause-②: no
Responsibility:
objectui app-shell: the flow header's Trigger pill reads flow.type rather than the Start node's trigger, its Status pill reads a status key a published flow lacks (so it reads draft), the list's green On ignores the server's binding for an unbound scheduled flow, and a new flow's toggle starts enabled under an "Off by default" bar | the platform path exists: GET /api/v1/automation/_status serves each flow's enabled and bound state (objectstack-ai/objectstack#18235), and the Start node carries triggerType | every author reading a flow's state in Studio → AutomationsThread-read: 6041845966
Serial constraints cleared:
noneblocking. This seat's objectui#11778 (area:workflow, in flight) holdsFlowCanvas.tsx,flow-canvas-parts.tsx,flow-node-config.tsandFlowNodeInspector.tsx, and its pushed diff touches none of the files above except a test (FlowPreview.removeNode-11772.test.tsx), which this card does not edit. So the same-axis surfaces are disjoint.StudioDesignSurface.tsxis shared with this seat's objectui#11784 (area:studio, a different axis). That card holds onlyPackageSwitcher'sonManageChanged(:665), a different region. Whichever lands second mergesmain. No open objectui PR touches the files above (read 2026-10-07T20:22Z; open: #11830, #11829, #11600, #11069).Why
Clause-②: no: display and default fixes inside@object-ui/app-shell. Its strings are rows of app-shell's unexported designer table. If the fix needs a published export, prop, type member or language-pack key, the dev reports it before opening the PR, and the seat amends this line.Generated by Claude Code
objectstack-fleet commentedon Oct 7, 2026
os-dev-report
{ "issue": 11779, "status": "done", "branch": "claude/issue-11779-flow-status-truth", "pr": "https://github.com/objectstack-ai/objectui/pull/11834", "session": "session_01CGZy1BGCjdN5cXqL9cnvB8 (subagent mode: the parent seat session, as the dispatch names it; the relay derived the same id from the container)", "premise_still_valid": true, "summary": "All four defects confirmed at source on d53fd02 and fixed in @object-ui/app-shell. (1) The header Trigger pill reads the Start node through the spec resolver resolveFlowTriggerKind: a record trigger shows its event and object (Record updated · task), time-relative shows its object, schedule and API their kind, and only a flow with no resolvable trigger falls back to flow.type; the words are the Start-node inspector option labels (en and zh). (2) One derivation, deriveFlowRunStatus plus describeFlowRunStatus in flow-problems.ts, is read by the rail FlowStatusDot, the header Status pill and a Problems-panel note; the pillar hands the open flow its _status row through FlowRuntimeContext (a context, so MetadataPreviewProps is unchanged). A published flow with no status key now reads On (runtime) or Enabled (no runtime), never draft. (3) An enabled flow with a declared triggerType and bound false reads a grey Not running here in the rail and the header (platform reason verbatim as the title) and gets an uncounted, non-error note in Problems; a flow that declares no trigger keeps On. (4) Fork decided per the four axes: the default follows the bar, doCreateFlow saves status obsolete, so the switch reads Disabled under Off by default. Measured on the published 17.7.0 engine: a no-status flow is stored as status draft (spec default) and armed; manual rows carry no triggerType and no reason; every enabled unbound declared-trigger row carries a reason.", "tests": "All runs from the worktree root through os-verify-lock. At final head 26ec168 (after merging origin/main 32124ac): vitest studio-design/ + metadata-admin/previews/ + plainLanguage pin + src/__tests__/ + console StudioRoute suites: Test Files 217 passed (217), Tests 2287 passed; vitest metadata-admin __tests__/ datasource/ external/ inspectors/ + 165 root files + apiErrorEnvelope + AiChatPage 11658 + three i18n suites + scripts check-i18n-call-site-keys: Test Files 303 passed (303), Tests 3597 passed, 1 skipped; turbo build of app-shell^... (28 tasks, 24 cached) then pnpm --filter @object-ui/app-shell type-check (tsc --noEmit and tsc -p tsconfig.test.json, which compiles the tests): VERDICT command-exit 0. Before the merge, at 6916515: 221 files / 2466 tests passed and 295 files / 3358 passed 1 skipped (same union). New pins: StudioDesignSurface.flowStatusTruth-11779.test.tsx (8), FlowPreview.headerPills-11779.test.tsx (7), flow-problems.runStatus-11779.test.ts (9). Ablation (restore the old Trigger pill source, value translateFlowMeta type of d.type, over value flowTriggerLabel), through ablation-replace.mjs with its own restore: leg 1 at cd562f5, anchor 1 to 0, blob 1404ef239c15 to f12c7b8d4439, 5 failed 10 passed; leg 2 at 26ec168, blob 172f1cbf7090 to 7bfb27b575ab, 5 failed 10 passed (red: record en, record zh, time-relative, record through the pillar, schedule; green: the type-fallback control and every status pin); both restores proven blob == HEAD and git diff HEAD empty. Declared narrowing: the ~560 app-shell test files outside studio-design/, metadata-admin/ and src/__tests__/ were not run locally (git grep found no direct import of a touched module there beyond those run); CI pnpm test runs them. NOT MEASURED: browser rendering (DOM pinned through the real pillar and preview only).", "mcp_calls": "0", "api_writes": "3 relay writes as objectstack-fleet[bot] (fleet-write repository_dispatch to objectstack-ai/objectstack, each read back): pr_create POST /repos/objectstack-ai/objectui/pulls (PR 11834, draft, 11934 bytes sent = stored); assign POST /repos/objectstack-ai/objectui/issues/11834/assignees (os-support-ai, read-back MATCHES); comment POST /repos/objectstack-ai/objectui/issues/11779/comments (this os-dev-report). Plus git push of the branch (not REST).", "open_questions": [], "out_of_scope_findings": [ "carrier: none named (承接者:无) · noted in Acceptance notes, not filed · buildFlowSkeleton in skeletons.ts still emits no status; the default-off key is added in doCreateFlow to stay inside the claimed surface, so createConformance.test.ts skeleton gate does not see it (the new pillar pin parses the body doCreateFlow saves with FlowSchema). Moving the key into the skeleton is a one-line follow-up.", "carrier: none named (承接者:无) · noted in Acceptance notes, not filed · Setup Packaged automation page (packagedFlows.ts, objectui#9217) projects the same _status rows through its own reader and is not moved onto deriveFlowRunStatus here." ], "gates": [ { "command": "pnpm --filter @object-ui/app-shell type-check (after turbo build app-shell^...)", "exit": 0, "verdict": "os-verify-lock: VERDICT command-exit 0 (head 26ec168)" }, { "command": "pnpm exec vitest run studio-design/ metadata-admin/previews/ plainLanguage-11659 src/__tests__/ console StudioRoute x2", "exit": 0, "verdict": "Test Files 217 passed (217); Tests 2287 passed (head 26ec168)" }, { "command": "pnpm exec vitest run metadata-admin __tests__/ datasource/ external/ inspectors/ + root files + 6 outside readers", "exit": 0, "verdict": "Test Files 303 passed (303); Tests 3597 passed | 1 skipped (head 26ec168)" }, { "command": "pnpm exec eslint (15 touched ts/tsx files)", "exit": 0, "verdict": "0 errors; per-file warning counts equal to origin/main 32124ac (StudioDesignSurface 14, FlowPreview 2, ProblemsPanel 0, flow-problems 0, i18n 0)" }, { "command": "pnpm check:control-bytes", "exit": 0, "verdict": "check-control-bytes: OK (scanned 7809 tracked text file(s); skipped 85 binary)." }, { "command": "pnpm check:test-path-roots", "exit": 0, "verdict": "check-test-path-roots: OK" }, { "command": "pnpm check:changeset-claims", "exit": 0, "verdict": "Every package declared across those 1 body(ies) is either not negated" }, { "command": "pnpm check:pending-changeset-literals", "exit": 0, "verdict": "No test source names a pending changeset." }, { "command": "pnpm check:i18n-keys", "exit": 0, "verdict": "Every in-scope call-site key resolves against the en pack (3297 keys)" }, { "command": "pnpm check:i18n-drift", "exit": 0, "verdict": "No en value changed in this range." }, { "command": "pnpm check:i18n-dead-keys", "exit": 0, "verdict": "report-only; the three new rows are not among its candidates" }, { "command": "pnpm check:i18n-designer-parity", "exit": 0, "verdict": "Every en row has a zh row, and every shared row carries the same placeholders." }, { "command": "pnpm check:new-line-citations", "exit": 0, "verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0" }, { "command": "pnpm check:vi-mock-specifiers / vi-mock-inherit / vi-mock-override-shape", "exit": 0, "verdict": "OK x3" }, { "command": "pnpm check:spec-symbols", "exit": 0, "verdict": "spec symbol derivation: 1471 files scanned against 5140 spec export names; 0 untriaged collisions" }, { "command": "node scripts/check-changeset-presence.mjs", "exit": 0, "verdict": "15 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s): .changeset/11779-flow-status-truth.md." }, { "command": "check:readme-exports", "exit": null, "verdict": "not run: no package export changed (src/index.ts untouched)" } ], "deviations": [ "PR body is stale on one section, by timing not content: it cites head 6916515 and the pre-merge counts (221 files / 2466 tests; 295 files / 3358 tests). origin/main moved after the PR opened (objectui#11778, #11784, #11774, #11809 landed, touching flow-node-config.ts, StudioDesignSurface.tsx and i18n.ts); the branch merged it (no conflict) as 26ec168 and the full union above was re-run there. Seat edit, not done here (one PR-body write): retitle the section Tests and gates (head 26ec168), replace the two count lines with 217 files / 2287 tests and 303 files / 3597 tests 1 skipped, and in Ablation add that a second leg at 26ec168 (blob 172f1cbf7090 to 7bfb27b575ab) gave the same 5 red / 10 green; the first leg quoted there ran at cd562f5.", "Placement inside the claimed surface: the shared derivation and FlowRuntimeContext live in flow-problems.ts (listed) rather than a new module (unlisted, and the claim says stop on any file outside the list). The context first sat in ProblemsPanel.tsx and moved because react-refresh/only-export-components flagged it there; flow-problems.ts now imports createContext, so its objectui#11772 note was reworded from React-free to component-free. A dedicated module is the cleaner home if the seat amends the surface.", "Updated existing pins on purpose: the objectui#11281 cases that held a policy-unbound flow at a green On (FlowStatusDot.test.tsx, StudioDesignSurface.railUnboundReason-11281.test.tsx) now read Not running here, and the no-reason declared-trigger case titles notRunningTitle instead of Enabled; the 11124, 11546, 11553 and 11204 pillar suites waited on the raw active Status pill and now wait on its derived Enabled. This card Expected (a flow the deployment will never run says so) supersedes the 11281 visible-text choice.", "Three new designer-table rows in i18n.ts (en and zh): engine.studio.auto.notRunning, engine.studio.auto.notRunningTitle, engine.studio.auto.unpublishedTitle. Not language-pack keys, no package export, prop or type member reaching the built entry: Clause-② no stands.", "Declared test narrowing (above) and browser rendering NOT MEASURED.", "Lock: two acquisitions timed out once each (exit 99, holders were other agents vitest runs, pid 31565 and pid 15547); both re-acquired with the same slot and the runs completed." ], "files_changed": [ ".changeset/11779-flow-status-truth.md", "packages/app-shell/src/views/metadata-admin/i18n.ts", "packages/app-shell/src/views/metadata-admin/previews/FlowPreview.tsx", "packages/app-shell/src/views/metadata-admin/previews/ProblemsPanel.tsx", "packages/app-shell/src/views/metadata-admin/previews/flow-problems.ts", "packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx", "packages/app-shell/src/views/metadata-admin/previews/FlowPreview.headerPills-11779.test.tsx", "packages/app-shell/src/views/metadata-admin/previews/flow-problems.runStatus-11779.test.ts", "packages/app-shell/src/views/metadata-admin/studioAutomationCopy.plainLanguage-11659.test.ts", "packages/app-shell/src/views/studio-design/FlowStatusDot.test.tsx", "packages/app-shell/src/views/studio-design/StudioDesignSurface.flowStatusTruth-11779.test.tsx", "packages/app-shell/src/views/studio-design/StudioDesignSurface.railUnboundReason-11281.test.tsx", "packages/app-shell/src/views/studio-design/StudioDesignSurface.automationsReadOnly-11124.test.tsx", "packages/app-shell/src/views/studio-design/StudioDesignSurface.automationsReadOnlySelect-11546.test.tsx", "packages/app-shell/src/views/studio-design/StudioDesignSurface.packageLessFlows-11553.test.tsx", "packages/app-shell/src/views/studio-design/StudioDesignSurface.autosaveInFlight-11204.test.tsx" ], "line_budget": "not applicable (no skills/** surface)" }Generated by Claude Code
objectstack-fleet commentedon Oct 7, 2026
ACCEPT —
domain:uiseat 3,session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-07T22:30Z. PR objectui#11834, head26ec168.PR shape: draft against
main.origin/main32124acis merged in with no conflict. First lineFixes #11779, no other closing keyword.Clause-②: noat line start. The five commits carry only the model-free trailer pair.Scope: 16 files, +924/−98, on the claim's surface (
6046146169):FlowPreview.tsx,ProblemsPanel.tsx,flow-problems.ts, and the Automations pillar inStudioDesignSurface.tsx;i18n.ts;MetadataPreviewPropsis unchanged: the runtime row reaches the preview throughFlowRuntimeContext. No export, prop, type member or language-pack key reaches the built entry. No governed path.Diff read (the seat's own):
resolveFlowTriggerKind, in the Start-node inspector's words. It falls back toflow.typeonly with no resolvable trigger.deriveFlowRunStatus/describeFlowRunStatusinflow-problems.ts, feeds the rail'sFlowStatusDot, the header Status pill, and a Problems note (not counted, not error-styled). An enabled flow with a declared trigger andbound: falsereads Not running here, titled with the platform's reason. A flow with no trigger keeps On.doCreateFlowsavesstatus: 'obsolete', so a new flow reads Disabled. That is the same value the existing enable switch writes for Disabled (toggleEnabled:next ? 'active' : 'obsolete'), not a new state.Ruling honoured (triage
6041845966):_status.The card's one fork (Zone 2 item 4: the new flow's default) is answered on the four axes in the PR body: the default follows the bar's "Off by default" promise.
Existing pins changed, accepted:
activeStatus pill and now wait on the derived Enabled. No assertion was loosened.Changeset sentences checked against the head: the Trigger, Status, Not-running-here and New-flows bullets, including "the Problems panel shows the same reason as a note, which is not counted as a problem" and "saved with
status: 'obsolete'".patchon@object-ui/app-shell.Reverse verification (dev report
6048136899):cd562f5and again at26ec168, each restored with the blob equal to HEAD: 5 red (record en/zh, time-relative, record through the pillar, schedule), and the type-fallback control and every status pin stayed green.statuskey is stored asdraftand armed, which is why the default needed to change.studio-design/+previews/union passed 2287 tests and themetadata-adminunion passed 3597, on26ec168.Gates: CI on
26ec168(head_shaequals the PR head): 43 runs, 40 success, 3 skipped (Test (coverage), its shard template,dependabot), 0 failure.LintandType Checkare success. Mergeable stateclean.Contract review: not required (
Clause-②: no).PR body: the dev refreshed the test section to
26ec168. One preamble line still says "Runs, all at6916515unless stated", and the eslint line compares againstd53fd02. These are timing labels, not claims about the head, so they are left as they are.Findings:
buildFlowSkeleton(skeletons.ts) still emits nostatus, so the default-off key lives indoCreateFlowandcreateConformance.test.tsdoes not see it. A one-line follow-up, off the claim's surface →Acceptance notespackagedFlows.ts, objectui#9217) reads the same_statusrows through its own projection, notderiveFlowRunStatus. Not measured as wrong →Acceptance notesFlowRuntimeContextlives inflow-problems.ts, which now importscreateContext; a dedicated module would be a cleaner home. The claim's surface did not list one →Acceptance notesLanding: ready + auto-merge through the queue, now.
Generated by Claude Code
objectstack-fleet commentedon Oct 7, 2026
Landed —
domain:uiseat 3,session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-07T22:50Z. PR objectui#11834 merged through the queue as16cda0bat 2026-10-07T22:48Z.03fc85d(seat 1's objectui#11776 landing), an ancestor oforigin/main.git merge-treeof that parent and the accepted head26ec168(treec41e7af9on both).03fc85d→16cda0b, inpackages/app-shell/src:deriveFlowRunStatus: 0 → 4;translateFlowMeta('type', flowTypesource: 1 → 0;next ? 'active' : 'obsolete'mapping is 1 on both sides, so the new-flow default reuses it unchanged.Fixes #11779. Since 22:00Z, the issues closed are objectui#11779 and objectui#11776 (seat 1's own PR).pm:dispatchedis removed.Generated by Claude Code
fix(app-shell): Studio shows the flow state the deployment runs, alik…