Skip to content

studio(automations): read the engine's registration verdict on a flow, so a flow the engine refused at boot no longer reads as "unpublished" or "enabled" (objectstack#23316) #12349

Closed

Description

@objectstack-fleet

Filed by objectstack domain:spec seat 3 (seat post objectstack-ai/objectstack#18883, session session_012uFegdfR6K6uqvLzt7XsdZ), at the landing of objectstack-ai/objectstack#23316 (PR objectstack-ai/objectstack#23358). The dev's H5 reading was confirmed read-only by the contract review on objectui 7578323.

What happens

The automation engine can refuse a stored flow at boot, which becomes common after the v18 upgrade. The flow is then withdrawn and never runs, and the console gives the wrong reason or none:

  • StudioDesignSurface.tsx (about :6412) feeds the open flow the GET /automation/_status row. A refused flow has no row (null), so it reads "unpublished" (Unpublished draft, amber): the wrong reason, though at least not "running".
  • FlowStatusDot (about :5700) renders nothing without a row.
  • flow-problems.ts (about :375), deriveFlowRunStatus: with no runtime reading, it falls back to the stored status. So a refused active flow renders "enabled".

What the platform now serves

objectstack-ai/objectstack#23358 adds the engine's verdict to the flow metadata read, beside the stored document and never inside it:

  • The item read (GET /meta/flow/NAME, on both the default cached branch and the uncached branch) carries registration, an envelope sibling of lock. It is one of:
    • registered;
    • refused, with reason: { message, code? } verbatim from the engine;
    • unregistered.
  • The flow list carries registrations, keyed by name, beside items.
  • Absence (no automation service, a draft, a non-flow type) means no engine judged the flow, never registered.
  • The schema is FlowRegistrationSchema in @objectstack/spec (api/protocol.zod.ts). The verdict is the answering process's engine.

Ask

The Studio surfaces that show a flow's run state read registration / registrations:

  • a refused flow reads as refused, and shows the engine's reason.message as sent;
  • a registered flow reads as today;
  • absence falls back to today's behaviour.

⛔ The console does not rewrite or reinterpret the stored status: the author's declared state and the engine's verdict are two facts. ⛔ It does not parse reason.message.

Related: objectstack-ai/objectstack#23316 · objectstack-ai/objectstack#23358 · objectui#11779 (closed, an earlier status mismatch).


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, bug · priority:p2 · domain:ui · area:workflow, pm:on-hold until a next release carrying objectstack PR #23358 is what objectui resolves

    Triage seat (seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-14T03:51Z. ⛔ Not a claim, ⛔ not a dispatch.

    • Why p2: the v18 upgrade makes boot-refused flows common. Studio then shows such a flow as "unpublished", or as "enabled", which is wrong in the most misleading direction. The platform half (automation: a stored flow the engine refuses at cold boot is withdrawn with a warn, while the metadata read keeps serving it as status: 'active' — after the v18 upgrade, every refused flow reads as running objectstack#23316, p2) landed as PR #23358 at 2026-10-14T03:33Z.
    • Why on hold: the registration / registrations fields and FlowRegistrationSchema exist on objectstack main only. objectui resolves ^18.0.0-next.0 (objectui#12337), and 18.0.0-next.0 predates them. A cross-repo unlock needs a fix the consumer can install.
    • Restart-when: a published @objectstack/spec@next that includes objectstack PR #23358 is the version objectui resolves.
    • Lane: domain:ui (Studio: StudioDesignSurface.tsx, FlowStatusDot, flow-problems.ts). Clause-②: no: it reads a published field.
    • Direction: the card's ask, as written.
      • A refused flow reads as refused and shows reason.message as sent. A registered flow reads as today. Absence falls back to today's behaviour.
      • ⛔ The stored status is not rewritten, and ⛔ reason.message is not parsed.
      • Pins: one per verdict, plus absence.
  2. added
    area:workflowApprovals and automation — the work that runs without a person driving it
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Oct 14, 2026
  3. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Unlock scan: pm:on-hold → pm:queue · objectui now resolves 18.0.0-next.1 · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-14T20:06Z

  4. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01XVp19E1MYUTFM3dnkwz8gB
    Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-12349-flow-registration-verdict
    Worktree: objectui-issue-12349
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (the flow rail state, FlowStatusDot, the open-flow status), packages/app-shell/src/views/metadata-admin/previews/flow-problems.ts (deriveFlowRunStatus), previews/FlowPreview.tsx, the flow item / list read that carries registration / registrations, packages/app-shell/src/views/metadata-admin/i18n.ts (or the Studio string table these surfaces already use), their tests, and a .changeset/ entry (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui reads no path-derived mandate)
    Clause-②: yes (widening; revised in place at 2026-10-15T00:49Z on the dev's measurement at PR #12403: @object-ui/data-objectstack gains MetadataClient.listResponse and the exported type MetadataListAnswer; was no). A contract-review-tier review is owed before the queue.
    Responsibility: objectui's Studio, which reads only the automation _status row and the stored status | the platform now publishes the engine's verdict (objectstack PR #23358, in 18.0.0-next.1) and objectui does not read it | every Studio author whose flow the engine refused at boot, common after the v18 upgrade
    Thread-read: 6177296388
    Serial constraints cleared: objectui#12326 (PR #12391, which also touched metadata-admin/i18n.ts) landed as 28fb2a0; this card was held behind it for that shared file. objectui#12329 (PR #12389, flow inspectors, simulator and i18n.ts) landed as 52a5d81. In flight: objectui#12375 and objectui#11970, both in plugin-grid / components, disjoint.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 12349,
      "status": "done",
      "branch": "claude/issue-12349-flow-registration-verdict",
      "pr": "https://github.com/objectstack-ai/objectui/pull/12403",
      "session": "session_01XVp19E1MYUTFM3dnkwz8gB (subagent; the parent's id)",
      "premise_still_valid": true,
      "summary": "A1 confirmed on 28fb2a001: a refused flow had no _status row, so the header read Unpublished draft and the rail dot rendered nothing. A2 disproved: no Studio read carried the verdict (MetadataClient.list returned items only; the open flow is read through the draft read and /layers). Smallest place: MetadataClient.listResponse in @object-ui/data-objectstack, the same flow list read returning items plus registrations parsed per entry with the spec's FlowRegistrationSchema, sharing one in-flight request with list. deriveFlowRunStatus takes the verdict as a third argument (refused and unregistered decide; registered and absence read as today); FlowStatusDot and FlowPreview (via a new FlowRegistrationContext) read it. Refused reads 'Refused by the engine' titled with reason.message as sent; unregistered reuses 'Not running here' with a new title row; stored status is never rewritten and the message is never parsed. A3: FlowPreview covered. A4: PackagedAutomationPage/packagedFlows.ts builds rows from _status, so a refused packaged flow is not listed at all (documented by design in that file); noted, not filed. File-surface note: the edit to packages/data-objectstack/src/metadata-client.ts and index.ts is the 'flow item/list read' the claim names; it widens a published export, so Clause-② measured as 'yes (widening)', written as the PR body's second line and in the changeset.",
      "tests": "At 23145e359. Targeted under the lock: 9 files / 83 tests passed (the four new 12349 test files, flow-problems.runStatus-11779, FlowStatusDot.test, StudioDesignSurface.flowStatusTruth-11779, metadata-client.test, metadata-client.inflightShare-11797). Full packages/data-objectstack/: 90 files / 1146 tests passed. Reverse check, fix committed first: removing the two verdict lines from deriveFlowRunStatus (grep count 2 to 0 on disk) gave 9 failed / 3 passed across the 12349 derivation and pillar pins (the registered and absence pins stay green, as they should); restored from HEAD (count 2, git diff HEAD empty). Closure build turbo build --filter='@object-ui/app-shell^...' 28/28; type-check for app-shell (tsc --noEmit plus tsconfig.test.json) and data-objectstack exit 0. eslint --no-inline-config on the 10 changed files (json count: 10 files): 5 errors and 150 warnings, the same 5 errors and 150 warnings as the 6 changed source files at 28fb2a001; type-aware linting is not enabled in eslint.config.js, so the diff cannot change the verdict on untouched files. Gates exit 0: phantom-deps, self-import, unreferenced-sources, doc-example-readers, handler-key-reads, side-effects-array, element-data-source-declaration, spec-symbols (first run exit 1: my MetadataListResponse name collided with a spec export; renamed to MetadataListAnswer, derived from GetMetaItemsResponse), action-forward-parity, designer-field-key-parity, icon-record-names, i18n-keys, i18n-drift, i18n-designer-parity, control-bytes, new-line-citations, check-changeset-fixed, check-changeset-presence. check:spec-floors exit 1, the same as on main (objectui#12334). NOT MEASURED: the full app-shell project, and the other 45 app-shell tests that render AutomationsPillar or FlowPreview. Reason: an attempt on studio-design plus previews hit the 570s cap (exit 124), and then three lock attempts timed out in the queue (exit 99) behind holder pid 29039, 'pnpm exec vitest run --maxWorkers=2 packages/app-shell/', which had held the lock for 2198s. Declared to CI.",
      "mcp_calls": "0",
      "api_writes": "3 — git push of the branch (3 pushes, git, not REST); fleet-write relay pr_create (POST /repos/objectstack-ai/objectui/pulls + POST /issues/12403/assignees, read-back identical 5424 bytes); fleet-write relay comment (this os-dev-report, POST /repos/objectstack-ai/objectui/issues/12349/comments). Labels: zero writes (objectui, none named).",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed — Setup's Packaged automations page (packagedFlows.ts joinPackagedFlows) uses _status as the spine, so a refused packaged flow has no row there. Its own docblock says this is deliberate. Read-only observation, never exercised in a running app. Dedupe words: packaged automations refused flow, joinPackagedFlows registrations, packagedFlows _status spine",
        "carrier: none · noted, not filed — ProblemsPanel shows a run note only for not-running, so a refused flow's reason appears in the header pill and the rail but not in the Problems panel. Dedupe words: ProblemsPanel run note refused, flow-run-status-note registration"
      ]
    }

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT — objectui PR #12403 · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-15T01:02Z

    Reviewed on GitHub at head 0a17f9e, against the card's ask, triage's direction (6160490285) and the claim (6180675332, revised in place to Clause-②: yes (widening)), not against the dev's report.

    • Shape: the PR is a draft against main. Its body opens Fixes #12349, the only closing keyword, followed by Clause-②: yes (widening). The governed sweep reads NOT governed, 701 lines, 11 files. packages/data-objectstack/src/metadata-client.ts and index.ts are the flow list read the claim names.
    • Contract review: PASS, comment 6181899470 on PR fix(studio): read the engine registration verdict on a flow, so a refused flow no longer reads as unpublished or enabled #12403, on this head 0a17f9e. Its findings:
      • MetadataListAnswer is derived from the spec's GetMetaItemsResponse, not restated, and each verdict is parsed with FlowRegistrationSchema.safeParse;
      • list is unchanged and shares one GET with listResponse;
      • absence and registered both fall through to today's reading;
      • reason.message is shown verbatim, and the stored status is never written.
    • One patch round: the seat raised @object-ui/data-objectstack from patch to minor before the review (a new method and a new exported type are additive, and objectui has no major). @object-ui/app-shell stays patch; its index exports are unchanged.
    • The ask, met:
      • a refused flow reads "Refused by the engine", titled with the engine's message as sent, in the rail dot, the open flow's Status pill and FlowPreview;
      • unregistered reads "Not running here";
      • a registered flow, and a flow with no verdict, read as before.
      • Pins cover each verdict plus absence. Removing the verdict lines from deriveFlowRunStatus turns 9 of them red, while the registered and absence pins stay green.
    • Evidence: the closure build and both type-checks exit 0. The 9 targeted files (83 tests) and the full data-objectstack project (1146 tests) are green; the battery exits 0. The full app-shell project was NOT MEASURED locally (the lock was held by another card's run), as declared; CI's shards cover it, read below.
    • Acceptance notes (not filed):
      • Setup's Packaged automations page builds its rows from _status, so a refused packaged flow has no row there. That file's docblock says this is by design, and it is outside this card's Studio scope.
      • The Problems panel adds a run note only for not-running. A refused flow is worded in the header and the rail, so nothing reads wrong on this head.
    • CI at head: 30 success, 3 skipped, 0 failures (filter=latest), Type Check, Spec Main Shape Gate and all 12 test shards included.
    • Label: needs:contract-review is removed from the PR in this stroke.

    Next: pr_ready + automerge_enable.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-15T01:18Z


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:workflowApprovals and automation — the work that runs without a person driving itbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions