From 9300bca556c1a377e313773497648a97aee5645b Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 3 Sep 2026 18:51:01 +0000 Subject: [PATCH 1/3] docs(spec): state the measured dependsOn spelling facts in the option-description docblock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The option-description docblock and the two prose sites in its pin file said the canonical spelling `depends_on` already exists at the field level. Measured against the schema it does not: `FieldSchema` declares the camelCase `dependsOn` and refuses `depends_on`, and neither spelling is declared on the option shape. Rewrite the three sites to state only what is measured, and leave the option-face question with objectui#6153 rather than substituting a new justification for the conclusion. Comment text only — no schema member moves. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_0174WZTU6XcFcS7g2kykC53i --- .../data/field-rows-option-description.test.ts | 16 ++++++++++------ packages/spec/src/data/field.zod.ts | 13 +++++++++---- 2 files changed, 19 insertions(+), 10 deletions(-) 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..8111f18574 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. `dependsOn` stays undeclared on this option shape, and so does + * `depends_on`; the key this package declares at the FIELD level is the + * camelCase `dependsOn` (`depends_on` is objectui's field-metadata + * spelling). Whether the option face gets one is pending 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`: undeclared on this + // option shape, and pending objectui#6153 — which spelling the widget + // side lands on is that card's call. Measured today: `FieldSchema` + // declares the camelCase `dependsOn` and refuses `depends_on`; objectui's + // field metadata declares `depends_on` (`BaseFieldMetadata`), which + // `LookupField` reads alongside `dependsOn`. 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..cc17f7cb8d 100644 --- a/packages/spec/src/data/field.zod.ts +++ b/packages/spec/src/data/field.zod.ts @@ -278,10 +278,15 @@ export const SelectOptionSchema = lazySchema(() => strictObject({ * refused it at publish, so the search behaviour was real for a key no * 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. + * along; this declaration is what makes that offer honest. `dependsOn` is + * not declared on this option shape today, and neither is `depends_on` + * (`field-rows-option-description.test.ts` pins the `dependsOn` refusal). + * Measured, the two spellings live apart: this package declares the + * camelCase `dependsOn` on the FIELD shape below and refuses `depends_on` + * there, while `depends_on` is objectui's field-metadata spelling + * (`BaseFieldMetadata.depends_on`, read by `LookupField` alongside + * `dependsOn`). Whether this option face should declare a dependency key, + * and under which spelling, is pending objectui#6153 — not settled here. */ 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'), From 5a1e6e981f38ebba366406a04f8687abf36227b5 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 3 Sep 2026 19:23:00 +0000 Subject: [PATCH 2/3] docs(spec): align the option-shape comments with the 2026-09-02 cascade-key ruling The maintainer amended the inherited reading on 2026-09-02: the contract's field-level cascade key is the camelCase `dependsOn`, objectui mirrors that spelling on its own metadata type, and objectui's snake_case twin retires on its own card. Re-word the three prose sites to that: the option shape declares `description` and no cascade key of its own (the pin file asserts the refusal), and the cascade key is `FieldSchema`'s `dependsOn`. `field.zod.ts` now carries no snake_case occurrence at all; the test file keeps one, naming the spelling `FieldSchema` refuses with a rename hint. No `expect()` changes, no schema member changes. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_0174WZTU6XcFcS7g2kykC53i --- .../field-rows-option-description.test.ts | 20 +++++++++---------- packages/spec/src/data/field.zod.ts | 16 +++++++-------- 2 files changed, 17 insertions(+), 19 deletions(-) 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 8111f18574..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,10 +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. `dependsOn` stays undeclared on this option shape, and so does - * `depends_on`; the key this package declares at the FIELD level is the - * camelCase `dependsOn` (`depends_on` is objectui's field-metadata - * spelling). Whether the option face gets one is pending objectui#6153. + * 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 @@ -202,12 +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`: undeclared on this - // option shape, and pending objectui#6153 — which spelling the widget - // side lands on is that card's call. Measured today: `FieldSchema` - // declares the camelCase `dependsOn` and refuses `depends_on`; objectui's - // field metadata declares `depends_on` (`BaseFieldMetadata`), which - // `LookupField` reads alongside `dependsOn`. + // 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 cc17f7cb8d..f093a0a4f6 100644 --- a/packages/spec/src/data/field.zod.ts +++ b/packages/spec/src/data/field.zod.ts @@ -278,15 +278,13 @@ export const SelectOptionSchema = lazySchema(() => strictObject({ * refused it at publish, so the search behaviour was real for a key no * 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. `dependsOn` is - * not declared on this option shape today, and neither is `depends_on` - * (`field-rows-option-description.test.ts` pins the `dependsOn` refusal). - * Measured, the two spellings live apart: this package declares the - * camelCase `dependsOn` on the FIELD shape below and refuses `depends_on` - * there, while `depends_on` is objectui's field-metadata spelling - * (`BaseFieldMetadata.depends_on`, read by `LookupField` alongside - * `dependsOn`). Whether this option face should declare a dependency key, - * and under which spelling, is pending objectui#6153 — not settled here. + * along; this declaration is what makes that offer honest. Per the same + * 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'), From e302c17d9bc6bfd0ec930d3d99ac4daaf2703ee7 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 3 Sep 2026 19:32:11 +0000 Subject: [PATCH 3/3] docs(permissions): re-anchor the system-context census citation after the docblock reflow `check-system-context-census.mjs --fix` rewrote the one rotted line anchor (`field.zod.ts:1537` to `:1540`): the option-description docblock above the `readonly` declaration changed height, so the page cited a line the census no longer calls a read site while the ledger row it excuses went unused. Pure line rot, repaired by the fixer, not by hand. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_0174WZTU6XcFcS7g2kykC53i --- content/docs/permissions/system-context.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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` |