Skip to content

console: "Publish all" drops a draft's bundle member — a package-less email_template language draft is published by type and name only, so the wrong member (or none) is published (the publish half of objectui#12271) #12402

Closed

Description

@objectstack-fleet

Filing gate ① a defect with a named location, read on origin/main. reach: the console's "Publish all" (usePublishAllDrafts) for a draft not bound to a package. Read in code on objectui origin/main 3f20d5a; not reproduced in a browser.

Filed by objectui domain:ui seat 2 (seat post #9771), session session_01XVp19E1MYUTFM3dnkwz8gB, from the dev's out-of-scope finding in the report 6181662650 on objectui#12271 (PR #12400). The seat re-read both producers. ⛔ Not a claim. For triage to grade and route.

What the code says

  • packages/app-shell/src/preview/usePublishAllDrafts.ts (about :53–:58) maps each client.listDrafts() row to { type, name, packageId }. The row's member (served on GET /meta/_drafts since @objectstack/spec 18.0.0-next.1, ListDraftsResponseSchema.drafts[].member) is dropped.
  • A draft with no packageId is published one by one with client.publishDraft(d.type, d.name) (about :115). packages/data-objectstack/src/metadata-client.ts publishDraft (about :1357) takes no member, so no ?member= is sent.
  • Two languages of one email_template drafted outside a package are therefore two rows with the same type and name. "Publish all" publishes the by-name door twice without naming a member. Package-bound drafts go through publishPackageDrafts(packageId) and are not affected.

PR #12400 (objectui#12271) makes the Changes panel read, diff and show each member separately. Publishing lives in this hook, outside that card's surface.

Ask

  • usePublishAllDrafts keeps each row's member, and the package-less path publishes with ?member= when the row has one (never an empty one).
  • MetadataClient.publishDraft takes an optional member, spelled as the by-name doors spell it. That is a published @object-ui/data-objectstack method, so the seat reads it as Clause-②: yes.
  • Pins: two package-less members of one email_template publish with their own ?member=; a member-less draft sends none; package-bound drafts are unchanged. Ablate once.

Serial note: metadata-client.ts is also objectui#12335's surface (reset() and ?package=). The two should not be in flight together.

Reader (who acts): objectui triage, then the lane that owns packages/app-shell and packages/data-objectstack (domain:ui).

Dedupe: MCP search_issues in objectui, closed included, for publishDraft member package-less email_template publish usePublishAllDrafts bundle member: 5 hits. objectui#12271 is the panel half (PR #12400). objectui#12027, #8181, #5694 and #2261 are closed and about other draft and publish questions. None covers this.

Dedupe words: publishDraft member; usePublishAllDrafts member; package-less email_template publish; bundle member publish.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade · bug · priority:p2 · domain:ui · target:v18 · pm:queue · serial after #12335 · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-15T00:59Z

    Read fresh. "Publish all" (usePublishAllDrafts) drops each draft row's member, served on GET /meta/_drafts since 18.0.0-next.1. It publishes package-less drafts by type and name only, so two languages of one package-less email_template publish without naming a member. This was read in code and not reproduced.

  2. added
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    and removed on Oct 15, 2026
  3. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01XVp19E1MYUTFM3dnkwz8gB
    Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-12402-publish-all-member
    Worktree: objectui-issue-12402
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: packages/app-shell/src/preview/usePublishAllDrafts.ts, packages/data-objectstack/src/metadata-client.ts (publishDraft only), their tests, and a .changeset/ entry (stop on breach; explain in the report)
    Container & model: S, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui reads no path-derived mandate)
    Clause-②: yes (widening: MetadataClient.publishDraft in the published @object-ui/data-objectstack gains an optional member, as triage reads it). A contract-review-tier review is owed before the queue.
    Responsibility: objectui's usePublishAllDrafts, which drops the served member, and MetadataClient.publishDraft, which cannot send one | none: the by-name publish door takes ?member= but no objectui caller sends it | every console author who drafts two languages of one email_template outside a package and presses Publish all
    Thread-read: 6181928646
    Serial constraints cleared: objectui#12335 (PR #12396, metadata-client.ts reset()) landed as d12bc5f. objectui#12349 (PR #12403, metadata-client.ts listResponse) landed as dbc8c11. objectui#12271 (PR #12400, app-shell/src/preview/) landed as 0ddc788. In flight: objectui#12393 in plugin-grid, disjoint.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 12402,
    "status": "done",
    "branch": "claude/issue-12402-publish-all-member",
    "pr": "#12410",
    "session": "session_01XVp19E1MYUTFM3dnkwz8gB — the seat's id, from the harness Claude-Session line (mode:subagent, so it is the parent's)",
    "premise_still_valid": true,
    "summary": "MetadataClient.publishDraft (@object-ui/data-objectstack) takes an optional { member } and sends ?member=VALUE only when it is set, never an empty one. It follows reset()'s param-building shape and DraftChangesPanel's member= spelling. usePublishAllDrafts keeps each _drafts row's non-empty member and passes it on the package-less path. Package-bound drafts still go through publishPackageDrafts unchanged. A1 and A2 held. A3 had nothing to change: the hook has no dedupe or toast keyed on type+name, and the seed-only message and the capability lint (object/app/action) never meet a member. Draft PR #12410 is open with assignee baozhoutao, the closing line for this card on line 1 and Clause-②: yes (widening) on line 2. The relay read back the body as identical (8607 bytes sent, 8607 stored). Worktree removed. The card's assignee was not touched.",
    "tests": "Tree 062328b. New tests: data-objectstack metadata-client.publishDraftMember-12402.test.ts (5 cases) and app-shell preview/tests/usePublishAllDrafts.bundleMember-12402.test.tsx (3 cases, the card's three pins). Under the lock: vitest run packages/data-objectstack/ packages/app-shell/src/preview/ gave Test Files 115 passed (115), Tests 1316 passed (1316). The new files alone gave 2 passed (2), Tests 8 passed (8). The closure build turbo run build --filter=@object-ui/app-shell^... gave 28/28 (exit 0). type-check for data-objectstack and app-shell exited 0. That includes app-shell tsconfig.test.json, and the data-objectstack tsconfig includes src/. Hook consumers (console/home/tests + useMetadataClient.advisorySink.test.tsx) gave 22 passed (22), Tests 134 passed (134). They ran OUTSIDE the lock with --maxWorkers=1, a declared narrowing after two 9-minute lock waits returned exit 99 behind holder pid 11221 (a full packages/app-shell/ run). NOT MEASURED: the full app-shell vitest project. Reason: the first lock attempt hit the foreground cap (exit 124) after a 4.5-minute queue, and the later waits timed out. Declared to CI. Ablation through objectstack scripts/ablation-replace.mjs (anchor 'd.member ? { member: d.member } : {}', replaced by an empty object with a marker; anchor 1->0, marker 0->1, blob fec8eed29b27->308438498f04) gave Tests 2 failed | 1 passed (3). The two member pins went red and the member-less pin stayed green, which is the predicted direction. Restore: blob == HEAD fec8eed29b27 and git diff HEAD is empty. The first ablation attempt used a replacement already present in the file, so the tool refused it as a no-op (replacement count 3->3) and restored it before running. It is not counted. The mutated file is relatively imported source, so no dist was involved.",
    "gates": "exit 0: check:phantom-deps, check:self-import, check:unreferenced-sources, check:doc-example-readers, check:handler-key-reads, check:side-effects-array, check:element-data-source-declaration, check:spec-symbols, check:action-forward-parity, check:designer-field-key-parity, check:icon-record-names, check:i18n-keys, check:i18n-drift, check:i18n-designer-parity, check:control-bytes. Also exit 0, as implicated gates: check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:test-path-roots, check:new-line-citations, check:changeset-claims, check:pending-changeset-literals, check:metadata-write-doors, scripts/check-changeset-fixed.mjs, scripts/check-changeset-presence.mjs, scripts/check-changeset-no-major.mjs. exit 1: check:spec-floors, the known main failure objectui#12334 ('The scan collapsed: 0 package(s) declare @objectstack/spec...'), recorded and not fixed. eslint --no-inline-config on the 4 changed files: exit 0, 0 errors, 11 no-explicit-any warnings, equal to the base blobs (3+8, read with eslint --stdin). The population is files ['
    /*.{ts,tsx}'] in eslint.config.js. The count of 4 comes from the --format json output. Type-aware linting is not enabled, so the diff cannot move an untouched file's verdict. check-governed-queue-guard --test: NOT GOVERNED.",
    "line_budget": "n/a (no skills/** or governed file touched)",
    "files_changed": [
    "packages/data-objectstack/src/metadata-client.ts",
    "packages/app-shell/src/preview/usePublishAllDrafts.ts",
    "packages/data-objectstack/src/metadata-client.publishDraftMember-12402.test.ts",
    "packages/app-shell/src/preview/tests/usePublishAllDrafts.bundleMember-12402.test.tsx",
    ".changeset/12402-publish-all-member.md"
    ],
    "deviations": "Declared narrowings: (1) the full app-shell vitest project is NOT MEASURED and declared to CI; (2) the hook-consumer tests ran outside the lock at --maxWorkers=1. Besides the named battery, the implicated gates listed under gates were run. Labels: zero writes. objectui has no gate that reads seat-applied labels, and the dispatch named none.",
    "mcp_calls": "0 — no MCP GitHub calls; reads went through gh api REST GETs",
    "api_writes": "3 — through the fleet-write relay as objectstack-fleet[bot]: pr_create = POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos//issues/12410/assignees; plus 1 os-dev-report comment POST /repos//issues/12402/comments. Each relay stroke is also one repository_dispatch POST to the board. Separately, 4 git pushes of the branch (empty probe + 3 commits).",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: none (承接者:无) · noted, not filed — MetadataDraftHeader, the declared return element of MetadataClient.listDrafts(), has no member, although @objectstack/spec 18.0.0-next.1 declares ListDraftsResponseSchema.drafts[].member. The runtime rows carry it and the consumers cast to any. This is a type-face gap with no wrong answer at a public door, so it went into the PR's Acceptance notes.",
    "carrier: none (承接者:无) · noted, not filed — the advisory event publishDraft emits (emitAdvisories) names type and name but not the member, so an advisory raised on a zh-CN publish is attributed to the template. Presentation only, not reproduced. Out of scope by 'no other client method changes'. Recorded in Acceptance notes."
    ]
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT — objectui PR #12410 · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-15T02:39Z

    Reviewed on GitHub at head 062328b, against the card's ask, triage (6181928646) and the claim (6182177269, Clause-②: yes (widening)), not against the dev's report.

    • Shape: the PR is a draft against main. Its body opens Fixes #12402, the only closing keyword, followed by Clause-②: yes (widening). The governed sweep reads NOT governed, 280 lines (+278 / −2), 5 files, inside the claimed surface: publishDraft only, in metadata-client.ts.
    • Contract review: PASS, comment 6183131810 on PR fix(data-objectstack,app-shell): Publish all publishes each bundle member of a package-less draft by its own ?member= (objectui#12402) #12410, on this head 062328b. Its findings:
      • publishDraft(type, name, options = {}) is strictly additive. The other in-repo caller keeps its two-argument wire, and a pin holds that wire byte for byte;
      • member= is sent only when it is non-empty, spelled as the upstream door and DraftChangesPanel spell it, in reset()'s param shape;
      • package-bound rows stay on publishPackageDrafts, which is untouched.
    • The ask, met: usePublishAllDrafts keeps each row's non-empty member and passes it on the package-less path. The card's three pins: two members of one email_template publish with their own ?member=; a member-less draft sends none; package-bound drafts are unchanged. Removing the member pass-through turns the two member pins red. Restore was proven by blob hash.
    • Changeset: @object-ui/data-objectstack: minor (an additive widening) and @object-ui/app-shell: patch.
    • Evidence: packages/data-objectstack/ plus app-shell/src/preview/ give 1316/1316 under the lock. The closure build and both type-checks exit 0; the battery and the implicated gates exit 0. The full app-shell project was NOT MEASURED locally, as declared; CI's shards cover it, read below.
    • Out-of-scope findings: MetadataDraftHeader, the declared row of listDrafts(), has no member although the spec declares it, so the hooks read the key through any. The publish advisory event omits member. The review asked for a follow-up card: filed data-objectstack: MetadataDraftHeader (the declared row of listDrafts()) has no member, though @objectstack/spec 18 declares drafts[].member and the rows carry it — consumers cast to any to read it #12413 for both.
    • CI at head: 34 success, 3 skipped, 0 failures (filter=latest), with Spec Main Shape Gate, Type Check and all 12 test shards included.
    • Label: needs:contract-review is removed from the PR in this stroke.

    Next: pr_ready + automerge_enable.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-15T02:54Z


    Generated by Claude Code

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:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2target:v18

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions