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
{{ message }}
Repository navigation
Commit e5c06cd
Browse filesBrowse the repository at this point in the historyBrowse files
docs(spec,adr): regenerate the v17 artifacts and record the ADR-0103 close-out (#3355)
- gen:schema / gen:spec-changes / gen:upgrade-guide / gen:docs / gen:api-surface
- objects.mdx: the bucket table, the engine-owned-vs-system-data section, the
`userActions`-narrows contract and a v16 upgrade callout
- ADR-0103: a v17 addendum completing D5 (which had explicitly deferred the
removal), recording the rejected alternatives, the default flip and its one
affordance consequence, and the new mis-assignment refusal
All 11 spec gates pass (liveness, empty-state, authorable-surface, docs,
api-surface, spec-changes, upgrade-guide, skill-refs, skill-docs,
skill-examples, variant-docs).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012C2cd7tL8QDoZ2QKN3djJ5
Copy file name to clipboardExpand all lines: content/docs/data-modeling/objects.mdx
+34-20Lines changed: 34 additions & 20 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -215,8 +215,8 @@ indexes: [
215
215
| Property | Type | Description |
216
216
| :--- | :--- | :--- |
217
217
|`isSystem`|`boolean`| System object, protected from deletion (default: `false`) |
218
-
|`managedBy`|`enum`| Lifecycle bucket that sets the default CRUD affordances and write policy — `'platform'` (default), `'config'`, `'system'`, `'engine-owned'`, `'append-only'`, `'better-auth'`. See [Lifecycle bucket](#lifecycle-bucket-managedby) below. |
219
-
|`userActions`|`object`| Per-object override of the CRUD affordances the `managedBy` default implies — `{ create?, edit?, delete?, import?, exportCsv? }`. This is what makes a `system`/`append-only`object admin/user-writable. See [Lifecycle bucket](#lifecycle-bucket-managedby). |
218
+
|`managedBy`|`enum`| Lifecycle bucket that sets the default CRUD affordances and write policy — `'platform'` (default), `'config'`, `'system-data'`, `'engine-owned'`, `'append-only'`, `'better-auth'`. See [Lifecycle bucket](#lifecycle-bucket-managedby) below. |
219
+
|`userActions`|`object`| Per-object override of the CRUD affordances the `managedBy` default implies — `{ create?, edit?, delete?, import?, exportCsv? }`. This is what NARROWS a `system-data` object, or opens a verb on an `engine-owned`/`append-only`one. See [Lifecycle bucket](#lifecycle-bucket-managedby). |
220
220
|`sharingModel`|`enum`| Org-Wide Default record visibility (ADR-0055/0056/0090). Canonical four only: `'private'`, `'public_read'`, `'public_read_write'`, `'controlled_by_parent'` (detail visibility derived from its master). The legacy aliases (`'read'`, `'read_write'`, `'full'`) were removed from the enum (ADR-0090 D4) — authoring rejects them. Unset on a custom object resolves to `'private'` (ADR-0090 D1) |
221
221
|`ownership`|`enum`| Record-ownership model: `'user'` (default — injects the reassignable `owner_id` lookup, engaging owner-scoped RLS, "My" views and owner reports), `'org'`, or `'none'` (no per-record owner — Dataverse-style catalog / junction tables, skips `owner_id`). Distinct from the package `own`/`extend` contribution kind. |
222
222
|`validations`|`ValidationRule[]`| Object-level validation rules (see [Validation](/docs/data-modeling/validation)) |
@@ -233,44 +233,58 @@ bare bucket string.
233
233
| :--- | :--- |
234
234
|`platform`|**Default.** User-owned business data — full New / Import / Edit / Delete. |
235
235
|`config`| Admin-authored configuration — New / Edit / Delete, no CSV import. |
236
-
|`system`| Platform-defined schema holding **admin/user-writable data** (RBAC link tables, preferences, messaging config). Locked by default; each object opens its writes via`userActions`. |
236
+
|`system-data`| Platform-defined schema holding **admin/user-writable data** (RBAC link tables, preferences, messaging config). Full CRUD by default; narrow it with`userActions`. |
237
237
|`engine-owned`| Runtime rows a platform service owns end to end — generic CRUD hidden, exposed `['get', 'list']` only, **no user writes ever**. |
|`better-auth`| Identity tables owned by the better-auth driver — generic user-context CRUD is suppressed; mutations flow through the auth API (sign-in, invite, reset). |
240
240
241
-
**`engine-owned` vs. writable `system` objects (ADR-0103).**Two buckets share
242
-
the same locked default matrix but say different things:
241
+
**`engine-owned` vs. `system-data`(ADR-0103, #3355).**Both hold a
242
+
platform-defined schema no tenant may model; they differ on who owns the *rows*:
|**icon**|`string`| optional | Icon name (Lucide/Material) for UI representation |
117
117
|**isSystem**|`boolean`| optional | Is system object (protected from deletion; defaults its org-wide sharing to public when no sharingModel is set — plugin-sharing) |
118
-
|**managedBy**|`Enum<'platform' \| 'config' \| 'system' \| 'engine-owned' \| 'append-only' \| 'better-auth'>`| optional | Lifecycle bucket — platform (user CRUD) \| config (admin authored) \| system (engine-managed schema, writable via userActions) \| engine-owned (engine owns the lifecycle, no user writes) \| append-only (audit) \| better-auth (identity). UI clients honour the resolved affordance matrix. |
Copy file name to clipboardExpand all lines: docs/protocol-upgrade-guide.md
+3Lines changed: 3 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -162,6 +162,8 @@ The datasource close-out also graduates the four legacy `datasource.config` spel
162
162
163
163
The `script` flow node converges on its one real path (#4343). It had four ways to name what it ran and only one of them ran anything: `config.actionType: 'email' | 'slack'` were logger-backed stubs that wrote a line, reported success and delivered nothing under any configuration — with `config.template` / `.recipients` / `.variables` feeding a message no channel ever sent; inline `config.script` was recognized and never executed (the built-in runtime has no server-side JS sandbox), so the node warned and no-op'd; and every other `actionType` value was shorthand for a registered-function name, a second spelling of `config.function`. All five keys are retired and `function` becomes required, which is also what finally made the contract PARSEABLE: while the legal key set depended on `actionType`, a flat parse would either reject valid shapes or wave everything through, so `script` (with `subflow`) now runs through the same execute-time contract parse #4277 gave the flat builtins. A shorthand `actionType` CONVERTS into `function` — that is what it meant — unless `function` is already set, in which case it was dead metadata the executor never reached. The other four are dropped outright: nothing read them, so there is no value to preserve, and rebuilding the intent is an authoring decision the tombstones prescribe per branch (a `notify` node for mail — it delivers through the messaging service, the in-app inbox by default and real email once `@objectstack/plugin-email` is installed; a `connector_action` with the Slack connector, or an `http` node posting to a webhook, for Slack; a registered function for an inline body). Retired from the load path for the same reason as the rest: absorbing `actionType: 'email'` silently would let an author keep believing the flow sends mail.
164
164
165
+
Finally, `object.managedBy: 'system'` is retired in favour of `'system-data'` (#3355), finishing the split ADR-0103 began in v16. That split was deliberately ADDITIVE: the 20 engine-owned objects moved to the new explicit `engine-owned`, and the 8 admin/user-writable ones — the RBAC link tables, `sys_user_preference`, the three messaging config grids — stayed behind on `system`. What was left is a value whose name describes the half that had already moved out: "system" sitting on precisely the objects a user writes. That is not a cosmetic complaint. An author choosing between `system` and `engine-owned` had nothing in the vocabulary to choose on, so the bucket was re-overloadable by anyone reading the name in good faith — a model author most of all. `system-data` states both boundaries: the SCHEMA is the platform's (versus `platform`, which is tenant-modelled), the DATA is the admin's or the user's (versus `engine-owned`, where the engine owns both). Reusing `config` was considered and rejected — `sys_user_preference` is user-owned rather than admin-authored, and `config` suppresses CSV import — as was `platform-data`, which sits one word away from the unrelated `platform` in the same closed enum and would reintroduce the confusion at the point of choosing. Because v16 already drained the engine side, the conversion is a ONE-TO-ONE mechanical value rename with no judgement call. One deliberate consequence: `system` defaulted LOCKED and each object re-opened its writes through `userActions`, while `system-data` defaults WRITABLE, so those blocks become redundant and are deleted (keep `userActions` only to NARROW). No enforcement moves — the engine write guard, the DelegatedAdminGate, RLS and permission sets all adjudicate off resolved affordances and the principal, never off the bucket name; `system-data` simply joins `platform`/`config` as a bucket the guard does not cover, because a writable default has nothing to fail closed on. Retired from the load path: the enum rejection is what teaches the new spelling, and absorbing `'system'` silently at load would leave every author writing the name this rename exists to retire.
166
+
165
167
### Mechanical (applied for you)
166
168
167
169
| Conversion | Surface | Change | Load window |
@@ -194,6 +196,7 @@ The `script` flow node converges on its one real path (#4343). It had four ways
194
196
|`datasource-inert-blocks-removed`|`datasource.retryPolicy / datasource.healthCheck / datasource.external.label / datasource.external.requirePermission`| datasource keys 'retryPolicy'/'healthCheck' and external 'label'/'requirePermission' removed (#4583 — nothing retried, nothing probed on a schedule, and the federation label/permission were read by nobody) | retired — `migrate meta` only |
|`flow-node-script-branch-keys-removed`|`flow.node.script.config.actionType / flow.node.script.config.template / flow.node.script.config.recipients / flow.node.script.config.variables / flow.node.script.config.script`| script flow-node config keys 'actionType' (→ 'function' when it was shorthand for one; otherwise removed — 'email'/'slack' were logger-backed stubs that delivered nothing), plus 'template' / 'recipients' / 'variables' (fed those stubs) and 'script' (inline JS the runtime never executed) (#4343) | retired — `migrate meta` only |
199
+
|`object-managed-by-system-to-system-data`|`object.managedBy`| object managedBy 'system' → 'system-data' (#3355 — ADR-0103's residual bucket named the engine-owned half v16 had already moved out to `engine-owned`; the rename leaves the name describing what the bucket actually holds: admin/user-writable platform data) | retired — `migrate meta` only |
197
200
198
201
### Semantic (delegated to you, with acceptance criteria)
0 commit comments