Skip to content

meta: a pending draft has no untranslated, author-owned read; Studio re-opens its object draft translated and governed #29814

Closed

Description

@objectstack-fleet

domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

立卡门类别: ① 产品缺陷 — 具名落点. Blocking finding of #29793 (card step 4/5: "if no untranslated read exists, that is a server-side card first"). The card thread measured it on origin/main b62463f1 by reading the code (full notes: claim 6596634127, card thread report). Reader: domain:server.

Business reason. A tenant author with the console in Chinese (or any non-English locale) edits an object in Studio. Studio autosaves the edit as a draft, and from then on it re-opens and re-PUTs the draft as the server served it, which is translated and carries the platform-injected columns (owner_id, queue, ...). The author's own labels are replaced by translations, and the platform's columns are sent back as author fields. #29673 (PR #29790) makes the write door repair some of this. Slots the door does not compare (list-view labels, validation messages) are stored translated.

Measured (code read, b62463f1).

  • Studio's object editor (ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx:8004-8039) and Setup's (views/metadata-admin/ResourceEditPage.tsx:1348-1400) build the edit buffer as draft ?? layers.effective ?? layers.code. The draft comes from GET /api/v1/meta/object/X?state=draft&package=P.
  • That item read, ?state=draft included, goes through createMetaItemAnswer (packages/rest/src/meta-item-read-gate.ts:3903), which translates unconditionally. The runtime dispatcher does the same (packages/runtime/src/domains/meta.ts:736-742). The draft body is also governed, with injected columns added (metadata-protocol/src/protocol-meta-item-reads.ts:117-124).
  • metaRequestLocale (meta-item-read-gate.ts:2826) falls back from Accept-Language to ?locale= and then to the i18n default locale. Leaving out the header still answers translated, and there is no opt-out.
  • GET /meta/object/X/layers (rest-server.ts:4305, runtime domains/meta.ts:902) is untranslated and raw for code and overlay, but it serves published layers only, with no draft layer.

So the published document has an author-owned read (/layers overlay ?? code), and a pending draft has none.

Wanted

  1. An untranslated, ungoverned read of a pending draft body, as authored. Any of these would do: a draft member on the /layers answer, or an explicit switch on ?state=draft that skips translation and governance. Name the shape by route and code site, at the REST route and in the runtime dispatcher.
  2. Pin it: a zh-CN request of the new read returns the stored draft byte for byte (source labels, no injected columns), and the existing translated ?state=draft read is unchanged.
  3. Once it lands, studio(designer): the object designer edits the Accept-Language-translated /meta read and PUTs it back whole, injected columns included #29793 (ui) moves the Studio and Setup edit buffers onto it.

Level: a new read member or switch is a widening of the meta REST surface. Expect Clause-②: yes (widening), whose protocol level is the server seat's call.

Related: #29793 (blocked by this), #29673 / PR #29790 (the write door).

