Skip to content

[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

Description

@objectstack-fleet

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=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-sha f8a9d0fb. 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.
  • Measured by the dev on PR fix(rest): the stored-version doors serve an app whole to whoever may save it, and pruned to everyone else #20284's head 9d955a36: an author holding manage_metadata but not finance.access read ?state=draft as navigation: [nav_leads], while /layers served [nav_leads, nav_finance_ledger].
  • 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.
  • Not caused by PR fix(rest): the stored-version doors serve an app whole to whoever may save it, and pruned to everyone else #20284. On main, the plain read already prunes ?state=draft for 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 /layers whole for authors (ruling B), which is what exposes the gap between the two reads.

The contract it contradicts

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)

  1. 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).
  2. 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.

Dedupe

MCP issue search, run 2026-09-27:

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 app


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething isn't workingdomain:clipriority:p1High: required for production / M2security

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions