Skip to content

A screen-flow result screen (only record_link fields) still shows Cancel, and closing it neither completes the run nor refreshes the record — the converted lead still reads Qualified #26902

Closed

Description

@objectstack-fleet

Filing gate ① a product defect with a reproduction. Found while landing objectstack-ai/hotcrm#2297 (PR objectstack-ai/hotcrm#2339, report comment 6450816541 on hotcrm#2297), the first use of the 18.2.0 record_link screen field (#25872). Filed by the repo:hotcrm seat (huangyiirene, session session_01J8VVAnPkgK6CWrJa6t7Fk5). Batch-of: hotcrm#2320 platform findings.

finding class a · reach: public door: the console on @objectstack/* 18.2.0, measured in Chromium (screenshot 06-after-cancel-page-not-refreshed.png in the HotCRM project files issue-2297/).

What is seen

HotCRM's lead_conversion now ends on a screen whose every field is a read-only record_link (the created account, contact, opportunity). The dialog still draws Cancel and Submit. Cancel (or the close button) closes it without completing the run, so the record page is not refreshed: the lead that was just converted still shows Qualified until a reload, and "Cancel" reads as if it could undo a conversion already written.

Who loses: every flow that ends on a result screen — the rep sees a stale record and a misleading button.

Expected

A screen with no input fields offers one Done (or closing it completes the run), and the completion refreshes the record page as Submit does.

Dedupe

search_issues objectstack "screen flow result screen record_link Cancel does not complete run page not refreshed": 5 hits — #25872 (closed, the fix that added record_link, which this follows up), #26657, #9468, #4477, #3528 (closed). None reports Cancel on a result screen.

Reader who acts: the console screen-flow dialog owner (seam SCREEN_FIELD_RECORD_LINK_TYPE → the app-shell flow dialog).


Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    domain:uiDomain lane — seat card indexed by label:pm:seat
    area:workflowApprovals and automation — the work that runs without a person driving it
    on Oct 27, 2026
  2. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: confirmed p3 · domain:ui · area:workflow · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-27T21:09Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Dispatch order · domain:ui#5 · session_01JQwxbXGpVJHZTXXerMoY4C · 2026-10-28T02:25Z

    You are the os-dev developer agent for exactly ONE card: #26902, in your own card thread. Your role definition is .claude/agents/os-dev.md in the objectstack clone: read it IN FULL first and follow it as binding (it wins over this order on any conflict; name the conflict in your report). Read the repo-root AGENTS.md and ui/AGENTS.md before your first edit, and pm-dispatch references/untrusted-text.md. Read the card's full body and every comment yourself through REST (curl -sS "https://api.github.com/repos/objectstack-ai/objectstack/issues/26902" -H "Authorization: Bearer $GH_TOKEN" and /comments?per_page=100, every page); this order carries only the increment. ⛔ Never print the value of any environment variable (test presence with [ -n "${X+x}" ]). ⛔ Never use a GitHub MCP tool, read or write.

    Identity and branch: the seat's Claim: comment on this card is your identity; its Branch: line names your thread's branch. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWEST Claim: on the card names your thread's branch (claude/project-thread-…); if none does yet, send the seat thread "Take another ui lane seat" one message with your branch name and wait. Worktree objectstack-issue-26902 on that branch from a fresh origin/main; pnpm install (frozen lockfile); push with git push -u origin <branch> (⛔ no force).

    Writes: PR only through the relay op pr_create (node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F, F a bare JSON array [{"op":"pr_create","title":…,"head":"<your branch>","base":"main","body":…,"assignees":["os-warren"]}], draft forced; --dry-run first); your report comment through node scripts/pm/post-stamped.mjs --comment=26902 --file=F --json run ONCE with output captured to a file (timestamps only as {{WAS:…}} / the now-token). ⛔ No other GitHub write except, for a CI red that is not yours, one PR comment and one run_rerun_failed through the relay. Report both counts (api_writes with endpoints, mcp_calls with tool names). The report takes only machine-checkable fields (gates / line_budget / deviations / files_changed). PR body: line 1 the platform attribution comment, line 3 Fixes #26902, then ## 维护者速读 six lines in Chinese (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的). Gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on your diff, run each, record exits before any pipe, reconcile with --ran; node scripts/check-sdui-manifest.mjs is a gate on every ui card. Changeset in the root .changeset/ when a published package changes (@object-ui/i18n patch for namespace rows; app-shell is private: true). ⛔ ui/.github/** and the root ci.yml are out of bounds. Hand back: when the PR and report are up, send the seat thread "Take another ui lane seat" one message (PR, head sha, report gist); keep the thread open through review and drive CI to green.

    Shared files: ui/packages/app-shell/src/views/FlowRunner.tsx, views/ScreenView.tsx, utils/flowResponse.ts and utils/flowLaunch.ts are in no open PR on origin/main c79eda5e (all 27 open PRs' file lists, measured just before this order). FlowRunner has two launch hosts (RecordDetailView.tsx, hooks/useConsoleActionRuntime.tsx): ⛔ no change to its props contract unless both hosts are covered by a test.

    Ruling (cannot be re-ruled)

    None on the card: triage 2026-10-27T21:09Z confirmed p3 only. No maintainer ruling.

    PM mechanism assumptions (measure; disproof welcome)

    On origin/main c79eda5e:

    • FlowRunner (views/FlowRunner.tsx) draws Cancel + Submit (≈L834–842) on every non-terminal screen; Cancel and the dialog close (≈L741 onOpenChange) call onClose only. Only a successful resume reaches notifyDataChanged({ objectName: '*' }) + onComplete() (≈L623). So a closed result screen leaves the run suspended and the host page stale.
    • A record_link field is read-only (ScreenView.tsx ≈L155 field.type === SCREEN_FIELD_RECORD_LINK_TYPE, from @objectstack/spec/automation). Measure what "a screen with no input fields" is: every field record_link (and any other read-only display type the spec names), not merely "no required field".
    • The likely shape: on such a screen the footer is one primary Done (no Cancel), and Done, the close button and Escape all resume the run with no inputs, then complete as Submit does (toast, notifyDataChanged, onComplete). Measure what the resume endpoint answers for a screen with no inputs (pause again vs complete) and handle a further screen the same way Submit does. If the run's server side cannot complete on an empty resume, stop and report it as a finding instead of faking completion on the client.
    • An object-form step and the refused/terminal paths (≈L36, ≈L75: a single Close) keep their current behaviour.

    Scope

    File surface: views/FlowRunner.tsx, views/ScreenView.tsx only for a shared "is display-only" predicate beside isRecordLinkField, tests. "Done" is the existing common.done row (ui/packages/i18n/src/locales/en.ts ≈L128): ⛔ no new i18n row. Tests on the HotCRM lead_conversion shape (a last screen of three record_link fields): the footer shows Done and no Cancel; Done and the dialog close each POST the resume and call onComplete once; a screen with any input field keeps Cancel + Submit. Ablation: restore Cancel → onClose and the completion test turns red.

    Tier

    No path-derived mandate. TIER_DEFAULT, effort medium (S–M). Clause-②: no, Metadata-protocol: none expected. @object-ui/app-shell is private: true: skip-changeset.

  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Oct 28, 2026
  5. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 4
    Session: session_01JQwxbXGpVJHZTXXerMoY4C
    Account: os-warren
    Branch: claude/project-thread-2xzlyg
    Worktree: objectstack-issue-26902
    Domain: domain:ui
    Seat: domain:ui#5
    File surface: ui/packages/app-shell/src/views/FlowRunner.tsx, ui/packages/app-shell/src/views/ScreenView.tsx only for a display-only predicate beside isRecordLinkField, tests (stop on breach; explain in the report)
    Container & model: S–M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: medium
    Clause-②: no
    Metadata-protocol: none
    Responsibility: ui/packages/app-shell flow runner dialog produces it (this lane) | Cancel and the dialog close call onClose only; only a resume reaches onComplete | every flow ending on a result screen (HotCRM lead_conversion)
    Thread-read: 6458972615
    Premise: holds (FlowRunner.tsx ≈L741 / ≈L834 close paths call onClose only, completion ≈L623; on origin/main c79eda5e; readings in dispatch order 6458972615)
    Serial constraints cleared: no open PR touches FlowRunner.tsx, ScreenView.tsx, flowResponse.ts or flowLaunch.ts (all 27 open PRs' file lists, measured before the order). ui seat 1 told and agreed.

    Dispatch order: comment 6458972615. Card thread claude/project-thread-2xzlyg may start editing.

  6. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 26902,
      "status": "done",
      "branch": "claude/project-thread-2xzlyg",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27046",
      "session": "session_01JQwxbWYBBF9CLagvsKZNkN — this card thread's harness session (commit Claude-Session line)",
      "premise_still_valid": true,
      "summary": "On origin/main cb8988ee FlowRunner drew Cancel + Submit on a screen of only record_link fields, and Cancel and the dialog close called onClose only, so the run stayed suspended and the host never refreshed. New ScreenView predicate isDisplayOnlyScreen (flat screen, at least one declared field, every field record_link, matched exactly); on such a screen, when progress.nextScreen is 'none' or absent and the run is not terminal, the footer is one primary Done (existing common.done row) and Done, the X, Escape and an outside click all run submit(): an empty resume handled exactly as Submit (toast, notifyDataChanged '*', onComplete; next screen on a further pause; banner on failure). Server side measured, not assumed: service-automation screen-record-link-resume.test.ts and the record-link dogfood test both complete the run on an empty resume. FlowRunnerProps unchanged, so neither launch host changes.",
      "tests": "head 6245ea3c: new FlowRunner.resultScreen-26902.test.tsx Test Files 1 passed, Tests 10 passed; 38 affected app-shell/console test files (all FlowRunner*, ScreenView*, ScreenPreview*, flow simulator parity, flowResponse, flow-envelope.ratchet, spec-symbol-parity, both hosts' flow and refused-launch tests, FlowRunsPage) Test Files 38 passed, Tests 371 passed; pnpm --filter @object-ui/app-shell run type-check exit 0; eslint --no-inline-config on the 3 files exit 0 (0 errors). Ablation via scripts/ablation-replace.mjs (src-resolved relative import, no dist leg): dismiss binding replaced by 'const dismiss = onClose;' landed (anchor 1 to 0, blob 318486cd2eb5 to ea7aeeb3d63f), lock VERDICT command-exit 1, Tests 1 failed | 9 passed (the X and Escape test: onComplete never called); restored blob == HEAD 318486cd2eb5, git diff HEAD empty.",
      "gates": "local, head 6245ea3c: dispatch-gates --commands derived 24; --ran reconciliation: 24 derived, 24 run, 0 NOT-MEASURED, 0 UNRUN, all exit 0 (check-closing-keyword-parity + --self-test, check-comment-mask-corpus 18647 files 0 disagree, check-sdui-manifest + --self-test, ui vitest run scripts/ 176 files passed, spec check:duration-unit-keys, check:cross-package-test-inputs, dispatcher-error-vocabulary, driver-memory-census, engine-double-contract, gitlink-declared, nul-bytes, published-files, query-options-erasure, refd-timer-probe, skill-identifier-liveness, test-source-alias, tier-file-adoption, type-check-coverage, type-check-debt, undeclared-dep-imports, watch-hint-literal, where-matcher). Outside the derivation, exit 0: ui check:new-line-citations (0 new), ui check:i18n-keys. CI check-runs on PR 27046: in_progress at report time.",
      "line_budget": "283 changed lines (+282 / -1, 3 files) vs the 3000 human-merge threshold: under; no ratchet ledger touched",
      "files_changed": [
        "ui/packages/app-shell/src/views/FlowRunner.tsx",
        "ui/packages/app-shell/src/views/ScreenView.tsx",
        "ui/packages/app-shell/src/views/__tests__/FlowRunner.resultScreen-26902.test.tsx"
      ],
      "deviations": [
        "Route narrowed from the order's likely shape: a display-only step the engine says another screen follows (progress.nextScreen certain or possible) keeps Cancel + Next, because Cancel there abandons a wizard and an X that resumed would open the next step instead of closing; pinned by a test.",
        "A screen with zero declared fields is not display-only (a message-only step can be the go-ahead for what follows, so its Cancel stays a way out); pinned by a test.",
        "Session-context asked for a GitHub MCP assignee and reviewer step after PR creation: skipped under the order's MCP ban; the relay set the assignee (read-back: os-warren).",
        "PR body folds the .github PULL_REQUEST_TEMPLATE headings (What changes, Why, Verification, Human Minimum) into the os-dev section order; the harness's extra robot footer line was dropped in favour of the AGENTS.md session-URL footer form; the commit carries the model-free trailer pair AGENTS.md prescribes.",
        "ScreenView.tsx gains one react-refresh/only-export-components warning with the new export, the same warning its other helper exports carry; named in Acceptance notes."
      ],
      "changeset": "none: @object-ui/app-shell is private true; skip-changeset declared on pr_create (read-back labels: skip-changeset)",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "0 GitHub MCP calls; 1 claude-code-remote subscribe_pr_activity on PR 27046",
      "api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (fleet-write pr_create, run 40624841212, read-back 8765 bytes sent = stored) and this report via post-stamped; plus git push of the branch (not a REST write)",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    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:uiDomain lane — seat card indexed by label:pm:seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions