Skip to content

fix(metadata): publish/discard package drafts in the draft's own org scope (#3115)#3156

Merged
os-zhuang merged 2 commits into
mainfrom
fix/publish-drafts-org-scope
Jul 18, 2026
Merged

fix(metadata): publish/discard package drafts in the draft's own org scope (#3115)#3156
os-zhuang merged 2 commits into
mainfrom
fix/publish-drafts-org-scope

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Problem — #3115

Saving a new object (with fields) in a package via Studio, then clicking Publish, returns no_draft even though the draft was just saved:

{ "success": false, "publishedCount": 0, "failedCount": 1,
  "failed": [{ "type": "object", "name": "",
    "error": "[no_draft] No pending draft exists for object/… — nothing to publish.",
    "code": "no_draft" }] }

Root cause — a cross-layer org-scope asymmetry

Step Endpoint Org scope
Save Draft REST PUT /meta/:type/:name?mode=draft&package=… (rest-server.ts) never threads activeOrganizationId → draft written env-wide (organization_id = NULL)
Publish POST /packages/:id/publish-drafts (http-dispatcher.ts) resolves session.activeOrganizationIdnon-null once a default org is stamped on the session

PR #1852 taught listDrafts to surface env-wide drafts to a non-null active org via $or [{org}, {org IS NULL}] — so the Publish CTA appears — but the publish path was never updated to match: promoteDraft still looks the draft up with a strict organization_id = <org> equality and 404s (no_draft) on the env-wide row it can never match. discardPackageDrafts had the identical latent gap (delete under the request org silently no-ops on env-wide rows).

Same "orphaned draft" bug as #1852, one layer deeper: the pending-changes list was fixed, the publish/discard action wasn't.

Fix

  • SysMetadataRepository.listDrafts() now projects each draft's own organizationId.
  • publishPackageDrafts / discardPackageDrafts promote / delete each listed draft in the scope it actually lives in (env-wide stays env-wide, per-org stays per-org) instead of forcing the caller's active org. Seed-body capture and the ADR-0067 revert-plan pre-state read are scoped the same way.

Package-owned metadata is env-level, so keeping it env-wide on publish is the correct provenance — the bug was purely that publish couldn't reach the env-wide draft.

Tests

  • protocol-publish-drafts-org-scope.test.ts (new) — reproduces the exact [no_draft] … nothing to publish. error against the real listDrafts+promoteDraft interaction (faithful stub engine honouring $or / IS NULL), then asserts publish succeeds env-wide; plus a no-regression case for a genuinely org-scoped draft.
  • sys-metadata-repository-list-drafts.test.ts — asserts the new organizationId projection.
  • Full metadata-protocol (37) + objectql (905) suites green.

Verification

Traced end-to-end: objectui Studio calls metadataClient.save(type, name, body, { mode: 'draft' }) → env-wide PUT /meta?mode=draft; publish via usePublishAllDraftsPOST /packages/:id/publish-drafts. The reported error string is only reachable with an env-wide draft + non-null publish org, which this fix resolves.

🤖 Generated with Claude Code

…scope (#3115)

Studio "Save Draft" goes through REST `PUT /meta/:type/:name?mode=draft`,
which never threads the session's `activeOrganizationId` into `saveMetaItem`
— so the draft row is written env-wide (`organization_id = NULL`). "Publish"
goes through `POST /packages/:id/publish-drafts`, which DOES resolve the
active org (non-null once a default org is stamped on the session).

PR #1852 taught `listDrafts` to surface those env-wide drafts to a non-null
active org via `$or [{org}, {org IS NULL}]` — so the Publish CTA appears —
but the publish path (`promoteDraft`) still looked the draft up with a STRICT
`organization_id = <org>` equality and 404'd (`[no_draft] No pending draft
exists …`) on the env-wide row it could never match. `discardPackageDrafts`
had the identical latent gap (delete under the request org silently no-ops on
env-wide rows).

Fix: `listDrafts` now projects each draft's own `organizationId`, and
`publishPackageDrafts` / `discardPackageDrafts` promote / delete each draft in
THAT scope (env-wide stays env-wide, per-org stays per-org) — so the
pending-changes list and the publish/discard paths agree. Seed-body capture
and the ADR-0067 revert-plan pre-state read are scoped the same way.

Regression tests reproduce the exact `no_draft` error (env-wide draft +
non-null publish org) and assert publish now succeeds env-wide, plus a
no-regression case for a genuinely org-scoped draft.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Canceled Canceled Jul 18, 2026 1:26am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/metadata-protocol, @objectstack/objectql.

13 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/metadata-protocol, @objectstack/objectql)
  • content/docs/data-modeling/formulas.mdx (via packages/objectql)
  • content/docs/deployment/migration-from-objectql.mdx (via @objectstack/objectql)
  • content/docs/deployment/vercel.mdx (via @objectstack/objectql)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/objectql)
  • content/docs/kernel/services.mdx (via @objectstack/objectql)
  • content/docs/permissions/authentication.mdx (via @objectstack/objectql)
  • content/docs/plugins/index.mdx (via @objectstack/objectql)
  • content/docs/plugins/packages.mdx (via @objectstack/objectql)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/objectql)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/objectql)
  • content/docs/releases/implementation-status.mdx (via @objectstack/objectql)
  • content/docs/releases/v9.mdx (via @objectstack/objectql)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

…e fix (#3115)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation tooling labels Jul 18, 2026
@os-zhuang
os-zhuang merged commit b8a21ad into main Jul 18, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the fix/publish-drafts-org-scope branch July 18, 2026 02:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant