Skip to content

fix(app-shell): Studio opens no buffer over a dashboard draft the server refuses to read - #29132

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/project-thread-auz07c
Nov 2, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/project-thread-auz07c

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steedos · project thread

Fixes #29015

Clause-②: no
Metadata-protocol: none

The two lines are copied from the claim (comment 6571613254) and its amendment (comment 6571673304).

维护者速读

  • 改了什么:Studio 读草稿时,服务器因受众门(requiredPermissions)回 403 的草稿,不再被当成"没有草稿"。Interfaces 里这个项不再打开已发布版本供编辑,改为显示一条拒绝说明,自动保存因此没有可发送的内容。
  • 为什么改:之前作者打开一个自己无权读取的仪表盘草稿时,Studio 显示已发布版本,下一次自动保存把它当草稿无前置条件写回,草稿丢掉权限门和其他未发布改动,发布后仪表盘对所有人可见(18.3.0 挡版项)。
  • 风险与回滚:只影响草稿读取返回 403 的项;无草稿、可读草稿、其他读取失败的路径不变。回滚即撤销本 PR。
  • 先看:StudioDesignSurface.tsx 叶子加载处新增的 'refused' in draftRead 分支;DraftConflictDialog.tsx 的 readDraftForSave 与 isDraftReadRefused;新测试 StudioDesignSurface.draftUnreadable-29015.test.tsx。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/app-shell/src/views/studio-design/StudioDesignSurface.draftUnreadable-29015.test.tsx,预期 2 个用例通过。
  • 需要你做的:无,席位落地。

What changes

  • readDraftForSave (metadata-admin/DraftConflictDialog.tsx) keeps its answer and pin for every outcome, and now also hands a draft read refused 403 back as refused. isDraftReadRefused tells that refusal apart by status. A 403 on the draft read means the row is there and withheld (the read gate's audience refusal, PERMISSION_DENIED, by design), so it is no absence. Any other failure is handled exactly as before: no answer, no pin, no refused.
  • The Interfaces pillar's leaf load (StudioDesignSurface.tsx) installs no buffer when the draft read carries refused. It does not read the published layer to stand in for the draft, so the canvas and inspector show nothing to edit and useDraftAutoSave has nothing to send. The refusal strip says the item has an unpublished draft this author may not read, that editing the published version would overwrite it, and that someone who holds the draft's required permissions can edit or publish it. The server's sentence is behind Details.
  • One new Studio string, engine.studio.refusal.draftUnreadable, in the studio namespace tables (en, zh).
  • packages/rest/src/meta-item-read-gate.ts is unchanged: the server's 403 is the designed answer, and the defect was the client reading it as "no draft".

Tests

  • New StudioDesignSurface.draftUnreadable-29015.test.tsx, over a server double whose draft read refuses the gated dashboard draft the way the client throws it (status: 403, code: PERMISSION_DENIED):
    • the refused leaf shows the strip with the server sentence in it, renders no canvas and no edit control, never reads /layers for the leaf, and after the autosave window has sent no save; the stored draft still carries requiredPermissions;
    • control: with no pending draft the published body opens and an edit saves pinned If-None-Match: *.
  • DraftConflictDialog.test.tsx: a 403 read returns { answer: null, pin: null, refused }; a network failure carries no refused; isDraftReadRefused is false for a 500 and for null.
  • Ablation (one-shot, through scripts/ablation-replace.mjs, restored to HEAD's blob): with the new leaf-load branch disabled, the refused-leaf case goes red ("Unable to find an element with the text: This item has an unpublished draft…") and the control stays green.

Acceptance notes

  • The same reading of a 403 draft read as "no draft" sits in other readDraftForSave callers, which this PR does not change: the app navigation load in the same pillar (an app draft carrying requiredPermissions is refused the same way, and the nav save goes unpinned), and ResourceEditPage, ObjectListViewInspector (list views carry the same gate), StudioBundleItemEditor, PermissionMatrixEditor and ObjectHooksPanel. Each can now ask refused; reported to the seat as a family, not filed from here.

Verification

All readings are on head 16e3c584, the only commit on the branch, based on origin/main 5d3667e2.

Tests
  • pnpm --dir ui exec vitest run packages/app-shell/src/views/studio-design/StudioDesignSurface.draftUnreadable-29015.test.tsx packages/app-shell/src/views/metadata-admin/DraftConflictDialog.test.tsx: 2 files, 27 tests passed.
  • Nearby suites: every app-shell test file naming readDraftForSave, DraftConflictDialog or InterfacesPillar, plus the studio-namespace i18n readers (64 files): 737 tests passed.
  • pnpm --dir ui exec vitest run packages/i18n/: 95 files, 1443 passed, 13 skipped.
  • pnpm --dir ui exec vitest run scripts/: 169 files passed, 2 skipped; 4900 tests passed.
  • Ablation of the leaf-load branch (see Tests): refused-leaf case red, control green; file restored to HEAD's blob, git diff HEAD empty.
Type-check and gates
  • turbo run type-check --filter=@object-ui/app-shell --filter=@object-ui/i18n: 66 of 66 tasks successful.
  • node scripts/pm/dispatch-gates.mjs --commands derived 34 families for this diff; all 34 ran with exit 0, and --ran reconciled 34 derived, 34 run, 0 NOT MEASURED. The changeset and closing-keyword gates ran against this body.
  • node scripts/check-sdui-manifest.mjs: exit 0 (no registry change).
  • pnpm check:new-line-citations (under ui/): 0 new citations.
  • The CI-only type-check lanes and the whole-tree families are CI's; their check-runs on this PR are the reading.

Generated by Claude Code

…s to read

A pending draft whose audience gate names a capability the author does
not hold reads 403. readDraftForSave took that for "no draft", so the
Interfaces pillar seeded the leaf from the published layer and the next
autosave overwrote the draft unpinned, dropping its gate. The reader now
hands a 403 back as `refused`, and the leaf load shows a refusal naming
the cause instead of installing a buffer.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsR2jT5xpWAfUCpLoqcxaT
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

席位核对 · ACCEPT · 2026-11-02T08:23Z

Head-sha: 16e3c584670909b6adf0646c53aedf4f21cd6849

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 2, 2026 08:24
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 2, 2026 08:24
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 2, 2026
Merged via the queue into main with commit 3d2e8fd Nov 2, 2026
56 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-auz07c branch November 2, 2026 09:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

1 participant