Filed unassigned from framework #10063 per the cross-repo follow-through rule. The framework half has landed as a draft PR; this is the consumer half and belongs here.
📝 Body re-posted once to repair a sanitizer strip: the original wrote the parameter as ?package= followed by an angle-bracketed id placeholder, and the stored bytes lost the placeholder in two places. Spelled PKG_ID below instead. No other edit.
What changed upstream
POST /meta/:type/:name/publish now accepts ?package=PKG_ID and forwards it as the promotion's package binding. Same wire spelling and same normalisation the save door already uses — all and the empty value mean "env-local overlay, no package".
Until that landed, the single-item promotion door named no package at all, so framework #9612's package-closure narrowing at the runtime publish gate could never fire on an HTTP-driven promotion. Studio's designer is the reason that matters: it saves ?mode=draft and POSTs /publish on every edit, so this is the hot path the gate exists to protect.
The ask
Wherever the designer save→publish loop issues the publish, state the same package it already states on the save. Concretely: the save step sends ?package=PKG_ID; the publish that seals it currently sends nothing. One value, one spelling, both steps.
⚠️Send it only when the designer actually has a binding. Omit the parameter entirely for an env-local overlay rather than sending an empty value — the two are the same to the framework's normaliser today, but "omit when unbound" is the shape the save door already follows and keeps the two calls symmetric.
Scope note — what this does and does not buy
⛔ Do not scope or accept this against an expected latency win. Package-closure narrowing has a second, independent gate this does not touch: narrowObjectsToPackageClosure keeps any object carrying no _packageId provenance, unconditionally, and a tenant-authored overlay corpus carries none. On such a corpus, stating the package still narrows nothing. On a provenance-stamped corpus the shipped deriver measures 421 objects → 45.
⇒ The acceptance criterion is "the designer states the binding it already knows, so the narrowing is reachable" — not "publishing got faster". The measurement behind this is on framework #9613; framework #10063 carries the cross-note.
Upstream references
- Framework issue:
objectstack-ai/objectstack#10063 - The narrowing this feeds:
objectstack-ai/objectstack#9612 - Why the payoff is gated twice:
objectstack-ai/objectstack#9613
⚠️ Blocked until the upstream draft PR lands — the parameter is ignored by any framework build older than it, silently (the route did not refuse unknown query parameters before, and still does not).
Unassigned, awaiting triage.
Filed unassigned from framework #10063 per the cross-repo follow-through rule. The framework half has landed as a draft PR; this is the consumer half and belongs here.
📝 Body re-posted once to repair a sanitizer strip: the original wrote the parameter as
?package=followed by an angle-bracketedidplaceholder, and the stored bytes lost the placeholder in two places. SpelledPKG_IDbelow instead. No other edit.What changed upstream
POST /meta/:type/:name/publishnow accepts?package=PKG_IDand forwards it as the promotion's package binding. Same wire spelling and same normalisation the save door already uses —alland the empty value mean "env-local overlay, no package".Until that landed, the single-item promotion door named no package at all, so framework #9612's package-closure narrowing at the runtime publish gate could never fire on an HTTP-driven promotion. Studio's designer is the reason that matters: it saves
?mode=draftand POSTs/publishon every edit, so this is the hot path the gate exists to protect.The ask
Wherever the designer save→publish loop issues the publish, state the same package it already states on the save. Concretely: the save step sends
?package=PKG_ID; the publish that seals it currently sends nothing. One value, one spelling, both steps.Scope note — what this does and does not buy
⛔ Do not scope or accept this against an expected latency win. Package-closure narrowing has a second, independent gate this does not touch:
narrowObjectsToPackageClosurekeeps any object carrying no_packageIdprovenance, unconditionally, and a tenant-authored overlay corpus carries none. On such a corpus, stating the package still narrows nothing. On a provenance-stamped corpus the shipped deriver measures 421 objects → 45.⇒ The acceptance criterion is "the designer states the binding it already knows, so the narrowing is reachable" — not "publishing got faster". The measurement behind this is on framework #9613; framework #10063 carries the cross-note.
Upstream references
objectstack-ai/objectstack#10063objectstack-ai/objectstack#9612objectstack-ai/objectstack#9613Unassigned, awaiting triage.