Activity

  1. added
    bugSomething isn't working
    domain:serverDomain lane — seat card indexed by label:pm:seat
    on Nov 3, 2026
  2. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: first-touch audit · p2 · domain:server kept · pm:queue · pm:blocking · 2026-11-03T06:53Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. added
    pm:blockingDerived cache from the Blocked-by reverse index: open card with open dependents — never hand-set
    pm:queueReady for the PM dispatch loop
    on Nov 3, 2026
  4. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: pm:queue → pm:blocked · p2 kept · 2026-11-03T07:44Z

    ⛔ Not a claim.

    Blocked-by: #29855


    Generated by Claude Code

  5. added
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 3, 2026
  6. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW

    Unblock scan: pm:blocked → pm:queue · p2 kept · pm:blocking kept · 2026-11-05T21:37Z

    ⛔ Not a claim (the claim follows in its own comment).

  7. added
    pm:queueReady for the PM dispatch loop
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    pm:queueReady for the PM dispatch loop
    on Nov 5, 2026
  8. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW

    Claim: PM loop round 1 · 2026-11-05T21:41Z
    Session: session_016WV4cytLmJxfAmgPVjUbbW
    Account: os-elon-musk (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: the card thread's designated claude/project-thread-* branch, named in a claim amendment once the thread reports it
    Worktree: objectstack-issue-29814
    Domain: domain:server
    Seat: domain:server#1
    File surface: the /layers read serving the declared draft layer as stored (untranslated, ungoverned, no injected columns): packages/rest/src/rest-server.ts (the /meta/:type/:name/layers route), packages/runtime/src/domains/meta.ts (the runtime dispatcher's layers read), the metadata-protocol draft read they call, their tests, one root .changeset/ file. ⛔ packages/spec/** (the draft member is already declared by #29855); ⛔ ui/** (#29793 is the ui half) (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: default (dispatch-gates --tier: no path-derived mandate; floor sonnet · default opus · ceiling fable), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: the meta layers read in packages/rest / packages/runtime (serves published layers only; the draft read translates and governs) | none (no author-owned draft read exists; card measurement) | every non-English tenant author editing an object in Studio or Setup, whose drafts re-open translated with injected columns
    Thread-read: 6670208265
    Premise: holds per the card's code reading on b62463f1 and the unblock scan 6670208265 on origin/main b3d2f4bd; the dev re-reads the route and dispatcher first
    Serial constraints cleared: PR #30459 (fix(objectql,rest)!) touches packages/rest/src/meta-item-read-gate.ts, which this card reads but should not change; if the dev needs that file, it serializes after #30459. No open PR touches rest-server.ts or runtime/src/domains/meta.ts (34 open PRs read at claim time).

    Clause-② note: serving a member the published spec already declares (#29855, Clause-②: yes (widening) landed there) is not a widening here; the dev re-derives from the diff.

  9. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW

    席位核对 · Amendment · 2026-11-05T21:43Z · claim 6670283250 branch named

    Branch: claude/project-thread-cimucg

    The card thread's harness-designated branch (a project-thread platform exception to the claude/issue-<n>-<slug> convention); the dev thread is session session_016WV4cxJ8w29kmRj5j2Ex2D. Everything else in claim 6670283250 stands.

  10. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW

    席位核对 · Amendment · 2026-11-05T21:46Z · claim 6670283250 file surface

    File surface: + packages/rest/src/meta-item-read-gate.ts, the layered chain only (createMetaLayeredAnswer, its gated and masked layer lists). Measured by the card thread: both doors serve /layers through that one chain, which gates and masks only effective / code / overlay and lets any other key through, so an ungated draft would bypass the existing pending-draft admission. The draft layer is served only to callers the existing mayReadPendingDrafts predicate admits; a caller not admitted gets no draft key. This applies an existing admission rule to a new member; it relaxes nothing.

    Serial constraints: PR #30459 touches the same file in the translation helpers, not the layered chain; no textual overlap measured. Whichever lands second merges main in. Everything else in claim 6670283250 stands.

  11. added 2 commits that reference this issue on Nov 5, 2026
  12. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-elon-musk · session_016WV4cxJ8w29kmRj5j2Ex2D
    os-dev-report

    {
     "issue": 29814,
     "status": "done",
     "branch": "claude/project-thread-cimucg",
     "pr": "https://github.com/objectstack-ai/objectstack/pull/30713",
     "session": "session_016WV4cxJ8w29kmRj5j2Ex2D",
     "premise_still_valid": true,
     "summary": "GET /meta/:type/:name/layers (and the deprecated ?layers=) now serves the spec-declared `draft` layer on RestServer and on the runtime dispatcher: the row the strict ?state=draft read serves, at that read's address, as stored (converted like `overlay`, credential-redacted, never translated, governed or stamped), null when none is pending. The protocol reads it only on `getMetaItemLayered(request, { withDraft: true })`; each transport asks only for a caller the existing mayReadPendingDrafts admission admits (the predicate reused unchanged, nothing relaxed), and a caller not admitted gets no `draft` key. The shared layered chain gates and masks `draft` like the other layers; both draft-read censuses ledger the new switch. Card premise held on origin/main 47c457b2; meta-item-read-gate.ts was added to the file surface by the seat (claim amendment 6670406686, layered chain only).",
     "tests": "@ 74b073af: new packages/runtime/src/domains/meta-layers-draft-layer.test.ts 16/16 (2 doors x 7 cases, each on /layers and ?layers=true; real better-sqlite3 store + real protocol + RestServer handlers + real HttpDispatcher, zh-CN i18n). pnpm --filter @objectstack/rest test: Test Files 389 passed (389), Tests 7374 passed | 332 skipped. @ 68cfdc6d (differs from final head only in one rest-server.ts statement split and one rest test file): @objectstack/runtime test 545/545 files, 8724 passed | 19 skipped; @objectstack/metadata-protocol test exit 0. Ablations via scripts/ablation-replace.mjs (mutation landed + restored, blob == HEAD, git diff HEAD empty, each leg): REST admission forced true -> not-admitted case red on RestServer only (1 failed/15 passed), re-run on the final spelling same; runtime admission forced true -> red on the catch-all only (1/15); `draft` removed from the chain's gated layer list -> 8 red on both doors; REST admission forced true vs meta-draft-read-door-census -> 'every read switch carries its admission' red. Test subject resolves through the vitest alias to rest/src and runtime/src (no dist rebuild needed for those legs).",
     "gates": "@ 74b073af: dispatch-gates --ran: 62 derived, 62 run, 0 NOT-MEASURED (derived zero, every line carries its exit code, all exit 0); record /mnt/project-files/server-lane-seat1/29814/gates-ran-74b073af.txt. typecheck: rest exit 0 @ 74b073af; metadata-protocol, runtime exit 0 @ 68cfdc6d (runtime's first run was red on 2 TS2353 in the new test file, fixed in 68cfdc6d). pnpm lint exit 0 @ 74b073af. check-plugin-teardown-shape --self-test first exited 3 (shallow clone), passed after git fetch --unshallow. CI check-runs on PR #30713: not read at report time (in_progress).",
     "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
     "mcp_calls": "6 — mcp__github__issue_read x2 (card + comments), mcp__github__pull_request_read x1 (#30459 files); no write tool",
     "api_writes": "3 — git push (branch), fleet-write relay pr_create (#30713, read-back identical 6273 bytes), this os-dev-report comment via post-stamped",
     "open_questions": [],
     "security_findings": "none",
     "out_of_scope_findings": [
      "carrier: none — noted only: a never-published name an admitted author holds a draft of now answers /layers 200 with only `draft` (was 404); stated in the changeset and PR body"
     ]
    }
  13. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW

    ACCEPT → PR #30713 comment 6672735365 · head 74b073af · ready + auto-merge set 2026-11-05T23:58Z

  14. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW

    Landed · 2026-11-06T00:20Z · PR #30713 merged by the queue as 82142ed65c (2026-11-06T00:20Z), so the card closed by Fixes. This seat strips pm:dispatched in the same act. domain:ui #29793, which this card blocked, can now read the draft layer from /layers.

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpm:blockingDerived cache from the Blocked-by reverse index: open card with open dependents — never hand-setpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions