From 3bbc3eb9b2d9a5999e9d41387b8f7b2bc8cf4b93 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 16:45:11 +0000 Subject: [PATCH 1/8] =?UTF-8?q?docs(spec):=20Seed.locale=20says=20which=20?= =?UTF-8?q?loads=20filter=20on=20it=20=E2=80=94=20install,=20reseed,=20hea?= =?UTF-8?q?l=20and=20per-organization=20replay=20pick=20by=20the=20resolve?= =?UTF-8?q?d=20locale?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa --- packages/spec/src/data/seed.zod.ts | 37 ++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/packages/spec/src/data/seed.zod.ts b/packages/spec/src/data/seed.zod.ts index dc7831d364a..47f616844cd 100644 --- a/packages/spec/src/data/seed.zod.ts +++ b/packages/spec/src/data/seed.zod.ts @@ -261,20 +261,33 @@ export const SeedSchema = lazySchema(() => strictObject({ * The platform translates nothing. This is the axis that SELECTS between * record sets the app authored itself. * - * **Publishing and installing are locale-neutral acts — this axis is scoped - * to the boot path, by decision.** The loader evaluates it against - * `SeedLoaderConfig.locale`, which only the boot path supplies (AppPlugin - * reads the app's declared `i18n.defaultLocale`). Package apply, draft - * publish and marketplace install each build their own load request and pass - * no locale, so a `locale`-scoped dataset reaching one of them is loaded for - * **every** locale and the loader warns naming each dataset it let through. - * That bound is the contract, not an unfinished path: a package is assembled - * once for every market, and selecting a market is what happens when it is - * opened. Ruled on #17011 (2026-09-10), which also kept the warning rather - * than turning those paths into a refusal. + * **Which loads filter on it.** The loader evaluates this axis against + * `SeedLoaderConfig.locale`; a load request that carries none loads a + * `locale`-scoped dataset for **every** locale, and the loader warns naming + * each dataset it let through. + * + * - **Boot.** The boot seed and the dev hot-reload seeder filter on the + * app's declared `i18n.defaultLocale` (AppPlugin). + * - **Install, reseed, heal and per-organization replay.** The marketplace + * install, the sample-data reseed, the restart heal and the + * per-organization replay filter on the locale resolved for that load by + * `resolveSeedLocaleForLoad` (`@objectstack/runtime`), first answer wins: + * the `localization.locale` setting for the organization the rows land in, + * counted only when somebody set it (a value whose `source` is `'default'` + * is the platform's placeholder, not a choice); then the `sys_user.locale` + * of the user who installs, reseeds or founds the organization, when one + * started the load; then the app's declared `i18n.defaultLocale`, when the + * caller names one. No answer is a load with no locale, as above. A + * setting or user read that fails seeds nothing rather than another + * language. + * - **Package apply and draft publish** pass no locale: they stay + * locale-neutral, because a package is assembled once for every market. + * That is the bound ruled on #17011 (2026-09-10), narrowed to these two + * paths when the maintainer ruled that the install paths pick by locale + * (2026-11-05). */ locale: z.array(LocaleSchema).min(1).optional() - .describe('Applicable locales (BCP-47 tags); omitted applies to every locale. The publish and install paths do not filter by locale — they load every dataset and warn'), + .describe('Applicable locales (BCP-47 tags); omitted applies to every locale. The boot seed filters on the app\'s i18n.defaultLocale; the marketplace install, sample-data reseed, restart heal and per-organization replay filter on the locale resolved for the load (the localization.locale setting when set, then the installing or founding user\'s locale, then the app\'s i18n.defaultLocale where the load names one); package apply and draft publish do not filter by locale — they load every dataset and warn'), /** * The Payload From 9ba2634923977a366ed4c9525f806c94089edd98 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 16:55:23 +0000 Subject: [PATCH 2/8] docs(spec): regenerate the references pages for the Seed.locale describe, and add the changeset Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa --- ...0347-spec-seed-locale-and-queue-refuse-wording.md | 12 ++++++++++++ content/docs/references/api/package-api.mdx | 4 ++-- content/docs/references/data/seed-loader.mdx | 2 +- content/docs/references/data/seed.mdx | 2 +- content/docs/references/kernel/manifest.mdx | 2 +- 5 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 .changeset/30347-spec-seed-locale-and-queue-refuse-wording.md diff --git a/.changeset/30347-spec-seed-locale-and-queue-refuse-wording.md b/.changeset/30347-spec-seed-locale-and-queue-refuse-wording.md new file mode 100644 index 00000000000..95f9245ef92 --- /dev/null +++ b/.changeset/30347-spec-seed-locale-and-queue-refuse-wording.md @@ -0,0 +1,12 @@ +--- +'@objectstack/spec': patch +--- + +docs(spec): `Seed.locale` says which loads filter on it, and the ownership-queue contract says the registered service honours `onFailedRead: 'refuse'` + +Clause-②: no +Metadata-protocol: none + +Wording only: no schema shape, no type and no behaviour changed. + +- **`Seed.locale`** (docblock and `.describe()`, which the references pages render). It no longer says that installing is locale-neutral. The boot seed and the dev hot-reload seeder filter on the app's `i18n.defaultLocale`. The marketplace install, the sample-data reseed, the restart heal and the per-organization replay filter on the locale `resolveSeedLocaleForLoad` (`@objectstack/runtime`) resolves for the load, first answer wins: the `localization.locale` setting, counted only when somebody set it (not `source: 'default'`); then the `sys_user.locale` of the user who installs, reseeds or founds the organization; then the app's `i18n.defaultLocale` where the load names one. Package apply and draft publish still pass no locale: they load every dataset and warn. diff --git a/content/docs/references/api/package-api.mdx b/content/docs/references/api/package-api.mdx index d185002b5e7..5faf6ad7ab0 100644 --- a/content/docs/references/api/package-api.mdx +++ b/content/docs/references/api/package-api.mdx @@ -246,7 +246,7 @@ Package manifest installed through POST /api/v1/packages (AUTHORING stage; scope | **mode** | `Enum<'insert' \| 'update' \| 'upsert' \| 'replace' \| 'ignore'>` | optional (default: `"ignore"`) | What a load does with a record whose `externalId` matches an existing row. `ignore` (default) is create-only: a missing row is inserted and an existing row is left as it is, so a replay (every boot, a package install or upgrade, a publish) never writes a seeded value back over a later edit. `upsert` also writes every declared column back onto the matched row on each replay; declare it for reference data the package keeps current. `update` writes matched rows only, `insert` inserts every record with no match, and `replace` inserts into a table the caller cleared. | | **columns** | `Record }>` | optional | Per-column write policy, keyed by field name: `{ status: { applyOn: 'create' } }` writes `status` only when the seed creates the row. Omitted, every column is written on create and update. | | **env** | `Enum<'prod' \| 'dev' \| 'test'>[]` | optional (default: `["prod","dev","test"]`) | Applicable environments | -| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The publish and install paths do not filter by locale — they load every dataset and warn | +| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The boot seed filters on the app's i18n.defaultLocale; the marketplace install, sample-data reseed, restart heal and per-organization replay filter on the locale resolved for the load (the localization.locale setting when set, then the installing or founding user's locale, then the app's i18n.defaultLocale where the load names one); package apply and draft publish do not filter by locale — they load every dataset and warn | | **records** | `Record[]` | ✅ | Data records | | **files** | `Record` | optional | Bytes of the package files the records name with `seedFile(path)`, keyed by path. Written by `os build`, which reads each path relative to the package root; the loader stores each one as a file the written record owns. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | @@ -354,7 +354,7 @@ Package manifest installed through POST /api/v1/packages (AUTHORING stage; scope | **mode** | `Enum<'insert' \| 'update' \| 'upsert' \| 'replace' \| 'ignore'>` | optional (default: `"ignore"`) | What a load does with a record whose `externalId` matches an existing row. `ignore` (default) is create-only: a missing row is inserted and an existing row is left as it is, so a replay (every boot, a package install or upgrade, a publish) never writes a seeded value back over a later edit. `upsert` also writes every declared column back onto the matched row on each replay; declare it for reference data the package keeps current. `update` writes matched rows only, `insert` inserts every record with no match, and `replace` inserts into a table the caller cleared. | | **columns** | `Record }>` | optional | Per-column write policy, keyed by field name: `{ status: { applyOn: 'create' } }` writes `status` only when the seed creates the row. Omitted, every column is written on create and update. | | **env** | `Enum<'prod' \| 'dev' \| 'test'>[]` | optional (default: `["prod","dev","test"]`) | Applicable environments | -| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The publish and install paths do not filter by locale — they load every dataset and warn | +| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The boot seed filters on the app's i18n.defaultLocale; the marketplace install, sample-data reseed, restart heal and per-organization replay filter on the locale resolved for the load (the localization.locale setting when set, then the installing or founding user's locale, then the app's i18n.defaultLocale where the load names one); package apply and draft publish do not filter by locale — they load every dataset and warn | | **records** | `Record[]` | ✅ | Data records | | **files** | `Record` | optional | Bytes of the package files the records name with `seedFile(path)`, keyed by path. Written by `os build`, which reads each path relative to the package root; the loader stores each one as a file the written record owns. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | diff --git a/content/docs/references/data/seed-loader.mdx b/content/docs/references/data/seed-loader.mdx index 231395ac6d1..84de2aea26a 100644 --- a/content/docs/references/data/seed-loader.mdx +++ b/content/docs/references/data/seed-loader.mdx @@ -233,7 +233,7 @@ Seed loader request with datasets and configuration | **mode** | `Enum<'insert' \| 'update' \| 'upsert' \| 'replace' \| 'ignore'>` | optional (default: `"ignore"`) | What a load does with a record whose `externalId` matches an existing row. `ignore` (default) is create-only: a missing row is inserted and an existing row is left as it is, so a replay (every boot, a package install or upgrade, a publish) never writes a seeded value back over a later edit. `upsert` also writes every declared column back onto the matched row on each replay; declare it for reference data the package keeps current. `update` writes matched rows only, `insert` inserts every record with no match, and `replace` inserts into a table the caller cleared. | | **columns** | `Record }>` | optional | Per-column write policy, keyed by field name: `{ status: { applyOn: 'create' } }` writes `status` only when the seed creates the row. Omitted, every column is written on create and update. | | **env** | `Enum<'prod' \| 'dev' \| 'test'>[]` | optional (default: `["prod","dev","test"]`) | Applicable environments | -| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The publish and install paths do not filter by locale — they load every dataset and warn | +| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The boot seed filters on the app's i18n.defaultLocale; the marketplace install, sample-data reseed, restart heal and per-organization replay filter on the locale resolved for the load (the localization.locale setting when set, then the installing or founding user's locale, then the app's i18n.defaultLocale where the load names one); package apply and draft publish do not filter by locale — they load every dataset and warn | | **records** | `Record[]` | ✅ | Data records | | **files** | `Record` | optional | Bytes of the package files the records name with `seedFile(path)`, keyed by path. Written by `os build`, which reads each path relative to the package root; the loader stores each one as a file the written record owns. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | diff --git a/content/docs/references/data/seed.mdx b/content/docs/references/data/seed.mdx index ad186a9c641..83404cc5e96 100644 --- a/content/docs/references/data/seed.mdx +++ b/content/docs/references/data/seed.mdx @@ -33,7 +33,7 @@ const result = SeedSchema.parse(data); | **mode** | `Enum<'insert' \| 'update' \| 'upsert' \| 'replace' \| 'ignore'>` | optional (default: `"ignore"`) | What a load does with a record whose `externalId` matches an existing row. `ignore` (default) is create-only: a missing row is inserted and an existing row is left as it is, so a replay (every boot, a package install or upgrade, a publish) never writes a seeded value back over a later edit. `upsert` also writes every declared column back onto the matched row on each replay; declare it for reference data the package keeps current. `update` writes matched rows only, `insert` inserts every record with no match, and `replace` inserts into a table the caller cleared. | | **columns** | `Record }>` | optional | Per-column write policy, keyed by field name: `{ status: { applyOn: 'create' } }` writes `status` only when the seed creates the row. Omitted, every column is written on create and update. | | **env** | `Enum<'prod' \| 'dev' \| 'test'>[]` | optional (default: `["prod","dev","test"]`) | Applicable environments | -| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The publish and install paths do not filter by locale — they load every dataset and warn | +| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The boot seed filters on the app's i18n.defaultLocale; the marketplace install, sample-data reseed, restart heal and per-organization replay filter on the locale resolved for the load (the localization.locale setting when set, then the installing or founding user's locale, then the app's i18n.defaultLocale where the load names one); package apply and draft publish do not filter by locale — they load every dataset and warn | | **records** | `Record[]` | ✅ | Data records | | **files** | `Record` | optional | Bytes of the package files the records name with `seedFile(path)`, keyed by path. Written by `os build`, which reads each path relative to the package root; the loader stores each one as a file the written record owns. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | diff --git a/content/docs/references/kernel/manifest.mdx b/content/docs/references/kernel/manifest.mdx index 64aba9b6b5d..2efa8ae50c9 100644 --- a/content/docs/references/kernel/manifest.mdx +++ b/content/docs/references/kernel/manifest.mdx @@ -100,7 +100,7 @@ Install mode: managed (registered as code, upgradeable, sealed) | unmanaged (cop | **mode** | `Enum<'insert' \| 'update' \| 'upsert' \| 'replace' \| 'ignore'>` | optional (default: `"ignore"`) | What a load does with a record whose `externalId` matches an existing row. `ignore` (default) is create-only: a missing row is inserted and an existing row is left as it is, so a replay (every boot, a package install or upgrade, a publish) never writes a seeded value back over a later edit. `upsert` also writes every declared column back onto the matched row on each replay; declare it for reference data the package keeps current. `update` writes matched rows only, `insert` inserts every record with no match, and `replace` inserts into a table the caller cleared. | | **columns** | `Record }>` | optional | Per-column write policy, keyed by field name: `{ status: { applyOn: 'create' } }` writes `status` only when the seed creates the row. Omitted, every column is written on create and update. | | **env** | `Enum<'prod' \| 'dev' \| 'test'>[]` | optional (default: `["prod","dev","test"]`) | Applicable environments | -| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The publish and install paths do not filter by locale — they load every dataset and warn | +| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The boot seed filters on the app's i18n.defaultLocale; the marketplace install, sample-data reseed, restart heal and per-organization replay filter on the locale resolved for the load (the localization.locale setting when set, then the installing or founding user's locale, then the app's i18n.defaultLocale where the load names one); package apply and draft publish do not filter by locale — they load every dataset and warn | | **records** | `Record[]` | ✅ | Data records | | **files** | `Record` | optional | Bytes of the package files the records name with `seedFile(path)`, keyed by path. Written by `os build`, which reads each path relative to the package root; the loader stores each one as a file the written record owns. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | From 9d61fa4aa466b55536b5068919b659f2d94c2a84 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 16:55:31 +0000 Subject: [PATCH 3/8] docs(spec): the ownership-queue contract says the registered service honours onFailedRead 'refuse', the ledger posture stays, and when isMember answers true beside a failed read Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa --- ...7-spec-seed-locale-and-queue-refuse-wording.md | 1 + .../spec/src/contracts/ownership-queue-service.ts | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.changeset/30347-spec-seed-locale-and-queue-refuse-wording.md b/.changeset/30347-spec-seed-locale-and-queue-refuse-wording.md index 95f9245ef92..052929cbe9d 100644 --- a/.changeset/30347-spec-seed-locale-and-queue-refuse-wording.md +++ b/.changeset/30347-spec-seed-locale-and-queue-refuse-wording.md @@ -10,3 +10,4 @@ Metadata-protocol: none Wording only: no schema shape, no type and no behaviour changed. - **`Seed.locale`** (docblock and `.describe()`, which the references pages render). It no longer says that installing is locale-neutral. The boot seed and the dev hot-reload seeder filter on the app's `i18n.defaultLocale`. The marketplace install, the sample-data reseed, the restart heal and the per-organization replay filter on the locale `resolveSeedLocaleForLoad` (`@objectstack/runtime`) resolves for the load, first answer wins: the `localization.locale` setting, counted only when somebody set it (not `source: 'default'`); then the `sys_user.locale` of the user who installs, reseeds or founds the organization; then the app's `i18n.defaultLocale` where the load names one. Package apply and draft publish still pass no locale: they load every dataset and warn. +- **`OwnershipQueueFailedReadAnswer` and `IOwnershipQueueService.isMember`** (`@objectstack/spec/contracts`). The registered service, `@objectstack/plugin-sharing`'s, honours `'refuse'`; the "until then a caller passing `'refuse'` still gets `'nobody'`" clause is gone. The activation-ledger read keeps reading "switched on" when it fails, under both answers, and the contract now states that as decided. `isMember` under `'refuse'` reads the queue's own rows (`sys_queue`, `sys_queue_member`) first and rejects at once when one fails; past them it answers `true` as soon as a successful read reaches the user, even beside a failed read, and rejects only when no successful read reaches the user and one failed. diff --git a/packages/spec/src/contracts/ownership-queue-service.ts b/packages/spec/src/contracts/ownership-queue-service.ts index aa3f13980d6..97fa855f982 100644 --- a/packages/spec/src/contracts/ownership-queue-service.ts +++ b/packages/spec/src/contracts/ownership-queue-service.ts @@ -62,8 +62,10 @@ export type QueueExpansionPurpose = 'access' | 'addressing'; * does not carry is absence, not failure. The activation-ledger read * (`sys_metadata_activation`, which says whether a declared queue or a position * is switched off) is NOT a failed read in this sense: under either answer its - * failure reads "switched on", as it did before the key existed; whether that - * posture moves is #29604's code half to decide. + * failure reads "switched on", as it did before the key existed. That posture + * stays by decision: it is the one the sharing-rule service takes for the same + * ledger on its own `position` recipients, so a queue's position and a rule's + * position cannot disagree during an outage. * * - `'nobody'` — the default and the answer every caller had before the key * existed. A failed read is logged at `warn`, and what sat behind it @@ -76,8 +78,7 @@ export type QueueExpansionPurpose = 'access' | 'addressing'; * grants and "nobody" there revokes: the approver slate (D6) and the * sharing-recipient grant recompute (D7). An implementation written before * this key existed ignores it and answers `'nobody'`; the registered one, - * `@objectstack/plugin-sharing`'s, honours `'refuse'` from #29604's code half - * on, so until then a caller passing `'refuse'` still gets `'nobody'`. + * `@objectstack/plugin-sharing`'s, honours `'refuse'`. * * Under either answer an EMPTY queue — every read succeeded and reached * nobody — is still `[]`, and a name that resolves nowhere is still `[]` / @@ -157,6 +158,12 @@ export interface IOwnershipQueueService { * under `'nobody'`, the default, a failed read counts as not reaching * `userId`; under `'refuse'`, `false` is answered only when every read * behind it succeeded, and a failed read rejects with a failure naming it. + * Under `'refuse'` the registered service reads the queue's own rows + * (`sys_queue`, `sys_queue_member`) first, and a failure there rejects at + * once, since without them the call does not know what to ask. Past them it + * answers `true` as soon as a read that succeeded reaches `userId`, even + * beside a failed read, and rejects only when no successful read reaches + * `userId` and one failed. * The options argument is optional, so a three-argument call is today's. */ isMember( From d56c29454ea2410040be2eb8a85b2bdbf30525f4 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 18:17:50 +0000 Subject: [PATCH 4/8] docs(spec): Seed.locale names the reseeding user in its describe, and says an organization-less load still reads the environment or global locale setting Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa --- packages/spec/src/data/seed.zod.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/spec/src/data/seed.zod.ts b/packages/spec/src/data/seed.zod.ts index 47f616844cd..fd26b90a92c 100644 --- a/packages/spec/src/data/seed.zod.ts +++ b/packages/spec/src/data/seed.zod.ts @@ -272,9 +272,12 @@ export const SeedSchema = lazySchema(() => strictObject({ * install, the sample-data reseed, the restart heal and the * per-organization replay filter on the locale resolved for that load by * `resolveSeedLocaleForLoad` (`@objectstack/runtime`), first answer wins: - * the `localization.locale` setting for the organization the rows land in, - * counted only when somebody set it (a value whose `source` is `'default'` - * is the platform's placeholder, not a choice); then the `sys_user.locale` + * the `localization.locale` setting for the organization the rows land in + * (a load that names no organization, such as a single-tenant install or + * reseed or the restart heal, still reads it, and the environment override + * or the `global` setting answers), counted only when somebody set it (a + * value whose `source` is `'default'` is the platform's placeholder, not a + * choice); then the `sys_user.locale` * of the user who installs, reseeds or founds the organization, when one * started the load; then the app's declared `i18n.defaultLocale`, when the * caller names one. No answer is a load with no locale, as above. A @@ -287,7 +290,7 @@ export const SeedSchema = lazySchema(() => strictObject({ * (2026-11-05). */ locale: z.array(LocaleSchema).min(1).optional() - .describe('Applicable locales (BCP-47 tags); omitted applies to every locale. The boot seed filters on the app\'s i18n.defaultLocale; the marketplace install, sample-data reseed, restart heal and per-organization replay filter on the locale resolved for the load (the localization.locale setting when set, then the installing or founding user\'s locale, then the app\'s i18n.defaultLocale where the load names one); package apply and draft publish do not filter by locale — they load every dataset and warn'), + .describe('Applicable locales (BCP-47 tags); omitted applies to every locale. The boot seed filters on the app\'s i18n.defaultLocale; the marketplace install, sample-data reseed, restart heal and per-organization replay filter on the locale resolved for the load (the localization.locale setting when set, then the locale of the installing, reseeding or founding user, then the app\'s i18n.defaultLocale where the load names one); package apply and draft publish do not filter by locale — they load every dataset and warn'), /** * The Payload From d0db2c6a973d2525b31e468af0a939d031b00db0 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 18:17:50 +0000 Subject: [PATCH 5/8] =?UTF-8?q?docs(spec):=20isMember=20says=20why=20the?= =?UTF-8?q?=20queue's=20own=20rows=20refuse=20first=20=E2=80=94=20the=20me?= =?UTF-8?q?mber=20set=20would=20be=20incomplete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa --- packages/spec/src/contracts/ownership-queue-service.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/spec/src/contracts/ownership-queue-service.ts b/packages/spec/src/contracts/ownership-queue-service.ts index 97fa855f982..19ce0a87d8a 100644 --- a/packages/spec/src/contracts/ownership-queue-service.ts +++ b/packages/spec/src/contracts/ownership-queue-service.ts @@ -160,7 +160,9 @@ export interface IOwnershipQueueService { * behind it succeeded, and a failed read rejects with a failure naming it. * Under `'refuse'` the registered service reads the queue's own rows * (`sys_queue`, `sys_queue_member`) first, and a failure there rejects at - * once, since without them the call does not know what to ask. Past them it + * once, since without them the queue's member set would be incomplete (a + * declared queue's own specifications come from the registry, but its + * authored additions come from `sys_queue_member`). Past them it * answers `true` as soon as a read that succeeded reaches `userId`, even * beside a failed read, and rejects only when no successful read reaches * `userId` and one failed. From 8629666d9d03584174b6f884c44c4b9fb2bf727c Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 18:38:12 +0000 Subject: [PATCH 6/8] docs(spec): regenerate the references pages for the Seed.locale describe Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa --- content/docs/references/api/package-api.mdx | 4 ++-- content/docs/references/data/seed-loader.mdx | 2 +- content/docs/references/data/seed.mdx | 2 +- content/docs/references/kernel/manifest.mdx | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/content/docs/references/api/package-api.mdx b/content/docs/references/api/package-api.mdx index 5faf6ad7ab0..58e9f4f9bef 100644 --- a/content/docs/references/api/package-api.mdx +++ b/content/docs/references/api/package-api.mdx @@ -246,7 +246,7 @@ Package manifest installed through POST /api/v1/packages (AUTHORING stage; scope | **mode** | `Enum<'insert' \| 'update' \| 'upsert' \| 'replace' \| 'ignore'>` | optional (default: `"ignore"`) | What a load does with a record whose `externalId` matches an existing row. `ignore` (default) is create-only: a missing row is inserted and an existing row is left as it is, so a replay (every boot, a package install or upgrade, a publish) never writes a seeded value back over a later edit. `upsert` also writes every declared column back onto the matched row on each replay; declare it for reference data the package keeps current. `update` writes matched rows only, `insert` inserts every record with no match, and `replace` inserts into a table the caller cleared. | | **columns** | `Record }>` | optional | Per-column write policy, keyed by field name: `{ status: { applyOn: 'create' } }` writes `status` only when the seed creates the row. Omitted, every column is written on create and update. | | **env** | `Enum<'prod' \| 'dev' \| 'test'>[]` | optional (default: `["prod","dev","test"]`) | Applicable environments | -| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The boot seed filters on the app's i18n.defaultLocale; the marketplace install, sample-data reseed, restart heal and per-organization replay filter on the locale resolved for the load (the localization.locale setting when set, then the installing or founding user's locale, then the app's i18n.defaultLocale where the load names one); package apply and draft publish do not filter by locale — they load every dataset and warn | +| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The boot seed filters on the app's i18n.defaultLocale; the marketplace install, sample-data reseed, restart heal and per-organization replay filter on the locale resolved for the load (the localization.locale setting when set, then the locale of the installing, reseeding or founding user, then the app's i18n.defaultLocale where the load names one); package apply and draft publish do not filter by locale — they load every dataset and warn | | **records** | `Record[]` | ✅ | Data records | | **files** | `Record` | optional | Bytes of the package files the records name with `seedFile(path)`, keyed by path. Written by `os build`, which reads each path relative to the package root; the loader stores each one as a file the written record owns. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | @@ -354,7 +354,7 @@ Package manifest installed through POST /api/v1/packages (AUTHORING stage; scope | **mode** | `Enum<'insert' \| 'update' \| 'upsert' \| 'replace' \| 'ignore'>` | optional (default: `"ignore"`) | What a load does with a record whose `externalId` matches an existing row. `ignore` (default) is create-only: a missing row is inserted and an existing row is left as it is, so a replay (every boot, a package install or upgrade, a publish) never writes a seeded value back over a later edit. `upsert` also writes every declared column back onto the matched row on each replay; declare it for reference data the package keeps current. `update` writes matched rows only, `insert` inserts every record with no match, and `replace` inserts into a table the caller cleared. | | **columns** | `Record }>` | optional | Per-column write policy, keyed by field name: `{ status: { applyOn: 'create' } }` writes `status` only when the seed creates the row. Omitted, every column is written on create and update. | | **env** | `Enum<'prod' \| 'dev' \| 'test'>[]` | optional (default: `["prod","dev","test"]`) | Applicable environments | -| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The boot seed filters on the app's i18n.defaultLocale; the marketplace install, sample-data reseed, restart heal and per-organization replay filter on the locale resolved for the load (the localization.locale setting when set, then the installing or founding user's locale, then the app's i18n.defaultLocale where the load names one); package apply and draft publish do not filter by locale — they load every dataset and warn | +| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The boot seed filters on the app's i18n.defaultLocale; the marketplace install, sample-data reseed, restart heal and per-organization replay filter on the locale resolved for the load (the localization.locale setting when set, then the locale of the installing, reseeding or founding user, then the app's i18n.defaultLocale where the load names one); package apply and draft publish do not filter by locale — they load every dataset and warn | | **records** | `Record[]` | ✅ | Data records | | **files** | `Record` | optional | Bytes of the package files the records name with `seedFile(path)`, keyed by path. Written by `os build`, which reads each path relative to the package root; the loader stores each one as a file the written record owns. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | diff --git a/content/docs/references/data/seed-loader.mdx b/content/docs/references/data/seed-loader.mdx index 84de2aea26a..c335792fcd9 100644 --- a/content/docs/references/data/seed-loader.mdx +++ b/content/docs/references/data/seed-loader.mdx @@ -233,7 +233,7 @@ Seed loader request with datasets and configuration | **mode** | `Enum<'insert' \| 'update' \| 'upsert' \| 'replace' \| 'ignore'>` | optional (default: `"ignore"`) | What a load does with a record whose `externalId` matches an existing row. `ignore` (default) is create-only: a missing row is inserted and an existing row is left as it is, so a replay (every boot, a package install or upgrade, a publish) never writes a seeded value back over a later edit. `upsert` also writes every declared column back onto the matched row on each replay; declare it for reference data the package keeps current. `update` writes matched rows only, `insert` inserts every record with no match, and `replace` inserts into a table the caller cleared. | | **columns** | `Record }>` | optional | Per-column write policy, keyed by field name: `{ status: { applyOn: 'create' } }` writes `status` only when the seed creates the row. Omitted, every column is written on create and update. | | **env** | `Enum<'prod' \| 'dev' \| 'test'>[]` | optional (default: `["prod","dev","test"]`) | Applicable environments | -| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The boot seed filters on the app's i18n.defaultLocale; the marketplace install, sample-data reseed, restart heal and per-organization replay filter on the locale resolved for the load (the localization.locale setting when set, then the installing or founding user's locale, then the app's i18n.defaultLocale where the load names one); package apply and draft publish do not filter by locale — they load every dataset and warn | +| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The boot seed filters on the app's i18n.defaultLocale; the marketplace install, sample-data reseed, restart heal and per-organization replay filter on the locale resolved for the load (the localization.locale setting when set, then the locale of the installing, reseeding or founding user, then the app's i18n.defaultLocale where the load names one); package apply and draft publish do not filter by locale — they load every dataset and warn | | **records** | `Record[]` | ✅ | Data records | | **files** | `Record` | optional | Bytes of the package files the records name with `seedFile(path)`, keyed by path. Written by `os build`, which reads each path relative to the package root; the loader stores each one as a file the written record owns. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | diff --git a/content/docs/references/data/seed.mdx b/content/docs/references/data/seed.mdx index 83404cc5e96..646ed74badc 100644 --- a/content/docs/references/data/seed.mdx +++ b/content/docs/references/data/seed.mdx @@ -33,7 +33,7 @@ const result = SeedSchema.parse(data); | **mode** | `Enum<'insert' \| 'update' \| 'upsert' \| 'replace' \| 'ignore'>` | optional (default: `"ignore"`) | What a load does with a record whose `externalId` matches an existing row. `ignore` (default) is create-only: a missing row is inserted and an existing row is left as it is, so a replay (every boot, a package install or upgrade, a publish) never writes a seeded value back over a later edit. `upsert` also writes every declared column back onto the matched row on each replay; declare it for reference data the package keeps current. `update` writes matched rows only, `insert` inserts every record with no match, and `replace` inserts into a table the caller cleared. | | **columns** | `Record }>` | optional | Per-column write policy, keyed by field name: `{ status: { applyOn: 'create' } }` writes `status` only when the seed creates the row. Omitted, every column is written on create and update. | | **env** | `Enum<'prod' \| 'dev' \| 'test'>[]` | optional (default: `["prod","dev","test"]`) | Applicable environments | -| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The boot seed filters on the app's i18n.defaultLocale; the marketplace install, sample-data reseed, restart heal and per-organization replay filter on the locale resolved for the load (the localization.locale setting when set, then the installing or founding user's locale, then the app's i18n.defaultLocale where the load names one); package apply and draft publish do not filter by locale — they load every dataset and warn | +| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The boot seed filters on the app's i18n.defaultLocale; the marketplace install, sample-data reseed, restart heal and per-organization replay filter on the locale resolved for the load (the localization.locale setting when set, then the locale of the installing, reseeding or founding user, then the app's i18n.defaultLocale where the load names one); package apply and draft publish do not filter by locale — they load every dataset and warn | | **records** | `Record[]` | ✅ | Data records | | **files** | `Record` | optional | Bytes of the package files the records name with `seedFile(path)`, keyed by path. Written by `os build`, which reads each path relative to the package root; the loader stores each one as a file the written record owns. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | diff --git a/content/docs/references/kernel/manifest.mdx b/content/docs/references/kernel/manifest.mdx index 2efa8ae50c9..fd124280ae1 100644 --- a/content/docs/references/kernel/manifest.mdx +++ b/content/docs/references/kernel/manifest.mdx @@ -100,7 +100,7 @@ Install mode: managed (registered as code, upgradeable, sealed) | unmanaged (cop | **mode** | `Enum<'insert' \| 'update' \| 'upsert' \| 'replace' \| 'ignore'>` | optional (default: `"ignore"`) | What a load does with a record whose `externalId` matches an existing row. `ignore` (default) is create-only: a missing row is inserted and an existing row is left as it is, so a replay (every boot, a package install or upgrade, a publish) never writes a seeded value back over a later edit. `upsert` also writes every declared column back onto the matched row on each replay; declare it for reference data the package keeps current. `update` writes matched rows only, `insert` inserts every record with no match, and `replace` inserts into a table the caller cleared. | | **columns** | `Record }>` | optional | Per-column write policy, keyed by field name: `{ status: { applyOn: 'create' } }` writes `status` only when the seed creates the row. Omitted, every column is written on create and update. | | **env** | `Enum<'prod' \| 'dev' \| 'test'>[]` | optional (default: `["prod","dev","test"]`) | Applicable environments | -| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The boot seed filters on the app's i18n.defaultLocale; the marketplace install, sample-data reseed, restart heal and per-organization replay filter on the locale resolved for the load (the localization.locale setting when set, then the installing or founding user's locale, then the app's i18n.defaultLocale where the load names one); package apply and draft publish do not filter by locale — they load every dataset and warn | +| **locale** | `string[]` | optional | Applicable locales (BCP-47 tags); omitted applies to every locale. The boot seed filters on the app's i18n.defaultLocale; the marketplace install, sample-data reseed, restart heal and per-organization replay filter on the locale resolved for the load (the localization.locale setting when set, then the locale of the installing, reseeding or founding user, then the app's i18n.defaultLocale where the load names one); package apply and draft publish do not filter by locale — they load every dataset and warn | | **records** | `Record[]` | ✅ | Data records | | **files** | `Record` | optional | Bytes of the package files the records name with `seedFile(path)`, keyed by path. Written by `os build`, which reads each path relative to the package root; the loader stores each one as a file the written record owns. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | From 15456e098aa5ae75f6327d7816477e8b427391dc Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 19:26:38 +0000 Subject: [PATCH 7/8] docs(spec): regenerate the package-api references page after merging origin/main Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa --- content/docs/references/api/package-api.mdx | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/content/docs/references/api/package-api.mdx b/content/docs/references/api/package-api.mdx index 58e9f4f9bef..932782050e6 100644 --- a/content/docs/references/api/package-api.mdx +++ b/content/docs/references/api/package-api.mdx @@ -461,7 +461,7 @@ Install package response | **success** | `boolean` | ✅ | Operation success status | | **error** | `{ code: Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| …>; declaredCode?: string; message: string; userMessage?: string; … }` | optional | Error details if success is false | | **meta** | `{ timestamp: string; duration?: integer; requestId?: string; traceId?: string }` | optional | Response metadata | -| **data** | `{ package: object; dependencyResolution?: object; namespaceConflicts?: object[]; message?: string }` | ✅ | | +| **data** | `{ manifest: object; source: Enum<'code' \| 'marketplace' \| 'authored'>; status?: Enum<'installed' \| 'disabled' \| 'installing' \| 'upgrading' \| 'uninstalling' \| 'error'>; enabled?: boolean; … }` | ✅ | The installed package row, served bare as `data`: the row the registry recorded, at the authoring stage | ### Nested Shape: `PackageInstallResponse.error` @@ -490,10 +490,19 @@ Install package response | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | -| **package** | `{ manifest: object; source: Enum<'code' \| 'marketplace' \| 'authored'>; status?: Enum<'installed' \| 'disabled' \| 'installing' \| 'upgrading' \| 'uninstalling' \| 'error'>; enabled?: boolean; … }` | ✅ | Installed package details | -| **dependencyResolution** | `{ dependencies: object[]; canProceed: boolean; requiredActions: object[]; installOrder: string[]; … }` | optional | Dependency resolution result | -| **namespaceConflicts** | `{ type: 'namespace_conflict'; requestedNamespace: string; conflictingPackageId: string; conflictingPackageName: string; … }[]` | optional | Namespace conflicts detected | -| **message** | `string` | optional | Installation status message | +| **manifest** | `{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }` | ✅ | Package manifest at the AUTHORING stage; a row installed by a `defineStack()` host carries the assembled body instead — see `AssembledInstalledPackageSchema` / `InstalledPackageAtEitherStageSchema` | +| **source** | `Enum<'code' \| 'marketplace' \| 'authored'>` | ✅ | Where the installed package came from: code (registered by the deployment's own code), marketplace (installed from the marketplace), or authored (a database-authored package) | +| **status** | `Enum<'installed' \| 'disabled' \| 'installing' \| 'upgrading' \| 'uninstalling' \| 'error'>` | optional (default: `"installed"`) | Package state: installed, disabled, installing, upgrading, uninstalling, or error | +| **enabled** | `boolean` | optional (default: `true`) | Whether the package is currently enabled | +| **installedAt** | `string` | optional | Installation timestamp | +| **updatedAt** | `string` | optional | Last update timestamp | +| **installedVersion** | `string` | optional | Currently installed version for quick access | +| **previousVersion** | `string` | optional | Version before the last upgrade | +| **statusChangedAt** | `string` | optional | Status change timestamp | +| **errorMessage** | `string` | optional | Error message when status is error | +| **settings** | `Record` | optional | User-provided configuration settings | +| **upgradeHistory** | `{ fromVersion: string; toVersion: string; upgradedAt: string; status: Enum<'success' \| 'failed' \| 'rolled_back'>; … }[]` | optional | Version upgrade history | +| **registeredNamespaces** | `string[]` | optional | Namespace prefixes registered by this package | --- From d0863ab931e735fbe32bbf98fa30d8eab5092063 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 19:26:40 +0000 Subject: [PATCH 8/8] =?UTF-8?q?docs(spec):=20Seed.locale's=20rung=201=20na?= =?UTF-8?q?mes=20the=20third=20source=20for=20a=20load=20with=20no=20organ?= =?UTF-8?q?ization=20=E2=80=94=20the=20deployment's=20one=20organization's?= =?UTF-8?q?=20own=20setting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Claude Claude-Session: https://claude.ai/code/session_01L6bhgTqqeHSwZYJmApbDCa --- packages/spec/src/data/seed.zod.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/spec/src/data/seed.zod.ts b/packages/spec/src/data/seed.zod.ts index fd26b90a92c..346ba8dfc8d 100644 --- a/packages/spec/src/data/seed.zod.ts +++ b/packages/spec/src/data/seed.zod.ts @@ -274,8 +274,10 @@ export const SeedSchema = lazySchema(() => strictObject({ * `resolveSeedLocaleForLoad` (`@objectstack/runtime`), first answer wins: * the `localization.locale` setting for the organization the rows land in * (a load that names no organization, such as a single-tenant install or - * reseed or the restart heal, still reads it, and the environment override - * or the `global` setting answers), counted only when somebody set it (a + * reseed or the restart heal, still reads it: the environment override + * answers first, then the `global` setting, then, where no wall stands and + * the deployment holds exactly one organization, that organization's own + * setting), counted only when somebody set it (a * value whose `source` is `'default'` is the platform's placeholder, not a * choice); then the `sys_user.locale` * of the user who installs, reseeds or founds the organization, when one