Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
d14fbe0
feat(spec,metadata-protocol)!: rename the type registry's allowOrgOve…
claude Oct 11, 2026
778aa60
test: rename the registry flag across the suites; pin the tombstone, …
claude Oct 11, 2026
22a0bdc
docs,tooling: the overlay whitelist table, checker column and docs na…
claude Oct 11, 2026
9686793
docs(references): regenerate for allowEnvironmentOverlay and the corr…
claude Oct 11, 2026
d98067c
changeset: the ADR-0087 marker names the D3 id the gate resolves
claude Oct 11, 2026
6b3de41
spec(contracts): MetadataTypeInfo.supportsOverlay says what it gates
claude Oct 11, 2026
b8b9b1f
Merge remote-tracking branch 'origin/main' into claude/issue-22340-s2…
claude Oct 11, 2026
077a4de
spec,metadata-protocol: supportsOverlay's carve-out takes the landed …
claude Oct 11, 2026
a169541
docs(references): regenerate for the landed carve-out wording
claude Oct 11, 2026
e684a2e
test(spec): the absence pin counts the refusal pin apart as its live …
claude Oct 11, 2026
088afc6
spec: the rename prescription names the published npm major (check:fu…
claude Oct 11, 2026
5202331
Merge origin/main into claude/issue-22340-s2-rename (pin round)
claude Oct 12, 2026
c0d91e9
regen: content/docs/references/system/email-template.mdx from the mer…
claude Oct 12, 2026
fa5dcbd
spec: the rename prescription carries no version word; a history comm…
claude Oct 12, 2026
67560ed
chore(objectui): move the console pin to e5311165a8d6 (objectui#12168…
claude Oct 12, 2026
2e15086
chore(objectui): the console changeset, the regenerated SDUI manifest…
claude Oct 12, 2026
49ef13a
regen: content/docs/references/ui/view.mdx — the FormField.span descr…
claude Oct 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .changeset/22340-registry-allow-environment-overlay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
'@objectstack/spec': major
'@objectstack/metadata-protocol': major
---

feat(spec,metadata-protocol)!: the metadata type registry's `allowOrgOverride` is renamed to `allowEnvironmentOverlay`, on the registry and on `GET /meta/types`

Clause-②: yes (narrowing)

<!-- adr-0087: registered metadata-type-registry-allow-org-override-renamed -->

**BREAKING**: a renamed authorable key and a renamed response field, shipped as `major` on the v18 line (`.changeset/pre.json` is open on `main` in `next` pre mode, so the release is `18.0.0-next.*`).

**Why.** ADR-0131 D6 retired the per-organization overlay axis: every metadata write and read is environment-wide. The registry flag kept the name that said "per-org" while it decided one environment-scope question at every door — whether an environment may overlay an item of the type that a managed package ships: the metadata protocol's save door, the managed-content seal on write and on the served read, the repository's put gate, and Studio's write gate through `GET /meta/types`. It is renamed to say that. One key, not two, and not the old name with a new meaning; no window in which both spellings are accepted or served.

## FROM → TO

| where | you wrote / read | write / read instead |
|:--|:--|:--|
| a `DEFAULT_METADATA_TYPE_REGISTRY` entry (`MetadataTypeRegistryEntry`, `@objectstack/spec/kernel`) | `allowOrgOverride: true` | `allowEnvironmentOverlay: true` |
| a reader of a registry entry | `entry.allowOrgOverride` | `entry.allowEnvironmentOverlay` |
| each `entries[]` item of `GET /api/v1/meta/types` (`GetMetaTypesResponse`) | `allowOrgOverride` | `allowEnvironmentOverlay` |

**The one-line fix: rename the key, and every read of it; the value is unchanged.**

Every value is unchanged: `true` on `view`, `dashboard`, `report`, `translation` and `email_template`, `false` on every other built-in type. On the wire the value is still the registry's grant OR the `OS_METADATA_WRITABLE` hatch naming the type (`overrideSource: 'env'`), and the hatch still opens only items no managed package ships, never a managed one. `overrideSource` keeps its `registry` / `env` values; its describe now names the new field.

⚠️ **Read the old key nowhere.** Writing `allowOrgOverride` fails to compile (its input type is `never`) and fails to parse with the rename prescription (issue code `invalid_type` at path `allowOrgOverride`). A READER does not fail: `if (!entry.allowOrgOverride)`, a filter on it or a partial-match assertion still compiles against the tombstone and reads `undefined`, which treats every type as closed to environment overlays. A client that declares its own type for the `/meta/types` response, instead of importing `GetMetaTypesResponse`, sees no compile error at all and reads every type as locked. Search for the old name, do not wait for `tsc`.

**`supportsOverlay` keeps its name; its describes now say what it gates.** It decides one thing: a stored overlay row of an item a managed package ships may be removed through the ordinary delete door without the type's environment-overlay permission: the removal removes no managed definition, and changes what is served for `permission` alone. It opens no save and it decides no read. The registry's describe, the `GET /meta/types` describe and `MetadataTypeInfoResponse`'s describe used to promise that "the loader can merge overlays", in the retired per-organization wording.

**Who is affected, measured.** No manifest, stack, plugin configuration or stored row can carry a registry entry (`contributes.kinds` is closed, `config.additionalTypes` is a tombstone, the registry is a TypeScript literal), so no authored metadata changes. The readers are code: every reader in this repository moved in this change, and a reader of the `/meta/types` field outside it moves with it — the Studio console reads the field and moves in its own repository's paired change, which the console pin carries.

### The kit

- **The tombstone.** `MetadataTypeRegistryEntry.allowOrgOverride` is a `retiredKey()` naming `allowEnvironmentOverlay` (`kernel/metadata-plugin.zod.ts`); the 28 built-in rows spell the new key.
- **The ledger.** The retired-keys entry `kernel/MetadataTypeRegistryEntry:allowOrgOverride` and the D3 semantic entry `metadata-type-registry-allow-org-override-renamed` (protocol 18), which records the registry key and the wire field together. No D2 conversion: there is no authored or stored source a conversion could rewrite.
- **The wire.** `getMetaTypes` writes the hatch elevation onto `allowEnvironmentOverlay` on both of its arms — a registry type and a runtime-registered type with no registry row — and no entry carries `allowOrgOverride`.
- **The refusal sentences** that named the flag name the new key: `… takes no environment overlay (allowEnvironmentOverlay=false) …`, `… has neither allowEnvironmentOverlay nor allowRuntimeCreate …`, `… allowRuntimeCreate=false and allowEnvironmentOverlay=false …`. Codes and statuses are unchanged.
72 changes: 72 additions & 0 deletions .changeset/console-e5311165a8d6.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
"@objectstack/console": minor
---

Console (objectui) refreshed to `e5311165a8d6`. Frontend changes in this range:

Derived from the changesets objectui declared over the range — 21 releasing of 23 changesets added across 24 non-merge commits; omitted: 2 release-nothing changesets, 1 commit carrying no changeset (they ship no package code).

- **minor** — **BREAKING** — Studio and the metadata admin read a metadata type's overlay flag under its new name, `allowEnvironmentOverlay`, and the read-only banners name `OS_METADATA_WRITABLE` (objectui#12… (objectui `e5311165a`)
- **minor** — The marketplace package page's **Update** button opens an update dialog, and a package README's raw HTML is no longer printed as text (objectui#12146). (objectui `82bb1d584`)
- **minor** — **BREAKING** — A form field declares `step` and `className` on both faces, so the strict authoring face stops telling authors to remove two keys that work. A built-in form branch now joins an en… (objectui `d2500d8be`)
- **minor** — "Clone to customize" on a packaged permission set calls the server's clone door (objectui#7611, objectstack ADR-0126 §7.1). (objectui `6d5879fe9`)
- **minor** — **A dashboard or a list view the server refuses you, opened by its URL, now says it was refused** (objectui#12112, the console half of objectstack#22611's ruling A). (objectui `43e150518`)
- **minor** — Setup's "Assigned users" on a permission set writes a new grant by the set's name alone (objectui#7611, after objectstack#22863, ADR-0131 stage 6b-2-pre). (objectui `faf4ce952`)
- **minor** — **BREAKING** — A form field declares `avatarField`, the record field each candidate of the search picker draws its avatar from, on both faces, so the strict authoring face stops telling authors… (objectui `c0c2f792b`)
- **minor** — A `position` decision output lists the position registry and commits position names (objectui#7611, objectstack ADR-0131 D3/D4). (objectui `8cc7158b4`)
- **minor** — The capability select lists the capability registry, and the permission-set editor's provenance badge reads the layered envelope (objectui#7611, objectstack ADR-0131 D3/D7). (objectui `53ee2f854`)
- **minor** — **BREAKING** — A form field declares the rest of the field metadata its widget reads off the `fields[]` entry, on both faces, so the strict authoring face stops telling authors to remove keys th… (objectui `0665c3be7`)
- **minor** — Screen readers hear the names of more controls in the viewer's language (objectui#12145). (objectui `e723f58ee`)
- **minor** — The suggested-bindings panel shows each suggestion's real state and can revoke an acceptance (objectui#7611, after objectstack#22854). (objectui `f962cdc09`)
- **minor** — The record feed and a related list's Add existing and fallback remove read the affordance-to-grant map, so a caller without the grant is no longer offered a write the server then… (objectui `158c75d90`)
- **minor** — A paged table's first, previous, next and last page buttons have accessible names (objectui#12124). (objectui `dc6d28e86`)
- **patch** — The Studio app's root now opens the app's first navigation entry, like every other app's root, and `StudioHomePage`, Studio's old metadata overview, is retired (objectui#12113). (objectui `ed12d48ec`)
- **patch** — A form field's own `defaultValue` is no longer drawn in its control, so the form never shows a value it does not save (objectui#12155). (objectui `f3d540814`)
- **patch** — A grouped grid's own first, previous, next and last page buttons have accessible names (objectui#12143). (objectui `2381c07f3`)
- **patch** — Console rendering fixes from the HotCRM browser pass (objectui#12110): (objectui `5330038f4`)
- **patch** — The record page's discussion shows stored replies under their comment, and every comment offers the reply input where the caller may post one (objectui#12144). (objectui `a7d492011`)
- **patch** — A record activity feed shows an object's `activityMilestones` rows of type `completed`, such as "Case resolved", instead of hiding them as completed tasks (objectui#12106). (objectui `1d1cfe0c1`)
- **patch** — A record-source refusal (`RECORD_SOURCE_REQUIRED`, raised by every arm that requires a record source) now reports the same path every time (objectui#5250). (objectui `9b7550999`)

⚠️ 4 of these carry a breaking change: 4 by the author's own breaking annotation in the changeset body — objectui declares no `major` inside a launch window (`scripts/check-changeset-no-major.mjs`). Each is marked **BREAKING** in the list above — read them before compiling the release record.

**In this console build, declared nowhere** — objectui merged 1 commit in this range with no `.changeset/*.md`. The code is inside the pin above and ships here, but nothing upstream declared it, so it appears in no objectui CHANGELOG and in no entry above. Listed by subject rather than counted, because a count cannot tell a dependency bump from a form-behaviour change (objectstack#6174); the upstream gate that would prevent this is objectui#3387.

- _(no changeset)_ feat(scripts): the JSON-fence gate reads the published READMEs (objectui#12131, phase 2) (#12139) (objectui `ce9811c96`)

<!-- adr-0087: not-required (no-migration-prescription)
This console changeset moves `.objectui-sha` and the artefacts that travel with it: the
re-recorded `scripts/sdui-manifest.record.json` and the regenerated `sdui.manifest.json`
(107 components; one input description changed, the record activity feed's
`showCompleted` (objectui#12106), and no component, input, type or required flag moved),
the re-recorded `packages/sdui-parser/objectui-lockstep.json` (its grammar region,
diagnostic codes and containment predicate are unchanged across the range) and the
re-measured pin citations in `packages/spec/src`, which carry their own
`@objectstack/spec` patch changeset. It adds, removes or renames no ObjectStack-authorable
key of its own. The one ObjectStack rename this pin follows,
`MetadataTypeRegistryEntry.allowOrgOverride` to `allowEnvironmentOverlay` and the
`GET /meta/types` field with it, is this same diff's: its FROM/TO prescription and its
`registered metadata-type-registry-allow-org-override-renamed` disposition live in
`.changeset/22340-registry-allow-environment-overlay.md`, so this body carries no FROM/TO
prescription of its own.
The range carries four declared-breaking objectui changes, each by its author's breaking
annotation and none by a declared `major`. Each is answered here:
(1) objectui#12141 (`e5311165a`): `@object-ui/app-shell`'s `RichMetadataTypeEntry` and
`resolveResourceConfig` read `allowEnvironmentOverlay` in place of `allowOrgOverride`,
with no dual read. It is the console half of this diff's own rename and reads the one
name this diff's `GET /meta/types` writes, on both of its arms; it is why this pin and
that rename land together.
(2) objectui#12130 (`d2500d8be`): objectui's form-field type declares `step` as the
spec's number and `className` as a string, so its tolerant face refuses `step: 'any'`.
objectui's own authoring face; `@objectstack/spec` declares and moves nothing here.
(3) objectui#12130 (`c0c2f792b`): objectui's form-field type declares `avatarField`, and
its tolerant face refuses a non-string value. objectui's own face; no ObjectStack key.
(4) objectui#12130 (`0665c3be7`): objectui's form-field type declares the field-metadata
keys its widgets read off a `fields[]` entry, by reference to `@objectstack/spec`'s
`FieldSchema` members, with value checks on its tolerant face. objectui's own face; the
spec members it references do not move.
No commit subject in the range carries `!`. Scope of the claim, stated rather than
implied: it is a claim about THIS diff, not a per-entry re-measurement of the upstream
declared-breaking entries. -->

objectui range: `4997995022f8...e5311165a8d6`
18 changes: 18 additions & 0 deletions .changeset/objectui-pin-citations-e5311165a8d6.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
'@objectstack/spec': patch
---

The spec's objectui citations, and the shipped description text that names the `.objectui-sha` pin (the `FormField.span` describe and six migration-entry descriptions), are re-measured against the new console pin, objectui `e5311165a8d6`.

Clause-②: no

Every anchor was mapped through the objectui diff `4997995022f8..e5311165a8d6`: 287 paths over 24 commits, four deleted (`StudioHomePage.tsx`, its two tests and `permission-set-clone-dispatch.ts`, none of which a record cites) and none renamed. Five files a record cites changed on the hop, plus the `en` / `zh` / `de` packs (whose `calendar.configRequired` strings did not change): `ObjectGrid.tsx` (objectui#12110 and objectui#12143), `data-table.tsx` (objectui#12124 and objectui#12145), `form.tsx` (objectui#12110, objectui#12130 and objectui#12155), `record-related-list.tsx` (objectui#12082) and `data-objectstack/src/index.ts` (objectui#12112). Every cited line in them moved or held with its text byte-identical, and each record that cites one is re-pointed with a hop sentence that says by how much. The records that cite only byte-identical files gain a hop sentence that says so.

Two readings sit beside a cited read, and each hop sentence says what it found:

- `record-related-list.tsx`: the list's fallback remove now reads the affordance-to-grant map's `relatedRowDelete` row (objectui#12082). The hunks sit above and below the `requiredPermissions` gate; the gate and the related object's read gate are byte-identical, 17 lines down.
- `form.tsx`: the built-in branches now settle the widget a field hint renders and the props they hand their control (objectui#12110, objectui#12155, objectui#12130). `spanLadderFor` and its one call site are byte-identical, so the `span` describe's reading holds.

The six migration entries' corpus counts were re-taken with `git grep -o -F`, the method that reproduces every `4997995022f8` number. The corpus is now 8506 tracked files. Every token an entry counts as zero still reads zero: 124 candidate tokens (every export of the four spec files the entries name, and every key they name) read zero at both pins. `Span` reads 519 against 517, both new hits `colSpan`, and `SpanSchema` reads 57 at both pins, as the tracing entry records. The controls moved with the corpus, for example `objectstack` from 18271 to 18355 and `timeout` from 1704 to 1706.

No key, default, enum member or export moves.
2 changes: 1 addition & 1 deletion .objectui-sha
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4997995022f8e65946f6362b7434685539cc72b7
e5311165a8d6aa77b5cb7d9fd05da8451a2c21aa
4 changes: 2 additions & 2 deletions content/docs/ai/agents.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ assistant to *write* your metadata and never run. Same word, two layers.
</Callout>

`*.agent.ts` is **closed to third parties** — the `agent` metadata type is
`allowRuntimeCreate:false, allowOrgOverride:false`, reserved for the two platform
`allowRuntimeCreate:false, allowEnvironmentOverlay:false`, reserved for the two platform
agents and platform-owned subagents (ADR-0063 §2). To give the `ask` agent a new
capability you author an agent **skill** (`*.skill.ts`). Every skill declares
`surface: 'ask' | 'build' | 'both'`, and an agent's tool set is the **union of its
Expand Down Expand Up @@ -240,7 +240,7 @@ LLM-callable.
The agent definitions below illustrate agent **anatomy** — how an `AgentSchema`
record is shaped (that schema and the `defineAgent` factory are part of the open
`@objectstack/spec/ai` package). Note that the `agent` metadata type is
`allowRuntimeCreate:false` / `allowOrgOverride:false` (ADR-0063 §2): the **cloud /
`allowRuntimeCreate:false` / `allowEnvironmentOverlay:false` (ADR-0063 §2): the **cloud /
Enterprise** in-product runtime honors only the two platform agents `ask` and
`build`, so you do not ship a custom agent *to that runtime* — you extend it by
authoring a **skill** (open metadata) that attaches to `ask`. In the open edition,
Expand Down
2 changes: 1 addition & 1 deletion content/docs/api/declarative-endpoints.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ PUT /api/v1/meta/api/acme_lead_feed → 403 {"code":"NOT_CREATABLE"}
```

The `api` metadata type is registered with `allowRuntimeCreate: false` and
`allowOrgOverride: false`, and that refusal runs **before any body validation** — so a
`allowEnvironmentOverlay: false`, and that refusal runs **before any body validation** — so a
perfectly valid endpoint body gets the same `403`, in `?mode=draft` as well as direct
writes. There is no per-organization overlay of an endpoint either.

Expand Down
2 changes: 1 addition & 1 deletion content/docs/api/metadata-api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Create or update a metadata item.

Creates are gated per type: `MetadataTypeRegistryEntry.allowRuntimeCreate` decides
whether a **brand-new** name may be minted under that type at all, separately from
whether an item that already exists may be overlaid (`allowOrgOverride`). A type that
whether an item that already exists may be overlaid (`allowEnvironmentOverlay`). A type that
declines the create half still accepts updates to names that already exist, and its
refusal — `403 NOT_CREATABLE` — names the route that does work. The flags are
documented on
Expand Down
2 changes: 1 addition & 1 deletion content/docs/automation/jobs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ writes carry*:
| | `job` | `schedule`-type flow |
|:---|:---|:---|
| What runs | a sandboxed `body`, a mapping `pull`, or (deprecated) one TypeScript function from `defineStack({ functions })` | a node graph — record operations, `notify`, `http`, approvals, subflows |
| Changeable after deploy | **No.** `job` is `allowRuntimeCreate: false` and `allowOrgOverride: false` — there is no "create job" in Studio and no per-tenant fork | Yes — a new flow can be authored through Studio / `PUT /meta` (`allowRuntimeCreate: true`) |
| Changeable after deploy | **No.** `job` is `allowRuntimeCreate: false` and `allowEnvironmentOverlay: false` — there is no "create job" in Studio and no per-tenant fork | Yes — a new flow can be authored through Studio / `PUT /meta` (`allowRuntimeCreate: true`) |
| Identity of its data writes | system, in the job's declared [`organization`](#the-organization-a-job-runs-as) | declared by [`runAs`](/docs/automation/flows) — and a `user` run that resolves no trigger user has its data operations **refused**, so a scheduled flow normally declares `runAs: 'system'` |
| Retry / time limit | `retryPolicy` + `timeoutMs` on the job, honoured by the job adapter | the flow's own error handling |
| Run history | `sys_job` + `sys_job_run` | `sys_automation_run` |
Expand Down
Loading
Loading