Skip to content

docs(objectql,spec): the tenant column is stamped and never NULL on single-tenant stacks (C1) - #25135

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-25128-tenant-column-never-null-comments
Oct 21, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-25128-tenant-column-never-null-comments

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

This PR carries item C1 only of #25128. Item B6 (narrowing the blanket pre-18 relax rigs) moved to #25132 under the claim's split; #25132 is not addressed here.

Fixes #25128

Clause-②: no (comment and docblock text only: no accept set, response, status, error, outcome or export moves)
Metadata-protocol: none

What changes

Since 7b-0 (#24940, merged as 5e9b100743), a table the driver creates carries its tenant column (organization_id) NOT NULL, and an insert is stamped (under single with the Default Organization). Three comments still said the column stays NULL on single-tenant stacks. Each now uses the wording 7b-0 used for the two sites it corrected (applySystemFields' docblock in registry.ts and SystemFieldName.ORGANIZATION_ID in system-names.ts): org-scoping stamps it on insert (under single with the Default Organization), and it is never NULL (ADR-0131 D1). Each comment keeps the rest of what it said; in particular the INDEX is still gated on multi-tenant mode.

File Site +/-
packages/objectql/src/registry.ts the comment at the organization_id gate in applySystemFields ("it just stays NULL when no tenant context exists") +3 / -2
packages/objectql/src/registry-tenant-index-declaration.test.ts the comment above expect(def.fields.organization_id).toBeDefined() ("it just stays NULL") +2 / -1
packages/spec/src/data/object.zod.ts the organization_id bullet of the systemFields docblock ("It stays NULL on single-tenant stacks"). The multi-tenant attribution to @objectstack/organizations (the org-scoping service) is kept +4 / -3
.changeset/25128-tenant-column-never-null-comments.md patch for @objectstack/spec +10

No code, assertion, .describe() text or CHANGELOG changes.

Cross-lane: packages/spec/src/data/object.zod.ts is a domain:spec file. The seat declares it to the spec seat.

What main does (read before editing)

  • NOT NULL: driver-sql createColumn takes a tenantColumn argument, and if (declaresColumnNotNull(field) || tenantColumn) makes the column not-nullable on both exits. Only the CREATE TABLE sites pass it (initObjects' create branch, ensureShardTable). The driver-turso remote face's buildCreateTableSQL does the same. Pinned by sql-driver-tenant-column-not-null.test.ts and turso-remote-tenant-column-not-null.test.ts.
  • The stamp under single: ObjectQL.resolveSystemInsertOrganization (packages/objectql/src/engine.ts) runs after the beforeInsert hooks. For a system insert that carries no organization, it calls resolveSystemWriteOrganization (packages/core/src/security/system-write-organization.ts), which answers derived when exactly one organization exists under single (the Default Organization). The engine threads that id as DriverOptions.tenantId, and the driver stamps the column with it. The comment's own block says "stamped with the derived organization or refused below — never left NULL". A session write carries its organization on the context.
  • Generator: nothing committed is generated from the systemFields docblock. build-docs.ts renders from json-schema/ (built from .describe()) plus each module's file-level header (renderFileDescription), never a property docblock. A repo-wide git grep of the docblock's text hits only object.zod.ts. After pnpm --filter @objectstack/spec build, git status is clean and check:generated reports all 14 artifacts up to date. The text does ship, through the built dist/ and src/**/*.zod.ts in spec's files[], so @objectstack/spec takes a patch changeset. objectql's files[] is dist only: after a build, dist/ holds applySystemFields (positive control) and none of the comment text.
  • Census (git grep -i for "stays NULL", "NULL on single-tenant", "stays null", "remains NULL" and "left NULL", plus a single-tenant/NULL regexp, over packages/objectql and packages/spec): only these three tenant-column sites. The other hits are unrelated (owner_id "when left NULL", nullable booleans, aggregates, notNull). Outside the fence, one hand-written page has the same stale sentence. It is named under Acceptance notes and not edited.

Verification

All on head ca06c671d, which includes the merge of origin/main 1b3b65e64, unless marked otherwise.

  • pnpm exec turbo run build --concurrency=2 (under the verify lock): 77/77 tasks, VERDICT command-exit 0.
  • pnpm --filter @objectstack/objectql typecheck: exit 0 (tsc and check:test-typecheck OK).
  • pnpm --filter @objectstack/spec typecheck: exit 0 (tsc, scripts-typecheck and check:test-typecheck OK).
  • pnpm --filter @objectstack/objectql exec vitest run --maxWorkers=2 src/registry-tenant-index-declaration.test.ts: 1 file, 12/12 tests passed.
  • pnpm --filter @objectstack/spec check:generated: exit 0, all 14 generated artifacts up to date, and the build left no tracked change.
  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, with no paths: 94 commands derived and 94 run, every exit code captured before any pipe. All 94 exited 0. --ran reconciliation: "94 derived famil(ies) accounted for — 94 run, 0 NOT-MEASURED (a DERIVED zero — all 94 recorded an exit code and none of them is 3)", exit 0.
  • On the pre-merge head 3c3a5759b, the same derivation ran 94 commands (86, plus 8 once the changeset existed). All exited 0 except pnpm check:dual-build-cjs-loads, which exited 3 (PREREQUISITE NOT MET: no dist/). After the full build it ran again and exited 0.
  • Not measured locally (CI's): the path-scheduled CI jobs and type-check lanes the derivation names, Test Core shards, and test:repo.
  • No ablation, because no tested behaviour changes.

Acceptance notes

  • content/docs/protocol/objectql/schema.mdx (section "Multi-Tenant Schemas") still says the injected organization_id "stays NULL where no organization context exists". It is a hand-written docs page outside this card's file surface, so it is named here and not edited. Carrier: none.

Generated by Claude Code

…ingle-tenant stacks

Three comments still said organization_id stays NULL on single-tenant
stacks. Since 7b-0 a table the driver creates carries the tenant column
NOT NULL, and an insert is stamped (under `single` with the Default
Organization). Reword them the way 7b-0 reworded applySystemFields'
docblock and SystemFieldName.ORGANIZATION_ID. Comment text only.

Claude-Session: https://claude.ai/code/session_01Xwr1aPkHuFRqE9RSahyogV
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/objectql, @objectstack/spec, touching 2 documentable anchor(s).

2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/concepts/metadata-driven.mdx (via ObjectSchemaBase (symbol, a top-level const object))
  • content/docs/permissions/system-context.mdx (via applySystemFields (symbol, a top-level function))
What this run could not see
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 145 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 1b3b65e643bf31d2cb4764dbfc18a04234194bbf → packageMentionDocs.

Which tree this was computed on

This run read content/docs from af63be7f6302cc9c0f36d034610874d7909835ba — the merge of head ca06c671d4df5d31e6be64e44d4dc9dd8b19b314 into base 1b3b65e643bf31d2cb4764dbfc18a04234194bbf, 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 af63be7f6302cc9c0f36d034610874d7909835ba && git checkout af63be7f6302cc9c0f36d034610874d7909835ba
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 1b3b65e643bf31d2cb4764dbfc18a04234194bbf ca06c671d4df5d31e6be64e44d4dc9dd8b19b314 && git checkout -B drift-repro 1b3b65e643bf31d2cb4764dbfc18a04234194bbf && git merge --no-ff ca06c671d4df5d31e6be64e44d4dc9dd8b19b314

node scripts/docs-audit/affected-docs.mjs --json 1b3b65e643bf31d2cb4764dbfc18a04234194bbf

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

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 1b3b65e643bf31d2cb4764dbfc18a04234194bbf → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: TIER_DEFAULT
Head-sha: ca06c671d4
Local-runs: none

Scope: the net diff against the merge base (4 files, +19/−6):

  • packages/objectql/src/registry.ts: the comment at applySystemFields' organization_id gate;
  • packages/objectql/src/registry-tenant-index-declaration.test.ts: the comment above expect(def.fields.organization_id).toBeDefined();
  • packages/spec/src/data/object.zod.ts: the systemFields docblock's organization_id bullet;
  • the changeset.

Read with them:

① Derived judgments

  • Each comment now says what 7b-0 already says at the sites it corrected: right.
    • All three use the same wording: org-scoping stamps the column on insert (under single with the Default Organization), and it is never NULL (ADR-0131 D1).
    • Each keeps the rest of what it said: the column is always provisioned, and only its index is gated on multi-tenant mode. The spec bullet also keeps its attribution to @objectstack/organizations in multi-tenant mode.
  • The wording is backed by main, as read by the dev before the edit.
    • NOT NULL comes from driver-sql's createColumn tenant argument on its CREATE TABLE sites, and from driver-turso's buildCreateTableSQL.
    • The single-posture stamp is ObjectQL.resolveSystemInsertOrganization calling resolveSystemWriteOrganization, which answers the one organization under single. That id reaches the driver as DriverOptions.tenantId.
  • Nothing else moves. No code, assertion, .describe() text or CHANGELOG line is touched. The spec edit is inside a /** */ docblock. build-docs renders JSON Schema from .describe() and file headers, not property docblocks, so nothing generated changes. check:generated reports 14/14 up to date.
  • The census is complete inside the fence. The seat's read on 4e2c42f363 and the dev's on the merged head both find only these three tenant-column sites in objectql and spec.
  • No ablation is owed: no tested behavior changes.

② Semver level

  • One changeset, patch for @objectstack/spec only. That is right: spec ships src/**/*.zod.ts and its dist, and both carry the docblock. objectql's published dist carries no comment text, so a release of it would ship nothing. The dev's open question is answered A: name only what ships.
  • The changeset and the PR body carry the claim's Clause-②: no (comment and docblock text only: …) line verbatim at a line start, and Metadata-protocol: none.

③ Boundary flags

  • Cross-lane:
  • Not governed: check-governed-merges matched 0 of 4 paths; 25 changed lines.
  • git merge-tree --write-tree against today's origin/main (1b3b65e643) is clean.
  • Deviations, all accepted:
    • the changeset, outside the claim's surface, which the Check Changeset gate requires;
    • the spec bullet joined rather than replaced, to keep its multi-tenant attribution;
    • Fixes #25128 on the PR body's third line, after the C1/B6 line the dispatch asked for first;
    • four pushes to the branch;
    • the AGENTS.md commit trailers.
  • Open questions: one, answered A above.
  • CI on ca06c671d4: 6 of 41 check-runs still running at this read. The ACCEPT waits for green.

Implemented-by: claude/issue-25128-tenant-column-never-null-comments
Reviewed-by: session_01JtSQQ3EWsbNPzyYMug1tXy

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · domain:engine seat 1 · session_01JtSQQ3EWsbNPzyYMug1tXy · 2026-10-21T20:09Z · ACCEPT

Head: ca06c671d4. It carries the three comment corrections, the changeset and a merge of main.

Card #25128 (p3, tooling, area:access), item C1 only: claim 6323015024 (item B6 split to #25132, since triaged to domain:services), dispatch 6323056619. Dev report: 6324346635.

Item Reading
Shape Draft PR → main. The body opens with the C1/B6 line, then Fixes #25128. 4 files, +19/−6. Not governed: check-governed-merges matched 0 of 4 paths.
Scope Three comments that still said the tenant column organization_id stays NULL on single-tenant stacks now say what main does since 7b-0: org-scoping stamps it on insert (under single with the Default Organization), and it is never NULL (ADR-0131 D1). The sites are objectql's registry.ts and registry-tenant-index-declaration.test.ts, and spec's systemFields docblock.
Seat's own read The wording is the one 7b-0 already shipped at the sites it corrected. Each comment keeps the rest of what it said, including the multi-tenant index gate. No code, assertion, .describe() text or CHANGELOG line moves.
Review TIER_DEFAULT. Record 6324719576 is PASS on this head.
Declaration One changeset, @objectstack/spec patch (spec ships src/**/*.zod.ts; objectql's dist carries no comment text), with Clause-②: no (comment and docblock text only: …) and Metadata-protocol: none at line starts, as on the PR body.
Cross-lane object.zod.ts declared to domain:spec on #6017 (6324737500); no objection at this read. The stale schema.mdx:723 sentence outside the fence is pointed to domain:devx on #6023 (6324756974), with no card filed.
Gates Dev at ca06c671d: 94 derived, 94 run, all exit 0. objectql and spec typecheck exit 0. The tenant-index test passed 12/12. check:generated 14/14 up to date. Full turbo build 77/77.
CI At this read on ca06c671d4: ci-failure GREEN, all 42 check-runs completed, none failed. Test Core (2/6) first died to runner loss: exit 143, "The runner has received a shutdown signal", every test before it green. Its one re-run (run 39659411362, attempt 2) passed. git merge-tree against today's origin/main (1b3b65e643) is clean.

Disposition:

  • open_questions: one, answered A: the changeset names @objectstack/spec only.
  • deviations: all accepted:
    • the changeset the Check Changeset gate requires;
    • the spec bullet joined rather than replaced;
    • Fixes on the body's third line;
    • four pushes;
    • the AGENTS.md commit trailers.
  • out_of_scope_findings: the schema.mdx:723 sentence, pointed to domain:devx, not filed.

Landing: ordinary queue (pr_ready + automerge_enable through the relay). Fixes #25128 then closes the card; B6 lives on as #25132.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 21, 2026 20:10
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 21, 2026 20:10
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 21, 2026
Merged via the queue into main with commit 863c580 Oct 21, 2026
56 of 58 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-25128-tenant-column-never-null-comments branch October 21, 2026 20:45
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 tests tooling

Projects

None yet

2 participants