Repository navigation
Description
domain:devx#1 · os-warren · session_01JQwxbZtZMhQkARKJtViA9U
Filing gate: ① a product defect, the #29015 path re-checked live after its fix (#29132, #29275, #29380), reach: the Studio autosave PUT, measured on two independent boots by two runners (10 of 11 and 7 of 9 fresh loads).
Business reason: an author opening a dashboard whose draft carries an audience gate (requiredPermissions) they do not hold now sees #29132's refusal strip, but on most loads Studio also renders an editable form under it. An edit through the header's Source tool autosaves over the draft with no If-Match: the gate and every draft-only change are lost, and publishing then serves the dashboard to everyone. That is exactly the data loss #29015 was filed (and fixed) for, so the 18.3.0 release blocker's fix is incomplete. It is not an authorization hole: the author holds metadata write on their own package.
Reader who acts: the triage seat, then a domain:ui implementer in ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (the Interfaces leaf load) and the #29132 test. QA suggestion only: area:studio; it re-opens the #29015 release-blocker path, so the director seat decides whether it blocks 18.3.0.
Duplicate search (incl. closed): "refuses to read" draft Studio → 27 hits, StudioDesignSurface draft 403 → 29, requiredPermissions draft 403 Studio dashboard → 38. Nearest: #29015 (closed by #29132, the original), #29148 (closed by #29275/#29380, the four other editors and the pillar load; the list-view editor re-measured here holds). None covers the Interfaces-leaf ordering.
Reproduction (subject 589049b0, main)
- Writable package PKG (
POST /api/v1/packages), a published dashboard D with one metric widget, and an app whose navigation entry names D. - As admin (no set grants
showcase.export_data):PUT /api/v1/meta/dashboard/D?mode=draft&package=PKGwith the published body plus"requiredPermissions":["showcase.export_data"]→ 200 draft. GET /api/v1/meta/dashboard/D?state=draft&package=PKG: admin → 403 PERMISSION_DENIED; an entitled reader (admin role +admin_full_access+showcase_ops) → 200 withrequiredPermissions.- Fresh browser, form sign-in as admin, open
/_console/studio/PKG/interfaces(D auto-selected) or the deep link/_console/studio/PKG/metadata/dashboard/D. - Observed: the refusal strip ("This item has an unpublished draft you are not allowed to read…") AND, under it, the Properties inspector (Label empty, Widgets 0) and the item tools; Source reads
{}. 10 of 11 loads (runner 2: 7 of 9); the deep link 4 of 4. No input was sent before observing (≥6 s after the 403). - Inspector Label edit →
PUT /api/v1/meta/dashboard/D?mode=draft&package=PKG&surface=studio{"label":"…"}, no If-Match → 422 INVALID_METADATA (name, widgets). The draft survives only because the inspector cannot supplyname(metadata-admin/dashboard-schema.tshides it). - Source tool (
[data-testid=studio-item-tool-source]): replace{}with the published body (name, label, columns, widgets), close the sheet → same PUT, no If-Match → 200. The entitled reader's draft read now has norequiredPermissionsand its draft-only label is gone; admin's draft read flips 403 → 200. 2 of 2 per runner (Interfaces and deep link).
Expected (the #29132 contract): Studio opens no buffer over a draft the server refuses to read; no autosave can be sent from that leaf. Actual: an empty editable buffer with a live, unpinned autosave on most loads.
Mechanism (read from source at the subject, consistent with both runs)
- The designers register through a dynamic import (
ui/packages/app-shell/src/index.ts~L425), soisEditable = !!Preview && !StudioCanvas(StudioDesignSurface.tsx~L5131) can be false on the first render. - In that state the
!current || !isEditablearm (~L5240–5251) installsdraft = {}withsetDraftFor(leafKey)and no version pin. - When the preview registers, the effect re-runs; its refused (403) branch (~L5284–5290) only calls
setErrorand returns, leavingdraftFor === leafKey, souseDraftAutoSave(useDraftAutoSave.ts~L167,loadedFor === target) reports loaded: item tools (~L6473) and inspector show and the autosave is live. The object, flow and app 403 branches clear theirs (setObjDraftFor('')~L8116,setDraftFor('')~L10565,setAppDraftFor('')~L4983). StudioDesignSurface.draftUnreadable-29015.test.tsxregisters the dashboard preview inbeforeEach(~L152), so it never reaches this ordering.
QA-source: #29890 · studio-authoring.api-written-keys-survive-studio-save · observed beside the clauses (#29015 off-clause re-check)
Activity
objectstack-fleet commentedon Nov 3, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: first-touch audit · p1 ·
domain:ui·pm:queue· release blocker incomplete · 2026-11-03T09:58Z⛔ Not a claim.
requiredPermissionsand every draft-only change, which is the Studio: a dashboard draft whose requiredPermissions the author does not hold reads 403, Studio treats that as "no draft", and the next autosave overwrites the draft without the key #29015 data loss, so that 18.3.0 blocker's fix is incomplete. Release context: this is a wave-5 finding of the 18.3.0 release sweep, and the maintainer's rule is 「发版本优先的都p1」. p1.Generated by Claude Code
objectstack-fleet commentedon Nov 3, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jV4dWohojjbTJTQq5m
Claim: PM loop round 34 · 2026-11-03T10:09Z
Session:
session_01QsR2jQx7EwgLR5PQRL3zQp(card thread, os-dev); dispatched by seat sessionsession_01QsR2jV4dWohojjbTJTQq5mAccount:
zhuangjianguoBranch:
claude/project-thread-dawqbk(platform-assigned to the card thread; it can push only this branch)Worktree:
objectstack-issue-29884Domain:
domain:uiSeat:
domain:ui#3File surface:
ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx(the dashboard / Interfaces leaf's refused-draft branch, and the pre-registration arm).StudioDesignSurface.draftUnreadable-29015.test.tsx(a new top-level describe), and one changeset (@object-ui/app-shellpatch).(stop on breach; explain in the report)
Container & model: M,
mode:thread,model: default tier (dispatch-gates: no path-derived mandate),effort: highClause-②: no
Metadata-protocol: none
Responsibility:
StudioDesignSurface's refused (403) dashboard branch leaves draftFor set after a late preview registration | #29132's refusal strip (drawn, but the buffer opens under it) | authors opening a dashboard whose draft gate they do not hold, today (10 of 11 loads)Thread-read: 6600602803
Premise: holds per the card's two-runner measurement at
589049b0, and triage 6600602803. The card thread re-verifies the mechanism at main before the first edit.Serial constraints cleared: none in flight. No open PR touches
StudioDesignSurface.tsx.objectstack-fleet commentedon Nov 3, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jQx7EwgLR5PQRL3zQp
os-dev-report
{ "issue": 29884, "status": "done", "branch": "claude/project-thread-dawqbk", "pr": "https://github.com/objectstack-ai/objectstack/pull/29922", "head": "58c3a3f7", "session": "session_01QsR2jQx7EwgLR5PQRL3zQp", "premise_still_valid": true, "summary": "Re-verified at main: the Interfaces leaf load's no-designer arm stamps the {} buffer as the leaf's, and the refused (403) branch kept that stamp once the late-registered preview triggered the draft read, so the canvas, inspector and Source tool opened and the autosave was live unpinned. A same-leaf reload after a readable load kept its buffer the same way. The refused branch now clears ownership (setDraft({}), setDraftFor(''), forgetLeafVersion(), read address null, setIfDirty(false)), mirroring the object/flow/app branches. The no-designer arm is kept (objectui#11272; the autosave is blocked while !isEditable). Census: object, flow and app loads have no stamping pre-registration arm and already clear on 403; only the Interfaces leaf had the ordering. The area deep link navigates to the same pillar load.", "files_changed": [ "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (+11)", "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.draftUnreadable-29015.test.tsx (+158, new top-level describe)", ".changeset/29884-refused-dashboard-draft-read-only.md (@object-ui/app-shell patch)" ], "line_budget": "182 changed lines (+182/-0), 3 files, under the 3000 threshold", "tests": "Harness at main 00f72f94 + test commit: Tests 3 failed | 3 passed (6), the three new cases red on surface-draft present. With the fix: 6/6. Ablation via ablation-replace (setDraftFor('') -> setDraftFor((prev) => prev), anchor 1->0, blob a60c33a4f242->ec0372a0a886): 3 failed | 3 passed, restored blob == HEAD, git diff HEAD empty. On final head 58c3a3f7: card file 6/6. Neighbour sweep on 1a9786f9: all 57 InterfacesPillar test files, 29 files/155 tests + 28 files/283 tests passed (narrowing: not all 223 StudioDesignSurface files; CI Test UI runs them). app-shell turbo type-check 65 tasks exit 0. eslint on the 2 ui files: 0 errors, warnings pre-existing. Live (showcase backend + Console Vite, card steps 1-7): before 7/7 loads (5 Interfaces, 2 deep link) show strip + empty Properties form + item tools; Source edit PUT draft no If-Match -> 200 and admin draft read 403 -> 200, on both routes. After 9/9 loads incl. two edit attempts: strip only, 0 form controls, no tools, no PUT, draft read stays 403. Shots: /mnt/project-files/issue-29884/shots/.", "gates": "Final head 58c3a3f7: dispatch-gates --commands derives 35; 34 non-vitest families all exit 0 (check-sdui-manifest exit 0 and --self-test exit 0, check:type-check-debt exit 0 706s, check:query-options-erasure exit 0); pnpm --dir ui exec vitest run scripts/ exit 0 (170 passed | 2 skipped files, 4979 passed | 2 skipped tests). dispatch-gates --ran on 1a9786f9: 35 derived, 35 run, 0 NOT-MEASURED; 58c3a3f7 derived the identical list. PR body gates: changeset-no-major, adr-0087-registration, closing-keyword-parity, partof-closing-keyword all exit 0. CI check-runs: in_progress at report time.", "dogfood_battery": "n/a, no ! in the PR title and no (narrowing) arm", "mcp_calls": "2, both reads (issue_read get, issue_read get_comments)", "api_writes": "3: git push (branch), fleet-write pr_create (#29922, read back byte-identical, no assignees), post-stamped os-dev-report comment on #29884", "deviations": [ "The PR body opens with the session's two-line project attribution block, then Fixes #29884 (third line), as on #29132.", "The PR body's Verification section says the ui scripts/ re-run on 58c3a3f7 was still running when the PR opened. It finished green afterwards (see gates). The seat may amend that sentence.", "Deep-link test mounts the landing URL areaItemPillarPath gives, not the StudioMetadataArea route itself.", "Late-registration cases use vi.resetModules for fresh empty designer registries (no unregister exists)." ], "open_questions": [], "security_findings": "none", "out_of_scope_findings": [] }objectstack-fleet commentedon Nov 3, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jV4dWohojjbTJTQq5m
ACCEPT → PR #29922 comment 6604563850 · 2026-11-03T13:04Z (no contract review owed; landing: ready + auto-merge)
objectstack-fleet commentedon Nov 3, 2026
domain:ui#3 · zhuangjianguo · session_01QsR2jV4dWohojjbTJTQq5m
Landed · 2026-11-03T13:18Z
40a35ded, at head58c3a3f7(ACCEPT 6604563850)completedbyFixes. Labels read back: bug, priority:p1, domain:uiState:
pm:dispatchedremoved, and the card is closed. Delivered: a dashboard draft the server refuses to read (403) now opens read-only in Studio Interfaces, whether the designer registers early or late. Only the refusal strip shows, with no canvas, inspector or Source tool. The autosave has nothing to send, so the draft'srequiredPermissionsgate can no longer be overwritten. The "All metadata" deep link is covered by the same load. Nothing is left on this card.