From 8db4595ecff4189b2c789c341d0d41a023efa784 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 24 Aug 2026 07:06:51 +0000 Subject: [PATCH] docs(spec): document NoSQLIndexSchema.unique's deliberate scope-vocabulary omission (#11215) The bare boolean is deliberate: this schema is the raw NoSQL driver-configuration descriptor layer below the tenancy seam. Nothing in the repo materializes indexes from NoSQLIndexSchema (leaf schema, no runtime/kernel/driver import), and the one NoSQL driver that creates indexes (driver-mongodb syncCollectionSchema) consumes the object-level indexes[] surface -- IndexSchema, which already carries the ADR-0120 vocabulary -- and is explicitly single-tenant (#3724). A scope word here would be declarable-but-inert (ADR-0078). Docblock + describe() now say so, and name the condition under which UniqueScopeSchema should be adopted. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01T9cDbY2NBiVJWYx3BpWfH2 --- .changeset/nosql-index-unique-scope-docs.md | 5 ++++ content/docs/references/data/driver-nosql.mdx | 2 +- packages/spec/src/data/driver-nosql.zod.ts | 28 +++++++++++++++++-- 3 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 .changeset/nosql-index-unique-scope-docs.md diff --git a/.changeset/nosql-index-unique-scope-docs.md b/.changeset/nosql-index-unique-scope-docs.md new file mode 100644 index 0000000000..f19fcdcb70 --- /dev/null +++ b/.changeset/nosql-index-unique-scope-docs.md @@ -0,0 +1,5 @@ +--- +'@objectstack/spec': patch +--- + +Document why `NoSQLIndexSchema.unique` stays a bare boolean instead of the ADR-0120 unique-scope vocabulary carried by `FieldSchema.unique` and `IndexSchema.unique`: the schema is a raw NoSQL driver-configuration descriptor below the tenancy seam — nothing materializes indexes from it, and the one NoSQL driver that creates indexes (driver-mongodb) consumes the object-level `indexes[]` surface (which already carries the vocabulary) and is explicitly single-tenant (#3724) — so a scope word here would be declarable-but-inert vocabulary (ADR-0078). The `describe()` and docblock now state the deliberate omission and the condition under which `UniqueScopeSchema` should be adopted, so the asymmetry with the other two `unique` surfaces is not mistaken for drift (#11215). diff --git a/content/docs/references/data/driver-nosql.mdx b/content/docs/references/data/driver-nosql.mdx index 00ba2e074a..4d4fc3c5c0 100644 --- a/content/docs/references/data/driver-nosql.mdx +++ b/content/docs/references/data/driver-nosql.mdx @@ -150,7 +150,7 @@ const result = AggregationPipelineSchema.parse(data); | **name** | `string` | ✅ | Index name | | **type** | `Enum<'single' \| 'compound' \| 'unique' \| 'text' \| 'geospatial' \| 'hashed' \| 'ttl' \| 'sparse'>` | ✅ | Index type | | **fields** | `{ field: string; order?: Enum<'asc' \| 'desc' \| 'text' \| '2dsphere'> }[]` | ✅ | Fields to index | -| **unique** | `boolean` | optional (default: `false`) | Enforce uniqueness | +| **unique** | `boolean` | optional (default: `false`) | Enforce uniqueness over exactly the listed `fields`. Boolean on purpose — no ADR-0120 scope vocabulary here: this is the raw driver-descriptor layer, below tenancy. The 'organization'/'global' boundary is stated on the authorable surfaces (FieldSchema.unique, IndexSchema.unique) and resolved into physical key columns before a descriptor like this is built, so an organization key part, when there is one, is already a listed field (#11215) | | **sparse** | `boolean` | optional (default: `false`) | Sparse index | | **expireAfterSeconds** | `integer` | optional | TTL in seconds | | **partialFilterExpression** | `Record` | optional | Partial index filter | diff --git a/packages/spec/src/data/driver-nosql.zod.ts b/packages/spec/src/data/driver-nosql.zod.ts index b625f27362..b763299ff1 100644 --- a/packages/spec/src/data/driver-nosql.zod.ts +++ b/packages/spec/src/data/driver-nosql.zod.ts @@ -398,9 +398,31 @@ export const NoSQLIndexSchema = lazySchema(() => z.object({ })).describe('Fields to index'), /** - * Unique constraint - */ - unique: z.boolean().default(false).describe('Enforce uniqueness'), + * Unique constraint — a bare boolean, DELIBERATELY not the ADR-0120 scope + * vocabulary (`UniqueScopeSchema`'s `boolean | 'global' | 'organization'`, + * carried by `FieldSchema.unique` and `IndexSchema.unique`). + * + * This file is the raw NoSQL driver-configuration descriptor layer, not an + * organization-aware authoring surface. Measured for #11215: nothing in the + * repo parses `NoSQLIndexSchema` or materializes indexes from it (a leaf + * schema — no runtime, kernel, or driver import), and the one NoSQL driver + * that does create indexes (driver-mongodb's `syncCollectionSchema`) + * consumes the object-level `indexes[]` surface — `IndexSchema`, which + * already carries the scope vocabulary — and is explicitly single-tenant + * (#3724), injecting no organization key part. The business boundary of a + * unique constraint ('organization' vs 'global') is stated on those + * authorable surfaces and resolved into physical key columns ABOVE this + * layer; by the time a descriptor like this one reaches a NoSQL engine, the + * organization key part — when there is one — is already a listed entry in + * `fields`. A scope word here would have no consumer to honor it, which is + * exactly the declarable-but-inert vocabulary ADR-0078 forbids. So the + * asymmetry with the other two `unique` surfaces is deliberate, not drift. + * If a NoSQL driver ever grows row-level tenancy and starts materializing + * THIS shape against organization-scoped collections, adopt + * `UniqueScopeSchema` here (import it — never fork the union) in the same + * change. + */ + unique: z.boolean().default(false).describe("Enforce uniqueness over exactly the listed `fields`. Boolean on purpose — no ADR-0120 scope vocabulary here: this is the raw driver-descriptor layer, below tenancy. The 'organization'/'global' boundary is stated on the authorable surfaces (FieldSchema.unique, IndexSchema.unique) and resolved into physical key columns before a descriptor like this is built, so an organization key part, when there is one, is already a listed field (#11215)"), /** * Sparse index (only index documents with the field)