diff --git a/content/docs/permissions/system-context.mdx b/content/docs/permissions/system-context.mdx index 0a598b835c..4b69e7d341 100644 --- a/content/docs/permissions/system-context.mdx +++ b/content/docs/permissions/system-context.mdx @@ -196,7 +196,7 @@ assuming `isSystem` covers it is a documented source of bugs. | "It suppresses triggers / record-change automation" | **No.** Only `skipTriggers` does. A bare `{ isSystem: true }` on a seed write re-fired automation on freshly seeded rows and wedged first boot | `metadata-protocol/src/seed-loader.ts:1971` (rationale at `:1881`–`1883`, #3760), `flow.zod.ts:702` | | "It skips the state machine" | **No.** That is `skipStateMachine`, carried by seed replay and by `treatAsHistorical` imports | `objectql/src/engine.ts` FSM gate; see [State Machine](/docs/protocol/objectql/state-machine) | | "It skips validation rules" | **No.** Field shape, `format`, `script` and the rest still run. The `readonly` strip runs *before* validation precisely so a discarded value is not judged | `objectql/src/engine.ts:10008`–`10025` | -| "It preserves a supplied `updated_at` / `updated_by`" | **No.** That is `preserveAudit`, a separate opt-in — and an UPDATE-path exemption only | `field.zod.ts:1537` (#3493 / #6640) | +| "It preserves a supplied `updated_at` / `updated_by`" | **No.** That is `preserveAudit`, a separate opt-in — and an UPDATE-path exemption only | `field.zod.ts:1540` (#3493 / #6640) | | "It stamps `created_by`" | **No.** Audit stamping reads `userId` from the context. A user-less system write stamps nothing — that is today's behaviour, not an error | `runtime-identity.ts:280`–`281` | | "It bypasses every guard" | **No.** The last-admin guard applies to **every** context, `isSystem` included — the deprovision path that actually locks an org out is the system one | `last-admin-guard.ts:299` | | "A client can request it" | **No.** Never settable from inbound HTTP or from an action body | `rest-server.ts:1520`, `:1549`; `domains/actions.ts:404` | diff --git a/packages/spec/src/data/field-rows-option-description.test.ts b/packages/spec/src/data/field-rows-option-description.test.ts index df4c6a3f18..4835a08347 100644 --- a/packages/spec/src/data/field-rows-option-description.test.ts +++ b/packages/spec/src/data/field-rows-option-description.test.ts @@ -21,8 +21,10 @@ * `recordToOption` produces the same key for fetched options — while * `SelectOptionSchema` refused it. The object-definition authoring form has * offered a `description` input all along; the declaration makes the offer - * honest. Per the same inherited ruling, `dependsOn` is deliberately NOT - * declared (the canonical `depends_on` already exists at the field level). + * honest. Per the same inherited ruling the option shape declares + * `description` and no cascade key of its own; the cascade key lives on + * `FieldSchema` as the camelCase `dependsOn`, which objectui mirrors + * (maintainer ruling 2026-09-02 on objectui#6153). * * The ruling's capability expansion STOPS at these keys: the four inert * rich-text editor keys (`toolbar`/`preview`/`minHeight`/`maxHeight`) stay @@ -200,10 +202,12 @@ describe('SelectOptionSchema accepts `description` (objectui#6153, inherited rul // this shape by #5016's option C, and #13671 re-measured that reading for // the FIELD-option surface and kept it (section 3). It stays an // unrecognized_keys refusal until someone rules otherwise — what #13671 - // changed is the OFFER, not this door. `dependsOn`: the inherited #6153 - // ruling resolves it objectui-side (the widget reads the canonical - // field-level `depends_on`); declaring a camelCase twin here is - // explicitly not licensed. + // changed is the OFFER, not this door. `dependsOn`: this option shape + // carries no cascade key of its own, per the inherited #6140 / #6153 + // ruling. The cascade key is `FieldSchema`'s camelCase `dependsOn`, + // which refuses the snake_case `depends_on` with a rename hint, and + // objectui mirrors that spelling (maintainer ruling 2026-09-02 on + // objectui#6153). for (const [key, value] of [['icon', 'circle-dot'], ['dependsOn', 'country']] as const) { const result = SelectOptionSchema.safeParse({ label: 'Open', value: 'open', [key]: value }); expect(result.success, `\`${key}\` unexpectedly parsed — an unruled accepted-set expansion`).toBe(false); diff --git a/packages/spec/src/data/field.zod.ts b/packages/spec/src/data/field.zod.ts index 5a4cdff9de..f093a0a4f6 100644 --- a/packages/spec/src/data/field.zod.ts +++ b/packages/spec/src/data/field.zod.ts @@ -279,9 +279,12 @@ export const SelectOptionSchema = lazySchema(() => strictObject({ * author could legally write. The object-definition authoring form * (`object.form.ts` options repeater) has offered a `description` input all * along; this declaration is what makes that offer honest. Per the same - * inherited ruling, `dependsOn` is NOT declared here — the canonical - * spelling `depends_on` already exists at the field level, and a camelCase - * twin would be a second spelling for a declared concept. + * inherited ruling this option shape declares `description` and no cascade + * key of its own — `field-rows-option-description.test.ts` pins that + * refusal. The cascade key this package declares is the camelCase + * `dependsOn`, the `FieldSchema` member below; objectui mirrors that + * spelling on its own metadata type (maintainer ruling 2026-09-02 on + * objectui#6153). */ description: z.string().optional().describe('Optional secondary/help text for this option. Lookup option search matches it in addition to the label; renderers may show it as supporting text.'), color: z.string().optional().describe('Color code for badges/charts'),