You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[finding] an app author's draft baseline is read through the pruned plain read (GET /meta/app/:name?state=draft), and the designers merge it over the whole stored app, so a draft save drops the navigation entries withheld from that author #20290
Filing gate: ① a defect with a named landing site. The server half is packages/rest/src/rest-server.ts, the plain read's ?state=draft branch. The client half is objectui's two app editors. Finding class (a), with reach: measured at a public door: an authoring save silently loses data.
Found by the os-dev round on #20156 (PR #20284, the ruled author exemption on the stored-version doors). The server half was confirmed at source by that PR's at-tier contract review (record 5858783654). Filed by the domain:cli execution seat (#6024, session_01UYBdGBzWSrAMzpW8ah3GbP). ⛔ Filed bare: routing, grading and the choice of carrier are triage's. ⛔ Not a claim.
What happens
⚠️ The objectui readings below are the dev's, relayed. They were read from objectui source at the pinned .objectui-shaf8a9d0fb. The seat did not re-read objectui.
Producers (objectui):
app-shell StudioDesignSurface.tsx builds its app baseline as { ...layered.effective, ...getDraft } (about :1760-:1767) and saves navigation with client.save('app', …, { mode: 'draft' }) (about :1960);
ResourceEditPage.tsx, the generic editor (no bespoke app edit page is registered), merges the same way (about :1016-:1056) and saves at about :1500.
The door:GET /meta/app/:name?state=draft, the plain read.
It sets state: 'draft' on getMetaItem (rest-server.ts about :6988-:7002).
It then runs metaItemReadGate(..., { arms: 'all', app: 'gate' }) and serves verdict.document (about :7060-:7068).
It attaches no author exemption, so it prunes the navigation entries the caller's requiredPermissions or documentation audience withhold, authors included.
Result: when an app has a pending draft, the draft's PRUNED navigation overrides the author's whole effective navigation in the editor. The next draft save writes the pruned list back, and the withheld entries are deleted.
Ruling 5856774816 on #20156 (letter B), in its rationale: 「whoever can save it must see it whole, or a save drops entries silently」. The same ruling: 「Read-to-display is pruned per user; read-to-edit is whole for the editor.」 The designers' draft read is a read-to-edit, but it goes through a read-to-display door.
Candidate carriers (for triage, ⛔ not presumed here)
Server: the plain read's ?state=draft branch honours the author exemption, since a draft is a stored version, not a rendered one. Or the draft is served on a stored-version door (/layers with a draft layer).
Client: objectui reads its edit baseline, draft included, through a stored-version door rather than the plain read.
If choosing between them changes what a non-author may read of a draft, that is a question for the decision box, not for a dev. Ruling B covers the three stored-version doors only.
Who acts
Triage decides the landing repository and lane. The server half is domain:cli (packages/rest); the client half is repo:objectui.
Ruled: 5861438413 · letter A · 2026-09-28T00:56Z
Filing gate: ① a defect with a named landing site. The server half is
packages/rest/src/rest-server.ts, the plain read's?state=draftbranch. The client half is objectui's two app editors. Finding class (a), withreach:measured at a public door: an authoring save silently loses data.Found by the
os-devround on #20156 (PR #20284, the ruled author exemption on the stored-version doors). The server half was confirmed at source by that PR's at-tier contract review (record5858783654). Filed by thedomain:cliexecution seat (#6024,session_01UYBdGBzWSrAMzpW8ah3GbP). ⛔ Filed bare: routing, grading and the choice of carrier are triage's. ⛔ Not a claim.What happens
.objectui-shaf8a9d0fb. The seat did not re-read objectui.StudioDesignSurface.tsxbuilds its app baseline as{ ...layered.effective, ...getDraft }(about :1760-:1767) and saves navigation withclient.save('app', …, { mode: 'draft' })(about :1960);ResourceEditPage.tsx, the generic editor (no bespoke app edit page is registered), merges the same way (about :1016-:1056) and saves at about :1500.GET /meta/app/:name?state=draft, the plain read.state: 'draft'ongetMetaItem(rest-server.tsabout :6988-:7002).metaItemReadGate(..., { arms: 'all', app: 'gate' })and servesverdict.document(about :7060-:7068).requiredPermissionsor documentation audience withhold, authors included.9d955a36: an author holdingmanage_metadatabut notfinance.accessread?state=draftasnavigation: [nav_leads], while/layersserved[nav_leads, nav_finance_ledger].main, the plain read already prunes?state=draftfor every caller. PR fix(rest): the stored-version doors serve an app whole to whoever may save it, and pruned to everyone else #20284 makes/layerswhole for authors (ruling B), which is what exposes the gap between the two reads.The contract it contradicts
Ruling
5856774816on #20156 (letter B), in its rationale: 「whoever can save it must see it whole, or a save drops entries silently」. The same ruling: 「Read-to-display is pruned per user; read-to-edit is whole for the editor.」 The designers' draft read is a read-to-edit, but it goes through a read-to-display door.Candidate carriers (for triage, ⛔ not presumed here)
?state=draftbranch honours the author exemption, since a draft is a stored version, not a rendered one. Or the draft is served on a stored-version door (/layerswith a draft layer).If choosing between them changes what a non-author may read of a draft, that is a question for the decision box, not for a dev. Ruling B covers the three stored-version doors only.
Who acts
Triage decides the landing repository and lane. The server half is
domain:cli(packages/rest); the client half isrepo:objectui.Dedupe
MCP issue search, run 2026-09-27:
publishPackageDraftsand draft-scope cards (SqlDriver org auto-scope makes SysMetadataRepository.listDrafts blind to env-wide drafts (organization_id IS NULL ∧ injected org = always empty); mode=draft saves drop package_id #11087, publishPackageDrafts writes no audit rows — Studio's "publish whole app" leaves the audit trail empty #8400, A draft row stored under a manifest-absent plural (fields,seeds,external_catalogs,translations) is promotable by publishPackageDrafts and lands ACTIVE in the second namespace #8908, publishPackageDrafts validation closure omits same-batch dataset drafts: a package shipping dashboard+dataset together can never publish (widget-dataset-unknown) #10377, publishPackageDrafts can promote (and drain) ANOTHER package's draft row — the promote resolves the draft without the ADR-0048 package dimension #8907, publishPackageDrafts' ADR-0010 audit row records the raw stored type spelling — the #8769 fold closed this forpublishMetaItemonly #8858, The lock/conflict denial audit rows roll back with the batch on publishPackageDrafts — a refused item in a package publish still leaves no trail #8594) and pm-dispatch: the director seat presents the governed drafts awaiting a human merge as one decision batch, and checks each carries its four-piece (maintainer, 2026-09-13) #17951, which is unrelated.Dedupe words:
app draft state=draft pruned author·designer getDraft merge effective navigation save drops entries·StudioDesignSurface draft baseline withheld nav·ResourceEditPage draft baseline pruned appGenerated by Claude Code