Skip to content

docs(spec): NoSQLIndexSchema.unique documents its deliberate scope-vocabulary omission - #11593

Merged
os-steve merged 1 commit into
mainfrom
claude/issue-11215-nosql-unique-scope
Aug 24, 2026
Merged

os-steve merged 1 commit into
mainfrom
claude/issue-11215-nosql-unique-scope

Conversation

@os-steve

Copy link
Copy Markdown
Collaborator

Fixes #11215

Branch decision: (b) — not tenant-aware / descriptor-layer. Measure-first card; the settling measurement (below) found no consumer that materializes NoSQLIndexSchema declared indexes at all, let alone against organization-aware collections, so the surface documents its deliberate omission of the ADR-0120 scope vocabulary instead of adopting it. Held as draft for the PM's contract review (clause-② path-limb, needs:contract-review hung at claim).

Measurement map

  1. Premise held at merge base 2dc0a770b6: packages/spec/src/data/driver-nosql.zod.ts:403 was still the bare boolean (unique: z.boolean().default(false)), while both sibling surfaces carry the vocabulary — UniqueScopeSchema at packages/spec/src/data/field.zod.ts:476 (used by FieldSchema.unique, field.zod.ts:822) and DeclaredIndexUniqueScopeSchema at packages/spec/src/data/object.zod.ts:431 (used by IndexSchema.unique, object.zod.ts:483, the UniqueScopeSchema's rejection message calls 'organization' "the explicit spelling of true" on BOTH surfaces — on a declared index bare true means 'global', so the message prescribes a silent scope change #10928 / PR fix(spec): give the declared-index unique surface its own rejection message #11213 per-surface message pattern).
  2. NoSQLIndexSchema consumer graph — empty. Repo-wide grep for NoSQLIndexSchema / NoSQLIndex hits only spec's own test (packages/spec/src/data/driver-nosql.test.ts), spec's generated artifacts, and the generated reference docs. No runtime, kernel, or driver import; it is a leaf schema — no other schema embeds it.
  3. The whole driver-nosql.zod.ts module is descriptor vocabulary with no live consumer: NoSQLQuerySchema, NoSQLConnectionSchema, AggregationPipelineSchema, NoSQLDatabaseTypeSchema, NoSQLTransactionOptionsSchema — zero imports outside packages/spec.
  4. isGlobalUnique / isOrganizationUnique reachability from the NoSQL side — none. The driver-facing helpers (packages/spec/src/data/field.zod.ts:490 / :518) are consumed by spec itself and packages/drivers/driver-sql/src/schema-drift.ts:68 only.
  5. The one NoSQL driver that creates indexes takes the other surface. driver-mongodb's syncCollectionSchema (packages/drivers/driver-mongodb/src/mongodb-schema.ts:79, called from mongodb-driver.ts:592) materializes the object-level indexes[] — the IndexSchema shape (mongodb-schema.ts:54-58), which already carries the vocabulary — and is explicitly single-tenant (settled by driver-mongodb 完全没有行级租户隔离:读不加谓词、写不打戳,多租户下跨租户可读写 #3724; mongodb-schema.ts:18-35 and :135-139): every scope materializes the listed columns verbatim, and no organization key part is injected anywhere on the NoSQL side.
  6. ADR-0120 mentions NoSQL zero times. D1's "both spellings" are the field-level and declared-index surfaces; NoSQLIndexSchema was never in the ADR's scope.

Conclusion: the 'organization'/'global' business boundary is stated on the authorable surfaces and resolved into physical key columns above this layer — by the time a descriptor of this shape would reach a NoSQL engine, an organization key part (when there is one) is already a listed field. A scope word here would be declarable-but-inert vocabulary (ADR-0078). The asymmetry the card observed is deliberate, not drift — the card's own stated right outcome for this branch.

Changes

  • packages/spec/src/data/driver-nosql.zod.ts — docblock + describe() on NoSQLIndexSchema.unique: states the layer, the measurement, why the vocabulary deliberately does not apply, and the condition under which UniqueScopeSchema should be adopted (import, never fork). The shape is untouched — still z.boolean().default(false), so no parse/materialization change (the FieldSchema accepts deleteBehavior: 'set_null' on a master_detail, and the engine silently resolves it to cascade #9689 parse-idempotency clause is branch-(a) material and does not arise).
  • content/docs/references/data/driver-nosql.mdx — regenerated (gen:docs).
  • .changeset/nosql-index-unique-scope-docs.md — patch on @objectstack/spec.

Verification

All dispatch-derived gates ran at commit 8db4595ecf (clean tree, exit codes captured before any pipe; wrapper verdict lines quoted):

  • pnpm --filter @objectstack/spec build — os-verify-lock: VERDICT command-exit 0 (runs gen:schema + gen:openapi + tsup + DTS; the authorable-surface roster is byte-unchanged — the key set did not move).
  • pnpm --filter @objectstack/spec check:generated — first run flagged exactly 1 of 14 artifacts stale (content/docs/references/**, the expected product of the describe change); --fix ran gen:docs only; re-verified VERDICT command-exit 0. The new describe text is present in the regenerated driver-nosql.mdx.
  • pnpm --filter @objectstack/spec test — Test Files 420 passed (420), Tests 11213 passed (11213).
  • pnpm --filter @objectstack/spec typecheck — VERDICT command-exit 0.
  • node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack at 8db4595ecf derived 33 families; all 33 green. Two (check:doc-formula-expressions, check:doc-security-posture) first failed on fresh-worktree missing dist (@objectstack/formula, @objectstack/lint) and went green after pnpm --filter "@objectstack/lint..." build — unbuilt-dependency artifacts, not this diff.
  • Declared narrowing (one gate): standalone node scripts/check-dev-prereqs.mjs asserts the entire workspace is built and reds in this fresh worktree because 63 of 67 packages have no dist/ — a build-state precondition CI provisions with a full pnpm build, independent of this diff (population: workspace build state; this diff cannot move it). The spec package's own prereq stamp — the one package this diff touches — was refreshed and verified during the spec build (✓ packages/spec/dist/.build-input-hash).
  • node scripts/check-nul-bytes.mjs — OK (6490 files scanned).

Generated by Claude Code

…ulary 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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T9cDbY2NBiVJWYx3BpWfH2
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation protocol:data tooling labels Aug 24, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. ✅

What this run could not see
  • the SDK route bridge reached 45 of 222 client-bound route-ledger rows — the other 177 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run: node scripts/docs-audit/affected-docs.mjs --bridge-coverage

Coarse fallback — 126 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 2dc0a770b61fa0b140994ddcdbe692256eb53666 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 99201179e0045d29105fe6cc097260bf0688e741 — the merge of head 8db4595ecff4189b2c789c341d0d41a023efa784 into base 2dc0a770b61fa0b140994ddcdbe692256eb53666, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 99201179e0045d29105fe6cc097260bf0688e741 && git checkout 99201179e0045d29105fe6cc097260bf0688e741
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2dc0a770b61fa0b140994ddcdbe692256eb53666 8db4595ecff4189b2c789c341d0d41a023efa784 && git checkout -B drift-repro 2dc0a770b61fa0b140994ddcdbe692256eb53666 && git merge --no-ff 8db4595ecff4189b2c789c341d0d41a023efa784

node scripts/docs-audit/affected-docs.mjs --json 2dc0a770b61fa0b140994ddcdbe692256eb53666

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@os-steve
os-steve marked this pull request as ready for review August 24, 2026 07:16
@os-steve
os-steve added this pull request to the merge queue Aug 24, 2026
Merged via the queue into main with commit 42a117b Aug 24, 2026
33 checks passed
@os-steve
os-steve deleted the claude/issue-11215-nosql-unique-scope branch August 24, 2026 07:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:data size/s tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants