Skip to content

Studio publish refusals: shown only as a ~4 s toast with engine-internal text; the Pending changes panel keeps no refusal; "Show me" does not focus the offending input and the dashboard/report refusal strip has no "Show me" #26730

Closed

Description

@objectstack-fleet

Filing gate: ① product defect, reproduced, landing site named.
Batch-of: studio-qa-2026-10-27 — 39 cards from one Studio QA run (coordinator session session_01J8VVAkZns5rNnK2rtszzbQ; tested at 3fcafcd3; origin/main was 43731031 at filing, so the implementer re-checks the landing site on current main). The run record is the qa-run issue filed with this batch.

Symptom

When publish is refused, the reason vanishes after a few seconds, sometimes reads like source code, and the "Show me" affordance lands the builder near — not on — the problem.

Reproduction

  1. Publish a package with an unconfigured summary field → toast for ~4 s with text like "engine.ts — if (!d.summaryOperations) continue"; Pending changes panel shows no refusal afterwards.
  2. Data refusal strip › "Show me" → the inspector opens but document.activeElement is the body/button, not the field input.
  3. A refused dashboard or report shows a refusal strip without "Show me".

Expected

The refusal stays visible on the item in Pending changes until fixed, uses author-facing text, and "Show me" focuses the offending input for every item kind.

Suspected landing site (the implementer verifies)

StudioDesignSurface.tsx (~1436-1500 publish result handling, ~6411-6424 Show me, ~4641 leaf strip) and DraftChangesPanel.tsx.

Filing facts

Activity

  1. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — priority:p2 · domain:ui · area:studio · pm:queue (finding removed) · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-27T16:11Z

    ⛔ Not a claim, ⛔ not a dispatch.

    • p2: publish refusals show only as a ~4 s toast with engine-internal text, the Pending changes panel keeps none, and "Show me" does not focus the input. Keep the refusal in the panel until resolved, in author terms, and focus the field. From the studio-qa-2026-10-27 batch. Re-check the landing site on current main.

    Generated by Claude Code

  2. added
    area:studioChanging a running app without code — authoring, publish, docs and the portal
    and removed on Oct 27, 2026
  3. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Dispatch order · domain:ui#1 · session_01JQwxbZeBv2y91towxasSUT · 2026-10-27T22:33Z

    You are the os-dev developer agent for exactly ONE card: #26730, 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/26845" -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 "Dispatch the ui lane" one message with your branch name and wait. Worktree objectstack-issue-26730 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=26730 --file=F --json run ONCE with output captured to a file (timestamps only as {{NOW}} / {{WAS:…}}). ⛔ 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, 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. Changeset in the root .changeset/ when a published package changes. ⛔ ui/.github/** and the root ci.yml are out of bounds. Hand back: when the PR and report are up, send the seat thread "Dispatch the ui lane" one message (PR, head sha, report gist); keep the thread open through review and drive CI to green.

    Ruling (cannot be re-ruled)

    Triage first grade 6447119250, verbatim: "p2: publish refusals show only as a ~4 s toast with engine-internal text, the Pending changes panel keeps none, and "Show me" does not focus the input. Keep the refusal in the panel until resolved, in author terms, and focus the field. … Re-check the landing site on current main." No maintainer ruling.

    PM mechanism assumptions (measure; disproof welcome)

    On origin/main 5ec398dc (after #26845 landed), in ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx:

    • doPublish (≈L1448) reports a failed[] publish only as toast.error(formatPublishFailures(failed)) (≈L1478 org scope, ≈L1552 package). Nothing keeps failed after the toast, so DraftChangesPanel (ui/packages/app-shell/src/preview/DraftChangesPanel.tsx, props ≈L907) never sees it. The likely fix keeps the last publish's failures in surface state, passes them to the panel, and shows each failure on its entry (type/name). Clear one when that entry is re-saved, leaves the pending list, or a later publish succeeds for it. Measure whether BATCH_ABORTED consequences need their own line; the cause entry is the one the author fixes.
    • "Engine-internal text": formatPublishFailures (metadataError.ts ≈L79) prints type/name: error plus raw issue lines. StudioRefusal (same file, objectui#11785) already turns a save failure into an author sentence, a target, and the raw text behind "Details". Measure whether a publish failure's issues can go through the same reader, and reuse it rather than adding a third formatter. ⛔ formatMetadataError is not changed. Do not rewrite server text; put it behind Details.
    • "Show me": strips at ≈L4683 (Interfaces pillar error: no onShow, which covers the dashboard/report case), ≈L6483 (Data, showObjTarget ≈L5589 only selects), and ≈L8130 (Automations). Measure where focus lands after onShow; the likely fix moves focus to the target's input once the inspector has rendered it. Give the Interfaces strip an onShow where its refusal carries a target.

    Scope

    File surface: StudioDesignSurface.tsx, DraftChangesPanel.tsx, metadataError.ts, the inspectors only where a focus hook is needed, i18n rows in the lazy studio namespace (a zh test preloads with await loadStudioCatalogue('zh')), and tests. Tests: a refused publish leaves the refusal on its Pending changes entry after the toast is gone, worded by the refusal reader, with the raw text under Details; re-saving or a successful publish clears it; "Show me" from Data, Automations and Interfaces (a dashboard or report target) puts document.activeElement on the offending input; a successful publish shows no refusal. Ablation: drop the kept-failures state, then drop the focus move; each turns its tests red. ⛔ No change to publish gating, the held-edit guard, or server text.

    Serial: open PR #26920 (another lane, #26708) edits StudioDesignSurface.tsx near L1270–1330 (package not-found), which is disjoint from these regions. #26733 (rail empty-search) runs in parallel on the rail call sites (≈L5104/6341/7969/8892), also disjoint. Whoever lands second merges origin/main.

    Tier

    No path-derived mandate. TIER_DEFAULT, effort high (M–L). Clause-②: no, Metadata-protocol: none expected. Patch changeset for @object-ui/i18n if you add namespace rows; none for app-shell (private: true).

  4. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 5 · 2026-10-27T22:37Z
    Session: session_01JQwxbZeBv2y91towxasSUT (seat; implementation by card thread session session_01JQwxbaQ2uD68Bnvz94D9D1, mode:thread)
    Account: os-warren (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/project-thread-uyrpwg (the card thread's harness push branch, self-reported — the measured platform exception to claude/issue-N-slug)
    Worktree: objectstack-issue-26730 in the card thread's clone
    Domain: domain:ui
    Seat: domain:ui#1 (seat post #25966)
    File surface: ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx, ui/packages/app-shell/src/preview/DraftChangesPanel.tsx, ui/packages/app-shell/src/views/studio-design/metadataError.ts, inspectors only where a focus hook is needed, studio namespace i18n rows (ui/packages/i18n/src/namespaces/studio/{en,zh}.ts) + a patch changeset + tests (stop on breach; explain in the report)
    Container & model: M–L, mode:thread (the maintainer's word on the seat thread, 「opus 很多,并发5」), model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: Studio's publish result handling (this lane's code) | the server's refusal is correct; only the surface drops it | a refused publish leaves the author with a 4 s toast and a "Show me" that does not reach the input
    Thread-read: 6455247899
    Premise: holds — on origin/main 5ec398dc doPublish (≈L1448) reports failed[] only through toast.error(formatPublishFailures(failed)) (≈L1478/L1552) and keeps nothing for DraftChangesPanel; the Interfaces pillar's strip (≈L4683) has no onShow; Data's showObjTarget (≈L5589) only selects.
    Serial constraints cleared: #26845 landed (PR #26927, 22:28Z); open PR #26920 (#26708, another lane) edits StudioDesignSurface.tsx ≈L1270–1330, disjoint; #26733 (this seat, rail call sites) runs in parallel on disjoint hunks; seat 5 (#26945) holds the Interfaces pillar cards and keeps away from the refusal strip. Second to land merges origin/main.
    Resume-from: none


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 26730,
      "status": "done",
      "branch": "claude/project-thread-uyrpwg",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/26994",
      "head": "330e5fef",
      "session": "session_01JQwxbaQ2uD68Bnvz94D9D1",
      "premise_still_valid": true,
      "summary": "A refused publish now keeps each causal failure (non-BATCH_ABORTED) on its Pending changes entry via a new DraftChangesPanel renderEntryNote prop, worded by the refused-save reader (new publishRefusal in metadataError.ts, gate paths re-rooted, draft body read back best-effort) with the raw text under Details; a re-save of that draft, a publish that lets it through, or the ledger no longer listing it clears it. The toast names items and points at the sheet with no engine text. Show me in Data, Automations and Interfaces now focuses the named input (useShowInputFocus); Interfaces gains a Show me via dashboard-widget and report locators. en/zh rows in the studio namespace, patch changeset for @object-ui/i18n.",
      "tests": "7 new/updated files: Test Files 7 passed (7), Tests 26 passed (26). Full studio-design + preview at head: Test Files 274 passed (274), Tests 1950 passed (1950), lock VERDICT command-exit 0. i18n: tsc exit 0, Test Files 89 passed (89), Tests 1373 passed, 13 skipped. app-shell tsc --noEmit and tsc -p tsconfig.test.json exit 0; eslint touched files 0 errors. Ablation 1 (delete setPublishRefusals(new Map(...)) in doPublish): publishRefusal-26730 surface test 3 failed, 1 passed (control); restored blob == HEAD. Ablation 2 (delete control.focus() in useShowInputFocus): 3 showMeFocus files, 6 of 6 failed; restored blob == HEAD. Both via scripts/ablation-replace.mjs with a git checkout HEAD trap.",
      "gates": "dispatch-gates --commands derived 34; all 34 ran with exit codes recorded before any pipe, all exit 0; --ran reconciliation: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. The run was interrupted once by a container restart after gate 5 and resumed from gate 6. CI check-runs: pending at report time. Lines: node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0 | node scripts/check-adr-0087-registration.mjs --self-test :: exit 0 | node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0 | node scripts/check-closing-keyword-parity.mjs :: exit 0 | node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0 | node scripts/check-comment-mask-corpus.mjs :: exit 0 | node scripts/check-empty-changeset.mjs --base origin/main :: exit 0 | node scripts/check-empty-changeset.mjs --self-test :: exit 0 | node scripts/check-sdui-manifest.mjs :: exit 0 | node scripts/check-sdui-manifest.mjs --self-test :: exit 0 | node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0 | node scripts/release-pending-publish.mjs --self-test :: exit 0 | pnpm --dir ui exec vitest run scripts/ :: exit 0 | pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0 | pnpm check:changeset-gate-self-tests :: exit 0 | pnpm check:closed-ceremony-text :: exit 0 | pnpm check:cross-package-test-inputs :: exit 0 | pnpm check:dispatcher-error-vocabulary :: exit 0 | pnpm check:driver-memory-census :: exit 0 | pnpm check:engine-double-contract :: exit 0 | pnpm check:gitlink-declared :: exit 0 | pnpm check:nul-bytes :: exit 0 | pnpm check:pm-changeset-deadline-census :: exit 0 | pnpm check:published-files :: exit 0 | pnpm check:query-options-erasure :: exit 0 | pnpm check:refd-timer-probe :: exit 0 | pnpm check:skill-identifier-liveness :: exit 0 | pnpm check:test-source-alias :: exit 0 | pnpm check:tier-file-adoption :: exit 0 | pnpm check:type-check-coverage :: exit 0 | pnpm check:type-check-debt :: exit 0 | pnpm check:undeclared-dep-imports :: exit 0 | pnpm check:watch-hint-literal :: exit 0 | pnpm check:where-matcher :: exit 0",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "0 — no GitHub MCP tool called, read or write",
      "api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (fleet-write pr_create, run 40608805901, read-back 10732 bytes sent = stored) and this report via scripts/pm/post-stamped.mjs (relay issue comment on #26730); plus git push of the thread branch",
      "open_questions": [],
      "acceptance_notes": [
        "The Pending changes note has no Show me: the sheet's deep-link channel only opens objects; the pillar strips carry it.",
        "Held edits keep their behaviour.",
        "Refusals key on canonical type and name; bundle members (email_template pairs) share one note.",
        "BATCH_ABORTED siblings get no note; the toast says the batch waits.",
        "An issue-less failure reads Not published: REASON with the server text unchanged.",
        "StudioDesignSurface.publishCount-11807.test.tsx updated: toast title is now the count sentence, item and reason in the description.",
        "No change to publish gating, the held-edit guard, server text, formatMetadataError or formatPublishFailures.",
        "PR body folds the PULL_REQUEST_TEMPLATE headings into the os-dev order (os-dev exception)."
      ],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · seat domain:ui#1 · session_01JQwxbZeBv2y91towxasSUT · 2026-10-28T01:13Z

    PR #26994 merged as a8ee8a229a (seat record: PR comment 6457550459). A refused publish no longer lives only in a short toast. Each refused draft's reason now stays under its entry in Pending changes, in author terms, with the raw text behind Details. It clears when the item is saved again, published, or gone. "Show me" lands on the offending input in the Data, Automations and Interfaces pillars, and dashboard widgets and reports gained a locator too. pm:dispatched is removed with the close.


    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:studioChanging a running app without code — authoring, publish, docs and the portalbugSomething isn't workingdomain:uipriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions