Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .changeset/seed-read-drops-dead-org-rung.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@objectstack/runtime": patch
---

The package-publish seed read-back no longer runs a two-attempt org-then-env ladder whose rungs resolve the same row.

`applyPublishedSeeds` — the route-level seed apply behind `POST /packages/:id/publish-drafts`, which runs for protocols that do not self-apply seeds inside `publishPackageDrafts` — read each just-published `seed` body twice when the session had an active organization: once naming the organization, then once env-wide. The comment above it said the first attempt tried the active org and the second fell back, "and resolving the wrong scope here is what silently produced `0 rows loaded`".

That was true when it was written and is not true now. `seed` declares `allowOrgOverride: false`, and `getMetaItem` resolves `organizationIdForMetaRead(request.type, request.organizationId)` once at its top and spends that binding — never the raw argument — on every read beneath it. The predicate answers `undefined` for every non-overridable type, so both rungs asked the engine the same predicates and served the same answer. Measured rather than reasoned: against the shipping protocol over one store, the two requests produce byte-identical engine reads and byte-identical answers on both the hit and the miss branch, and neutering the second rung reddens nothing on a pinned publish-then-read path (a `view` control confirms the same comparison does separate the two rungs for an org-overridable type).

The read is now a single call naming no organization, and the comment states that the scope is decided by the registry flag and the gate inside `getMetaItem` rather than by this call site — matching the sentence the `app` flip in the same file already carries.

One observable changes, and only on the failure branch: `getMetaItem` answers a wrapper rather than a falsy value for a name it cannot resolve, so the second rung was in practice reached only when the read *threw* — where it repeated the identical failing read and appended the same sentence to the client-facing `seedApplied.errors[]` twice. A failed read-back is now reported once. Nothing about which row a publish resolves, or whether its rows load, moves.
16 changes: 9 additions & 7 deletions packages/metadata-protocol/src/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7550,7 +7550,7 @@ export class ObjectStackProtocolImplementation implements
// hydration walks past.
//
// ⇒ What is left to move is the runtime callers that hand this method a
// RAW active organization. FOUR, across two files — the population is
// RAW active organization. THREE, all in one file — the population is
// stated with the method that establishes it, because the first
// enumeration of it named only the first file and was wrong: grep every
// `getMetaItem(` / `getMetaItemCached(` invocation in the repo, then
Expand All @@ -7560,12 +7560,14 @@ export class ObjectStackProtocolImplementation implements
// be right about scope, by construction.
// • `runtime/src/domains/meta.ts:768` — `singularType` off the URL, so
// it moves only for the non-overridable half of what it serves.
// • `runtime/src/domains/packages.ts:1239` (`applyPublishedSeeds`,
// organization from `deps.resolveActiveOrganizationId`) — `type:
// 'seed'`, also non-overridable, so its org-first attempt now reads
// the env-wide partition directly. It hand-rolls the same fallback
// as a second attempt, so what it used to reach on the second try it
// now gets on the first.
// A FOURTH used to sit here: `applyPublishedSeeds` in
// `runtime/src/domains/packages.ts`, `type: 'seed'`, equally
// non-overridable. It hand-rolled an org-then-env ladder that this gate
// had turned into a byte-identical repeat — both rungs asking the
// engine the same predicates and serving the same answer. #15068
// measured that (ablation: neutering the second rung reddened nothing
// on a pinned publish-then-read path) and collapsed it to a single read
// naming no organization at all, so it now belongs to the bucket below.
// Every other invocation either names no organization at all or is a
// REST door that already computed `organizationIdForMetaRead` — the
// idempotence legs above are what make those two cases no-ops.
Expand Down
Loading
Loading