You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[Decision] When a curated capability name is already held in the platform bucket, should the seeder keep declining — or adopt, backfill, or refuse the collision at authoring time? #8552
Surfaced while reviewing #8470 / PR #8537. Not blocking that PR — it lands with the conservative behaviour and reports the collision loudly. This card is the policy question the PR deliberately declined to answer, and it is filed because the dev was right to decline it, not because anything is wrong with the fix.
The state the question is about
After #8537, the curated seeder looks up { name, managed_by: 'platform', organization_id: null } — the row the platform owns. If that matches nothing and the insert is then refused by the unique key, the platform's curated definition is missing from sys_capability installation-wide, and the seeder counts it (blockedCurated) and warns on every boot.
It declines to resolve the collision, for two stated reasons: adopting a differently-stamped row into the platform's identity would reverse #5876's ruling that "not provably ours" resolves to leave-it-alone, and backfilling a stamp is a data migration. Both are calls above the implementer's pay grade, so neither was made.
What was measured, not assumed
Two of the three non-platform provenances in that bucket are reachable, and one is ordinary rather than exotic:
managed_by: 'admin' — reachable and ordinary.organization_id auto-stamping lives in the enterprise @objectstack/organizations runtime, which is also what activates every walled posture. A deployment without it is single posture with no stamper, so every Setup-authored capability row lands in the NULL-organization bucket. That is the default community shape.
managed_by: 'package' — reachable via name promotion, with real instances.bootstrapDeclaredCapabilities refuses a name in PLATFORM_CAPABILITY_NAMES, but a package that declared a name before the platform curated it left a managed_by: 'package' row there. setup.write and manage_sharing were both added to the curated set after the fact.
no managed_by at all — NOT engine-reachable. The field is required: true with defaultValue: 'admin', and applyFieldDefaults resolves defaults on insert before the beforeInsert hooks, so an insert omitting it stores 'admin'. (The diagnostic still handles it, because a message must not assert what it cannot observe.)
Why this is a decision and not a follow-up bug
For the package case specifically, #8537changes the outcome on already-upgraded installations rather than only fixing a defect:
installation where a package declared setup.write before it was curated
the seeder found that row by { name }, took the update branch, and overwrote it with the platform copy — so the platform definition effectively existed
the scoped lookup matches nothing, the insert is refused, and the platform definition is absent installation-wide, with a warning every boot
Neither state is good. The new one is the one ADR-0066 D1 implies (do not clobber another author) and it is honest about itself, which is why it is the right thing to ship now. But whether it is the right long-term answer on the two deployment shapes above is a product call.
The options, stated without a recommendation
Keep declining — the shipped behaviour. The platform definition stays absent on colliding installations; the operator sees a warning naming the blocking row's provenance and has to resolve it by hand.
Backfill the managed_by stamp for known-curated names in the NULL bucket. A data migration, and it decides on the operator's behalf that those rows were the platform's.
Refuse the collision at authoring time — stop Setup from creating a sys_capability row whose name is in PLATFORM_CAPABILITY_NAMES, so the state cannot arise going forward. Does nothing for installations already carrying one, so it likely pairs with 1 or 3.
⛔ I am not answering this on the maintainer's behalf, and I have deliberately not ranked the options. I will note only that option 4 is the one that matches the standing principle recorded 2026-08-12 — "if the platform cannot honour a declaration, refuse it at the latest checkpoint that can see the whole picture, name the offending key path, and never answer 200" — because authoring a curated name in Setup is precisely a declaration the platform later cannot honour. Whether that principle should govern here is the question, not the answer.
Surfaced while reviewing #8470 / PR #8537. Not blocking that PR — it lands with the conservative behaviour and reports the collision loudly. This card is the policy question the PR deliberately declined to answer, and it is filed because the dev was right to decline it, not because anything is wrong with the fix.
The state the question is about
After #8537, the curated seeder looks up
{ name, managed_by: 'platform', organization_id: null }— the row the platform owns. If that matches nothing and the insert is then refused by the unique key, the platform's curated definition is missing fromsys_capabilityinstallation-wide, and the seeder counts it (blockedCurated) and warns on every boot.It declines to resolve the collision, for two stated reasons: adopting a differently-stamped row into the platform's identity would reverse #5876's ruling that "not provably ours" resolves to leave-it-alone, and backfilling a stamp is a data migration. Both are calls above the implementer's pay grade, so neither was made.
What was measured, not assumed
Two of the three non-platform provenances in that bucket are reachable, and one is ordinary rather than exotic:
managed_by: 'admin'— reachable and ordinary.organization_idauto-stamping lives in the enterprise@objectstack/organizationsruntime, which is also what activates every walled posture. A deployment without it issingleposture with no stamper, so every Setup-authored capability row lands in the NULL-organization bucket. That is the default community shape.managed_by: 'package'— reachable via name promotion, with real instances.bootstrapDeclaredCapabilitiesrefuses a name inPLATFORM_CAPABILITY_NAMES, but a package that declared a name before the platform curated it left amanaged_by: 'package'row there.setup.writeandmanage_sharingwere both added to the curated set after the fact.managed_byat all — NOT engine-reachable. The field isrequired: truewithdefaultValue: 'admin', andapplyFieldDefaultsresolves defaults on insert before the beforeInsert hooks, so an insert omitting it stores'admin'. (The diagnostic still handles it, because a message must not assert what it cannot observe.)Why this is a decision and not a follow-up bug
For the
packagecase specifically, #8537changes the outcome on already-upgraded installations rather than only fixing a defect:setup.writebefore it was curated{ name }, took the update branch, and overwrote it with the platform copy — so the platform definition effectively existedNeither state is good. The new one is the one ADR-0066 D1 implies (do not clobber another author) and it is honest about itself, which is why it is the right thing to ship now. But whether it is the right long-term answer on the two deployment shapes above is a product call.
The options, stated without a recommendation
managed_bystamp for known-curated names in the NULL bucket. A data migration, and it decides on the operator's behalf that those rows were the platform's.sys_capabilityrow whose name is inPLATFORM_CAPABILITY_NAMES, so the state cannot arise going forward. Does nothing for installations already carrying one, so it likely pairs with 1 or 3.⛔ I am not answering this on the maintainer's behalf, and I have deliberately not ranked the options. I will note only that option 4 is the one that matches the standing principle recorded 2026-08-12 — "if the platform cannot honour a declaration, refuse it at the latest checkpoint that can see the whole picture, name the offending key path, and never answer 200" — because authoring a curated name in Setup is precisely a declaration the platform later cannot honour. Whether that principle should govern here is the question, not the answer.
Related
bootstrapSystemCapabilitiesreconciles an arbitrary row when a curated capability name exists in more than one organization —find(..., limit: 1)has no ORDER BY, so the platform's own row can be left unseeded #8470 / PR fix(security): the curated capability seeder reconciles the row the platform owns, not whichever row shares the name (#8470) #8537 — the fix that makes this state observable and names it.bootstrapSystemCapabilitiesalso leaves the platform bucket unseeded when an organization holds the name — the #5876 guard skips instead of inserting #8536 — the DERIVED half has the same unseeded-bucket shape, on the halfbootstrapSystemCapabilitiesreconciles an arbitrary row when a curated capability name exists in more than one organization —find(..., limit: 1)has no ORDER BY, so the platform's own row can be left unseeded #8470's ruling excluded.Filed unassigned by the
domain:metadataPM seat.