Skip to content

Commit 22f54b0

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/issue-21898-builtin-node-config-values-judged
2 parents d1c7d8d + c9761cd commit 22f54b0

9 files changed

Lines changed: 466 additions & 45 deletions
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@objectstack/metadata-protocol': patch
3+
---
4+
5+
A metadata publish consults the item lock at the package key it resolved
6+
7+
- A publish that states no package promotes the draft row it resolves, under that row's own package. Its ADR-0010 lock lookup now uses that same resolved key (the stated package, else the draft row's own), the key the gate reads the draft under and the promotion writes under, instead of only the package the request stated. Where several packages' rows declare the strictest lock, the refusal now carries the lock of the package whose draft is being promoted.
8+
- The authoring gate's package narrowing is unchanged: it still uses only the package the caller stated.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/metadata-protocol': minor
3+
---
4+
5+
A metadata publish promotes only the draft its gate judged
6+
7+
Clause-②: yes (widening)
8+
9+
- A publish (`publishMetaItem`, and each promotion of `publishPackageDrafts`) reads the draft to judge it and then promotes the draft row. The promotion is now handed the judged draft's hash. A draft saved after the judgement, or a draft that appears where the judgement found none, is refused with `409 METADATA_CONFLICT`, and nothing is published. Publishing again judges and promotes the current draft.
10+
- `SysMetadataRepository.promoteDraft` takes a new optional `expectedDraftHash` (`string | null`). When it is stated, the draft row the promotion reads must carry that hash (with `null`, no draft row may exist); otherwise the promotion throws a `ConflictError` before anything is written. When it is omitted, the promotion behaves as before.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@objectstack/metadata-protocol': patch
3+
---
4+
5+
The organization-scoped save check judges a view overlay against every package's environment-wide definition of its row
6+
7+
- An organization-scoped `view` save or publish in the organization the anonymous form endpoints read is refused when it would leave open a form the environment-wide definition withdraws. Its row anchor is now resolved per package, the way the list read resolves each package's item: each package's own environment-wide row, else the package-less environment-wide row (which stands in for every package), else that package's artifact. Before, with no environment-wide row stored, it judged only the first package's artifact in registry order, and a stored row of any one package hid every package's artifact of the name.
8+
- The known limit stated with the public-form withdrawal ("it may over-close, never under-close") is narrowed. A withdrawal of a view name still closes that name in every package, so it may over-close. The organization-scoped save check judges every package's environment-wide definition of the name. The anonymous endpoints do too, with one exception: where a package's environment-wide copy of a view container is saved, the endpoints read that copy's expansion alone for each form it expands, and can miss another package's withdrawal of that form, whether saved or shipped, until the form is withdrawn in every saved environment-wide copy of that container as well. Reading each package's expansion separately is tracked in #21967.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@objectstack/metadata-protocol': patch
3+
---
4+
5+
The view list serves one item per package for a view name that several installed packages ship, whether or not a view row is stored
6+
7+
- Where two installed packages ship a view of the same name, the list read (`getMetaItems` for `view`) now serves each package's item of that name, as it already did while no view row was stored. Only a name that a stored view container's expansion writes is upserted by name.
8+
- The environment-wide view list is the layer the anonymous form endpoints judge a withdrawal against. A package-less organization copy of the view, stored before one package withdrew the form, is now judged against every package's body of the name there, so it stays closed whichever package withdraws.

‎content/docs/ui/public-data-collection.mdx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,13 @@ A withdrawal is a kill switch across metadata layers. If the environment-wide de
6262

6363
**Which form a withdrawal closes.** Two checks apply the rule, and they match forms differently:
6464

