Skip to content

fix(spec): MONGODB_MULTI_TENANT_UNSUPPORTED leaves the error-code ledger — a boot refusal never reaches a wire envelope (#8035) - #8239

Merged
huangyiirene merged 4 commits into
mainfrom
claude/issue-8035-unregister-unemittable-code
Aug 13, 2026
Merged

fix(spec): MONGODB_MULTI_TENANT_UNSUPPORTED leaves the error-code ledger — a boot refusal never reaches a wire envelope (#8035)#8239
huangyiirene merged 4 commits into
mainfrom
claude/issue-8035-unregister-unemittable-code

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Fixes #8035

ERROR_CODE_LEDGER (ADR-0112 D3) registered MONGODB_MULTI_TENANT_UNSUPPORTED under @objectstack/driver-mongodb (#3724). The finding-grading round on #8035 measured the code as registered-but-unemittable; this PR re-verified both readings on the merged tree before deleting, then unregisters the ledger row only.

Premise re-verification (both readings, on this branch's tree)

  1. Boot path rethrows pre-HTTP. packages/cli/src/commands/serve.ts:1279 rethrows a driver-construction failure on e?.code === 'MONGODB_MULTI_TENANT_UNSUPPORTED' into run()'s fatal handler — the process prints and exits 1 before any HTTP server exists. No envelope.
  2. The one request-reachable trigger is swallowed. assertObjectsNotTenantScoped (thrown from the driver's syncSchema/syncSchemasBatch) reaches request scope only via engine.syncObjectSchema inside ensureObjectStorage (packages/metadata-protocol/src/protocol.ts:9915-9922), whose catch is a documented "best-effort + non-fatal" console.warn. No envelope.
  3. Sweep of every other caller of the sync path (beyond the two readings the grading round measured): ObjectQLEngine.syncSchemas catches per-object into logger.error ([convention] best-effort 降级导致"看起来正常、实则不持久"时不应记 warn——把 #4460 的点状修复定成规则 #4632); the objectql plugin's boot sync catches into reportSyncFailure; service-datasource's connect path catches into logger.warn; the lifecycle sweep's archiveObject cold-store sync is caught by the per-object handler into report.errors + warn (a message string, never a wire error.code); packages/verify is CLI tooling. No wire path exists.

Consumer check (per the ledger's "Retiring a code" section)

  • Repo-wide exact-name search: the ledger row itself, two generated reference pages (contract.mdx, error-code-ledger.mdx), the driver's guard constant + README + drivers.mdx (all describe the thrown error object, which is unchanged — every sentence stays true), the CLI's duck-typed boot match (a consumer of the thrown object, not of the wire vocabulary — stays), and historical changesets/CHANGELOGs. No wire producer, no wire consumer.
  • objectui at origin/main: 0 hits (positive control on VALIDATION_FAILED confirms the grep saw the tree).
  • cloud (GitHub org-wide code search): 0 hits outside this repo.
  • Nothing gates an emission on ledger membership, so the removal changes no accept/reject verdict at runtime; the narrowing is type-level (ErrorCode / ApiErrorSchema.code).

What changed

  • packages/spec/src/api/error-code-ledger.zod.ts: the @objectstack/driver-mongodb entry (whose only row was this code) is removed. The header's "Retiring a code" section now names the second shape of the class: a row that never had a wire path, as opposed to one that lost its producer (OVERLAY_PERSISTENCE_FAILED / 删除 saveMetaItem legacy 写入分支后的三处残留:一个无生产者的 ledger 错误码 + 两处已过期的跨包注释 #5783, the precedent this PR mirrors).
  • packages/spec/src/api/error-code-ledger.test.ts: the wire vocabulary's refusal is asserted — ErrorCode.parse('MONGODB_MULTI_TENANT_UNSUPPORTED') throws, the union does not contain the string, and the owner key is gone (a future driver-mongodb wire code re-registers deliberately, with an emit path, not by reverting this PR).
  • packages/drivers/driver-mongodb/src/mongodb-tenancy-guard.test.ts: new pin — MULTI_TENANT_UNSUPPORTED_CODE === 'MONGODB_MULTI_TENANT_UNSUPPORTED'. With the ledger row gone this is the only cross-package guard on the literal the CLI matches duck-typed; a silent rename would un-arm the CLI's loud-fail path and boot the server with no driver (the exact failure driver-mongodb 完全没有行级租户隔离:读不加谓词、写不打戳,多租户下跨租户可读写 #3724 removed). The boot refusal itself — constant, error class, message, CLI match — is untouched, and its existing tests (message names the knobs, the escape route, and every offending object) all still pass.
  • content/docs/references/api/*.mdx: regenerated — the code leaves the two reference pages, and the ErrorCode enum count drops 264 → 263 across the API pages.
  • Changeset: @objectstack/spec patch — wire impact none (no response ever carried the code; the narrowing is type-level, and there is no emit site to reject), mirroring the 删除 saveMetaItem legacy 写入分支后的三处残留:一个无生产者的 ledger 错误码 + 两处已过期的跨包注释 #5783 precedent's bump. Not a declared-breaking changeset, so no ADR-0087 disposition marker is owed (check-adr-0087-registration --base origin/main: "adds no declared-breaking changeset"); the ADR-0087 conversion registry governs authorable metadata shapes, not the response vocabulary.

Verification (all post-merge of main @ fa4897335)

  • @objectstack/spec test: 385 files / 10196 tests passed; typecheck green.
  • @objectstack/driver-mongodb test: 16 files passed, 5 skipped / 365 tests passed, 143 skipped (skips are the suites needing a live MongoDB binary — pre-existing).
  • @objectstack/rest test: 104 files / 1744 tests passed.
  • check:generated: all 13 artifacts up to date from the merged tree (api-surface unchanged — the export set is unchanged, only the union narrows).
  • Gate farm: adr-anchors, changeset-gate-self-tests, cross-package-test-inputs, doc-formula-expressions, docs-audit-scope, i18n (9 bundles in sync), merge-driver, release-body, spec-parsed-alias, nul-bytes, error-code-casing — all pass.

Reverse verification (direction predicted before running)

  • Declarations: a probe compiled against the rebuilt dist .d.tsconst retired: ErrorCode = 'MONGODB_MULTI_TENANT_UNSUPPORTED' fails with TS2322 while the 'VALIDATION_FAILED' control compiles; a @ts-expect-error variant compiles clean (exactly one absorbed error). Proves the narrowing is in the built declarations, not a cached tree.
  • Runtime: temporarily restoring the deleted ledger row turned exactly the new rejection test red (1 failed | 8 passed in error-code-ledger.test.ts — the retired string parses again) and nothing else; restoring the committed state returned the file to 9 passed.

Generated by Claude Code


Generated by Claude Code

claude added 2 commits August 12, 2026 20:38
…ger (#8035)

The code was registered under @objectstack/driver-mongodb (#3724) but no
response envelope can carry it: the CLI boot handler rethrows the tenancy
refusal pre-HTTP and aborts, and the one request-reachable trigger
(assertObjectsNotTenantScoped via syncObjectSchema inside the metadata
protocol's ensureObjectStorage) is swallowed by a documented best-effort
catch. Registered-but-unemittable is the class the ledger header names;
precedent OVERLAY_PERSISTENCE_FAILED / #5783 — this instance is the sister
shape (never had a wire path, rather than lost it), now documented in the
header.

The boot refusal stays untouched: MULTI_TENANT_UNSUPPORTED_CODE, the error
class, its message, and the CLI's duck-typed literal match. A new
driver-mongodb test pins the code literal (with the ledger row gone it is
the only cross-package guard on the literal serve.ts matches); the ledger
test now asserts the wire vocabulary refuses the retired string. Reference
docs regenerated (ErrorCode enum 264 -> 263).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r
@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 13, 2026 2:16am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

106 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/tenancy-modes.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/permissions/system-context.mdx (via packages/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/apps.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/field-grouping-and-order.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

7 release-owned page(s) also reference the affected code. These are read-only:

  • content/docs/releases/implementation-status.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

claude added 2 commits August 13, 2026 01:58
os-regen merge lap for landing: merge origin/main (committed first, per
scripts/pm/os-regen-merge.sh), then wholesale regen of the os-regen'd
references/api pages from the merged tree. Sibling assertions on the
regenerated tree: #8230 retirement state (def names only in retirement
prose + migration entry), #8232 currency fraction-digit guard, #8234's
13 comparand-door exports in api-surface/data.json, #8236's groupBy
union row all survive; MONGODB_MULTI_TENANT_UNSUPPORTED stays absent
from the ledger and the references ErrorCode union reads main-minus-one
(+265 -> +264; the union grew by 2 on main since the previous lap).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r
@huangyiirene
huangyiirene marked this pull request as ready for review August 13, 2026 02:35
@huangyiirene
huangyiirene added this pull request to the merge queue Aug 13, 2026
Merged via the queue into main with commit 4dc1c7d Aug 13, 2026
27 checks passed
@huangyiirene
huangyiirene deleted the claude/issue-8035-unregister-unemittable-code branch August 13, 2026 02:53
huangyiirene pushed a commit that referenced this pull request Aug 13, 2026
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 17, 2026
…ered/virtualScroll (ADR-0049, objectstack-ai#7176) (objectstack-ai#8252)

* refactor(spec)!: retire pass-through-only list-view keys striped/bordered/virtualScroll (ADR-0049, objectstack-ai#7176)

Maintainer ruling 2026-08-10: every measured reader copies the key forward
and ObjectGrid, where the chains end, never applies any of the three —
copy-without-apply is dead in effect. retiredKey() tombstones on
ListViewSchema (radiating into ObjectListViewSchema), ADR-0087 D2 conversion
view-list-passthrough-keys-removed + D3 chain step + six
RETIRED_KEYS_BY_MAJOR[17] entries, ledger rows flipped to dead with the
retirement note, form inputs pruned, docs updated, changeset with FROM->TO.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r

* test(spec): match the striped prescription's actual casing in the pin test

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r

* merge origin/main (os-regen artifacts taken from main; regeneration follows)

* chore(spec): regenerate artifacts after merging origin/main (4dc1c7d relay: objectstack-ai#8230/objectstack-ai#8232/objectstack-ai#8234/objectstack-ai#8236/objectstack-ai#8239)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123k4cam2jEAkPmbJeoaY3r

---------

Co-authored-by: Claude <noreply@anthropic.com>
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 size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] MONGODB_MULTI_TENANT_UNSUPPORTED may be registered-but-unemittable in the error-code ledger — a boot refusal never reaches a wire envelope

2 participants