You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Ruling (maintainer, 2026-09-18, live chat, verbatim): 「organizationField 撤出可授权面 同意你的建议」 — filed on that word. The recommendation it accepts: take the key off the authorable surface and keep its one real use as a platform-internal fact, but do it on its own card, AFTER #18420 lands.
What is wrong today
tenancy.organizationField is an authorable key — packages/spec/authorable-surface/data.json carries data/TenancyConfig:organizationField, so any app author can declare it on any object. That means every future piece of organization-related logic has to consider "what if somebody set this?".
It does not earn that reach. Measured on main, the whole repository declares it once:
Every other hit is a test fixture, a spec docblock, a generated JSON-schema, or a comment. Zero business objects declare it, and the spec's own docblock says why: "For ordinary objects the two coincide and organizationField is never needed."
Why sys_api_key needs it at all (⛔ do not "just use organization_id")
Two facts make this table genuinely different, and both must survive the change:
It is managedBy: 'better-auth' (sys-api-key.object.ts:22). resolveInjectedSystemColumns bails on managedBybefore tenancy is consulted, so the platform never injects organization_id here. The column that exists is better-auth's active_organization_id (:231).
So the key's whole job is: one unwalled table whose audit/approval/run rows still stamp the organization the row is about. That is a fact about a platform table we ship — not a knob customers need.
Proposed change
Remove organizationField from TenancyConfigSchema (packages/spec/src/data/object.zod.ts) and add its row to TENANCY_RETIRED_KEY_GUIDANCE beside the two existing precedents (tenancy.strategy, tenancy.crossTenantAccess, both removed after v15.0 with a prescription each).
Replace limb 0 with a platform-internal constant in packages/metadata-core/src/record-organization.ts — one row, sys_api_key → active_organization_id, read by the stamp face only. The three sanctioned platform-row writers (audit stamping, the approval-row writer, the automation-run recorder) keep their behaviour byte for byte; their pins should stay green untouched.
ADR-0087 conversion entry — retiring an authorable key is a protocol change, and an app that declared it needs a rewrite or a named refusal rather than a silent drop.
Regenerate: json-schema/**, authorable-surface/data.json, liveness/object.json (its organizationField evidence row moves or retires), the generated reference page.
⚠️ This card is itself Clause-②: yes (an authorable key leaves the published surface), so it owes its own contract review.
⚠️ The honest risk: an app outside this repo that declared the key will be refused after the change. The ADR-0087 conversion plus the guidance row are exactly the machinery for that, but this is a real protocol change, not a cleanup.
Acceptance criteria
authorable-surface/data.json no longer carries data/TenancyConfig:organizationField, and the gate over that baseline is green.
An object declaring tenancy.organizationField is refused with the guidance row's prescription, pinned.
objectstack migrate meta rewrites or names the refusal for a declaration carried by an older artifact (ADR-0087 entry, with its own acceptance criteria).
Ruling (maintainer, 2026-09-18, live chat, verbatim): 「organizationField 撤出可授权面 同意你的建议」 — filed on that word. The recommendation it accepts: take the key off the authorable surface and keep its one real use as a platform-internal fact, but do it on its own card, AFTER #18420 lands.
What is wrong today
tenancy.organizationFieldis an authorable key —packages/spec/authorable-surface/data.jsoncarriesdata/TenancyConfig:organizationField, so any app author can declare it on any object. That means every future piece of organization-related logic has to consider "what if somebody set this?".It does not earn that reach. Measured on
main, the whole repository declares it once:Every other hit is a test fixture, a spec docblock, a generated JSON-schema, or a comment. Zero business objects declare it, and the spec's own docblock says why: "For ordinary objects the two coincide and
organizationFieldis never needed."Why
sys_api_keyneeds it at all (⛔ do not "just useorganization_id")Two facts make this table genuinely different, and both must survive the change:
managedBy: 'better-auth'(sys-api-key.object.ts:22).resolveInjectedSystemColumnsbails onmanagedBybefore tenancy is consulted, so the platform never injectsorganization_idhere. The column that exists is better-auth'sactive_organization_id(:231).organization_idcolumn" IS the wall —computeTenantField/resolveTenantFieldNamefall back to it and the Layer-0 wall exempts objects that lack it. Naming the columnorganization_idwould wall the credential table on an equality that excludes NULL, and every pre-[finding] API keys carry no organization — under the isolated posture a minted key reads no org data at all (no leak, but the key surface is inert) #8287 key would vanish from its own owner's "My Keys" list. That is the defect [finding] API keys carry no organization — under the isolated posture a minted key reads no org data at all (no leak, but the key surface is inert) #8287 exists to have removed, and the object's own comment forbids the move in as many words.So the key's whole job is: one unwalled table whose audit/approval/run rows still stamp the organization the row is about. That is a fact about a platform table we ship — not a knob customers need.
Proposed change
organizationFieldfromTenancyConfigSchema(packages/spec/src/data/object.zod.ts) and add its row toTENANCY_RETIRED_KEY_GUIDANCEbeside the two existing precedents (tenancy.strategy,tenancy.crossTenantAccess, both removed after v15.0 with a prescription each).packages/metadata-core/src/record-organization.ts— one row,sys_api_key → active_organization_id, read by the stamp face only. The three sanctioned platform-row writers (audit stamping, the approval-row writer, the automation-run recorder) keep their behaviour byte for byte; their pins should stay green untouched.json-schema/**,authorable-surface/data.json,liveness/object.json(itsorganizationFieldevidence row moves or retires), the generated reference page.groupposture is an on-premise shape — should package-authored scheduled flows run undergroupwith the switch on, and which organization do their writes carry? (ruling G item 3, reopened by the maintainer) #18378 (resolveRecordWallOrganizationField) is unaffected — it never read the key.The playbook for all of this already exists in-repo:
.claude/skills/spec-property-retirement.Sequencing and risk
groupruns package-authored scheduled work without a declaration, owning each run's writes per record #18420 lands. It touches the same module and the same spec file; running both at once buys a conflict for nothing. feat(spec,types,triggers)!:groupruns package-authored scheduled work without a declaration, owning each run's writes per record #18420 does not depend on this card in either direction — it already stopped reading the key.Clause-②: yes(an authorable key leaves the published surface), so it owes its own contract review.Acceptance criteria
authorable-surface/data.jsonno longer carriesdata/TenancyConfig:organizationField, and the gate over that baseline is green.tenancy.organizationFieldis refused with the guidance row's prescription, pinned.sys_api_key's audit / approval / automation-run rows still stampactive_organization_id— pinned end to end, with the stamp/wall divergence pin from [Decision]groupposture is an on-premise shape — should package-authored scheduled flows run undergroupwith the switch on, and which organization do their writes carry? (ruling G item 3, reopened by the maintainer) #18378 still green.objectstack migrate metarewrites or names the refusal for a declaration carried by an older artifact (ADR-0087 entry, with its own acceptance criteria).Dedup terms
organizationField·TenancyConfig·stamp-only·sys_api_key active_organization_id·authorable surface retirementFiled from the #18378 / PR #18420 work, where the key's scope-pin was the finding that blocked the PR until the design was changed to stop reading it.