Optional ReadonlycreateRight to create a feature. Absent or false ⟹ refused.
Optional ReadonlyupdateRight to modify an existing feature. Absent or false ⟹ refused.
Optional ReadonlydeleteRight to delete a feature — what enableEditionFull actually gated.
What a layer permits, per operation. Declared under the profile key
edition.Replaced the pair
enableEdition/enableEditionFullon 05/08/2026 (Sprint 5, task 5.9 — decision V1). The second name did not mean what it said: it was read once usefully, ascanDelete(), so "full edition" was in fact the right to delete.Absent means refused — each key independently
No key implies another. Deriving one from another is the exact mechanism by which
enableEditionFullacquired a name that lied — and, at the other end, by which the editor's layer picker briefly read it as a widener (it granted edition to a layer that only carried the delete right). Both readings are gone.⚠️ The default is restrictive, and that is a deliberate departure from the sibling fallback in
packages/plugins/editor/src/config.ts(_acceptsGeometry), which stays permissive on purpose. The difference is what each one gates:editableGeometryTypesis a sub-filter on an already-editable layer, so making it restrictive would render layers unclickable with no other gate to say why.editionis the gate. Measured at the migration: 42 of the 48 layer configs declare nothing and are not editable — a restrictive default changes nothing for them, a permissive one would have granted edition to all 42 in silence.✅ Enforced on EVERY write path since 07/08/2026 (Sprint 8, task 8.7 — B-138). It was enforced on the offline path only (
local-edit-api.ts), while the online path (editor/src/persistence/rest-adapter.ts) issued an unconditionalDELETE: a connected user could delete from a layer declaringdelete: false. The rule now lives in the BOOT graph (kernel/shared/edition-permissions.ts) because it reads the profile, not IndexedDB — and the editor's persistence factory wraps all four of its outputs with a gate consultingGeoLeaf.Storage.mayEdit()before routing, soonline,offline,autoand thecollectiondialect are covered by one guard.⚠️ What this type still does NOT gate: the editor's toolbar gates the delete TOOL on its own
enabledTools, a plugin config, never on the layer. The button may therefore be offered on a layer that refuses — the write itself is refused.