65-
- **Saving and publishing in an organization** judges the organization's copy against the stored environment-wide definition it overrides (the row its copy is keyed by). Inside that definition, a withdrawn form is the same form as the organization's when they share a place (`form`, the same `formViews` entry, or the view's own `config`) or a public link. A match on either is enough, so a renamed `formViews` key, a `form.name`, a move to another place, a renamed expanded item, and a new or re-cased slug all still count as the same form. A form that differs from every withdrawn form in both place and link is a different form, such as a sibling in the same view.
65+
- **Saving and publishing in an organization** judges the organization's copy against the stored environment-wide definition it overrides (the row its copy is keyed by, in each package that ships it). Inside that definition, a withdrawn form is the same form as the organization's when they share a place (`form`, the same `formViews` entry, or the view's own `config`) or a public link. A match on either is enough, so a renamed `formViews` key, a `form.name`, a move to another place, a renamed expanded item, and a new or re-cased slug all still count as the same form. A form that differs from every withdrawn form in both place and link is a different form, such as a sibling in the same view.
6666
- **The anonymous endpoints** judge each form by the name of the view item they serve. Beneath the organization's read they read the environment-wide view list, and a form is closed when the environment-wide item of the same name explicitly withdraws a form in the same place or under the same link.
6767
- **A different view is a different form.** A different view that uses the same public link (for example, another app's "contact us" form) neither closes this one nor is closed by it.
6868

6969
**Forms a package ships.** A package's form is part of the environment-wide definition, not a separate layer beneath it. A definition parsed by the stack schema (strict `defineStack`, the default) gets the schema's default `enabled: false`, so a shipped form that keeps its link without setting `enabled: true` counts as withdrawn and an organization's copy cannot open it. A definition loaded without that parse (`defineStack(..., { strict: false })` or a hand-built manifest) is judged as written: a switch it leaves out is absent, which is not a withdrawal, so set `enabled: false` explicitly to ship a form closed. The environment-wide definition is the administrator's switch: an environment-wide save may open a form that the package ships closed.
7070

71-
**Known limit: packages and names.** A withdrawal of a view name closes that name in every package. When two packages each ship a view of the same name, one package's withdrawal also closes the other package's form of that name. This may close more than was meant, but it never leaves a withdrawn form open. Per-package precision is tracked in #21934.
71+
**Known limit: packages and names.** A withdrawal of a view name closes that name in every package. When two packages each ship a view of the same name, one package's withdrawal also closes the other package's form of that name, so this may close more than was meant. The organization-scoped save check judges every package's environment-wide definition of the name. The endpoints do too, with one exception: where a package's environment-wide copy of a view container is saved, the endpoints read that copy's expansion alone for each form it expands, and can miss another package's withdrawal of that form, whether saved or shipped. To close such a form at the endpoints, withdraw it in every saved environment-wide copy of that container as well. Reading each package's expansion separately is tracked in #21967.
7272

7373
**Known limit.** The save check runs only when an organization's copy is saved or published. A copy that was already stored before the environment-wide withdrawal, or that a rollback or revert restores, is judged only by the endpoints, which match by served item name. If that copy keeps the form open under a different key or place than the environment-wide definition, the endpoints can still serve it. To close it, withdraw the form in that organization's copy too; the next organization-scoped save of a copy that keeps it open is refused.
7474

‎packages/metadata-core/src/anonymous-form-intake.ts‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -322,9 +322,16 @@ function anonymousFormExplicitWithdrawals(view: unknown): Array<{ slot: string;
322322
* and closes nothing. The package a body is bound to is NOT compared: a
323323
* withdrawal of a name closes that name's form in every package (a known
324324
* limit that fails closed: it may over-close another package's form of the
325-
* same name, never under-close). A layer with no body of the row, or whose body has no
326-
* explicit withdrawal, withdraws nothing, so a form published only in an
327-
* organization stays open there.
325+
* same name). It judges only the bodies the layer holds, so a caller closes a
326+
* name in every package only when its layer holds every package's body of the
327+
* name. The organization-scoped write door anchors one body per package. The
328+
* env-wide view list the anonymous doors read holds one item per package of a
329+
* name, with one exception: where a package's env-wide copy of a view
330+
* container is saved, the list holds that copy's expansion alone for each form
331+
* it expands, so the doors can miss another package's withdrawal of that
332+
* form, whether saved or shipped (per-package expansion is #21967). A layer
333+
* with no body of the row, or whose body has no explicit withdrawal, withdraws
334+
* nothing, so a form published only in an organization stays open there.
328335
*/
329336
export function anonymousFormIntakeWithdrawnIn(
330337
layer: ReadonlyArray<unknown>,

0 commit comments

Comments
 (0)