Skip to content

docs(deployment): 按 ADR-0105 D1 三态 posture 重写 tenancy-modes 页 - #5361

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-5269-tenancy-posture-docs
Aug 5, 2026
Merged

docs(deployment): 按 ADR-0105 D1 三态 posture 重写 tenancy-modes 页#5361
os-zhuang merged 1 commit into
mainfrom
claude/issue-5269-tenancy-posture-docs

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #5269

前提复核(先于动手)

issue 正文的前提在 origin/main @ c89d18c16成立content/docs/deployment/tenancy-modes.mdx 对权威 knob OS_TENANCY_POSTURE grep 零命中,整页按 ADR-0105 D1 之前的两态世界写。原文点名的三处(L21 「Enabled by OS_MULTI_ORG_ENABLED=true」、L41 requested: boolean // OS_MULTI_ORG_ENABLED、L100/L109 的 FATAL 文案)逐条对上,行号未漂移。

核证过程中另外查出四处原文与代码不符,一并修掉(详见下方逐断言核证表):TenancyService 的字段形状早已不是 mode;降级告警是黄色不是原文写的红色;「wildcard tenant_isolation RLS is stripped」的说法在 ADR-0095 D1 之后不再准确;OS_ORG_LIMIT 计的是自己拥有的组织而非「创建过的」。

改了什么

单文件 content/docs/deployment/tenancy-modes.mdx,以 single / group / isolated 三态为主线重写,遗留布尔降为「posture 未设时才读的回落输入」:

  • 三态对照表 —— 每态的 Layer 0 墙谓词、读取范围、写入是否补 organization_id、是否需要企业版 runtime、默认组织归属、组织管理 UI。
  • posture 解析优先级表 —— posture 已设则完全不读布尔;multiisolated 的旧拼法;布尔只有在 posture 未设时才读,且「除大小写不敏感的 false 以外的任何值」都算开;非法值抛错而不回落。
  • open code, entitled activation —— 两种有墙 posture 都需要企业版 @objectstack/organizations 才能激活,org-scoping 可用 supportedPostures 进一步收窄,开核对未列出的 posture fail closed。
  • tenancy 服务快照 —— 改为 posture / requestedPosture 双事实(原文的 mode: 'single' | 'multi' 字段已不存在),并说明「墙立不起来就不算墙」。该 os:check 代码块现在从 @objectstack/spec/security 导入真实的 TenancyPosture,posture 集合一旦漂移就编译失败。
  • /auth/config 与组织创建闸门 —— tenancyPosture / multiOrgEnabled / degradedTenancy 三个 feature,以及闸门读的是生效 posture(organization/create 的闸门读的是被降级的 OS_MULTI_ORG_ENABLED,不是权威的 OS_TENANCY_POSTURE —— 只设权威 knob 的有墙部署,引导式「创建工作区」是死路 #5233 / organization/create 的闸门判「请求的 posture」还是「实际生效的 posture」?降级部署(D5)下两者分叉,闸门放行而 /auth/config 隐藏 #5261),因此降级部署也会拒绝建组织。
  • 启动闸门 —— 区分 import 阶段(OS_ALLOW_DEGRADED_TENANCY 可放行)与 mount 阶段(不可放行);FATAL 文案按 serve.ts 现文照抄;降级告警更正为黄色。
  • 成员归属一节 —— 保留 ADR-0093 的语义,措辞改成 posture;补上 defaultOrgId()任何有墙请求(含降级)下都返回 null 的理由;策略来源补齐三处(AuthPlugin 选项 / auth.membership_policy 设置 / OS_AUTH_MEMBERSHIP_POLICY)。
  • 环境变量表 —— 补 OS_TENANCY_POSTUREOS_AUTH_MEMBERSHIP_POLICY,并修正 OS_ORG_LIMIT 口径。

不碰 content/docs/references/**content/docs/releases/、任何 packages/** 源码。content/docs/deployment/environment-variables.mdx 只作参照,未编辑。

逐断言对码核证(#1085 方法论,行号均为 origin/main @ c89d18c

页面断言 代码依据
posture 是权威 knob,布尔是回落输入 packages/types/src/env.ts:145-162(posture 已设走 normalizeTenancyPosture,未设才 resolveMultiOrgEnabled() ? 'isolated' : 'single'
布尔「非 false 即开」、空串也算开 packages/types/src/env.ts:119-122 + readEnvWithDeprecation env.ts:52-86(只有 undefined 才算未设)
posture 空串/纯空白视为未设 packages/types/src/env.ts:150
multi 旧拼法 = isolated;trim + 小写 packages/spec/src/security/tenancy-posture.ts:107-112
非法值抛错不回落 packages/types/src/env.ts:152-158
三态与墙谓词 packages/spec/src/security/tenancy-posture.ts:40-55, 80-82packages/plugins/plugin-security/src/tenant-layer.ts:34-39, 99-119, 139-145
只有谓词不同、组合方式相同、无解析范围时 fail closed plugin-security/src/tenant-layer.ts:103-112
single 下平台自带 tenant RLS 被剥、应用自写的保留并 fail closed plugin-security/src/security-plugin.ts:572-575(ADR-0105 D3)
写入补 organization_id 是企业版的活、校验留在开核 packages/spec/src/security/tenancy-posture.ts:57-71.changeset/adr-0105-group-posture-entitlement.md
两种有墙 posture 都要企业版才激活 plugin-auth/src/tenancy-service.ts:196-207
supportedPostures 收窄、未声明则两种都给 packages/spec/src/security/tenancy-posture.ts:84-99plugin-auth/src/tenancy-service.ts:200-202auth-plugin.ts:478-489
TenancyService 字段形状 plugin-auth/src/tenancy-service.ts:53-98, 209-239
生效 posture 与请求 posture 可分歧;不可执行的请求解析为 single + degraded plugin-auth/src/tenancy-service.ts:219-226
/auth/config 三个 feature plugin-auth/src/auth-manager.ts:3341-3344, 3368-3383
组织创建闸门读生效 posture,single 时 403 plugin-auth/src/auth-manager.ts:1915-1937, 3249-3261
默认组织:single 归 plugin-auth,有墙归企业版 plugin-auth/src/auth-plugin.ts:807-813
组织管理 UI 由 multiOrgEnabled 决定 plugin-auth/src/auth-manager.ts:3321-3328, 3373
成员协调器:让位既有成员、只绑无歧义组织、best-effort plugin-auth/src/reconcile-membership.ts:199-254auth-plugin.ts:337-341
defaultOrgId() 在任何有墙请求下返回 null(含降级) plugin-auth/src/tenancy-service.ts:78-97, 227-238
策略三处来源、live 读取、非法值不强转 plugin-auth/src/auth-manager.ts:2694-2712auth-plugin.ts:1114-1122reconcile-membership.ts:63-71, 199-216
backfill 只在 auto 下跑,OS_SKIP_MEMBERSHIP_BACKFILL=1 退出 plugin-auth/src/reconcile-membership.ts:277-292auth-plugin.ts:852-891
FATAL 文案(import 阶段) packages/cli/src/commands/serve.ts:1842-1855
mount 阶段无条件拒绝,逃生阀不覆盖 packages/cli/src/commands/serve.ts:1876-1912
降级告警是黄色 packages/cli/src/commands/serve.ts:1860-1866chalk.yellow
已声明但装坏 vs 根本没装,两种修法 packages/cli/src/commands/serve.ts:1829-1841
OS_ALLOW_DEGRADED_TENANCY 接受 1/true/on/yes packages/types/src/env.ts:175-179
OS_ORG_LIMIT 计自己拥有的组织 plugin-auth/src/auth-manager.ts:1862-1880packages/types/src/env.ts:296-309

一处刻意收窄的措辞

environment-variables.mdx:85 写「An unrecognized value refuses to boot」。静态追踪下来这句只对了一半:非法 posture 的第一次抛错落在 serve.ts 的 AuthPlugin 大 try 里(catch 在 serve.ts:1942-1948,只打一句黄字警告就继续),真正的退出发生在 banner 阶段 serve.ts:2716 二次解析、经外层 catch serve.ts:2764-2773exit(1)——那时 runtime.start() 早已绑定端口。所以本页写的是可证的窄断言:解析抛错、os serve 报错并以非零码退出,没有替 ADR 说「fail-fast」这种代码没做到的话。顺序问题另开 #5359 记录,不在本 PR 修。

验证

  • node scripts/check-nul-bytes.mjsOK (scanned 5368 tracked text file(s) … no raw NUL bytes);另按控制字符纪律自扫 grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f]',零命中
  • node scripts/check-doc-authoring.mjs✓ 362 files clean
  • node scripts/docs-audit/check-audit-scope.mjs✓ scope is in sync … 178 hand-written doc(s)
  • node scripts/check-role-word.mjsOK (43 baselined file(s), no new occurrences)(首版用了 role: owner 被这道门拦下,已改写)
  • node scripts/check-adr-anchors.mjsOK (26 anchored file(s))
  • pnpm --filter @objectstack/spec run check:skill-examples✅ 204 prose examples type-check against @objectstack/spec,其中包含本页新块 content/docs/deployment/tenancy-modes.mdx:112
  • 反向核证(先定方向、预期变红):把该块的导入改成不存在的 TenancyPostureNOPE,同一道门变红并精确指到本页 112:15 —— error TS2724: '"@objectstack/spec/security"' has no exported member named 'TenancyPostureNOPE'。证明这个 os:check 块是真的在对 spec 编译,而不是空过。已还原
  • pnpm --filter @objectstack/spec run check:docs✅ 239 generated files in sync with packages/spec(顺带产生的 packages/spec/authorable-surface.base.json 改动已还原,未提交)
  • MDX 用仓库自带的 @mdx-js/mdx@3.1.1 单文件编译通过(本页与参照页均 OK)

Changeset

加了空 frontmatter changeset(.changeset/tenancy-modes-doc-posture-rewrite.md):纯文档改动,不改任何包的行为,不该触发版本号;空 frontmatter 正是仓库认可的「本 PR releases nothing」声明,Check Changeset 门只数本 PR 新增的 .changeset/*.md,因此照样通过。

顺带记录的框外发现(未在本 PR 修)

🤖 Generated with Claude Code

https://claude.ai/code/session_01FTszibd6C8sUCCZnM4VcrL


Generated by Claude Code

整页此前按 ADR-0105 D1 之前的世界写:两态 tenancy mode、`OS_MULTI_ORG_ENABLED`
当开关、`TenancyService.mode`、只提 `isolated` 的降级 FATAL 文案;对权威 knob
`OS_TENANCY_POSTURE` 全页 grep 零命中。

重写以 `single` / `group` / `isolated` 三态为主线,遗留布尔降为「posture 未设时
才读的回落输入」,并逐条对码核证:

- posture 解析优先级表(posture 已设则完全不读布尔;`multi` 别名;非法值抛错不回落)
- 两种有墙 posture 都需要企业版 `@objectstack/organizations` 才能激活,也都会降级
- `tenancy` 服务快照改为 `posture` / `requestedPosture` 双事实,`os:check` 块从
  `@objectstack/spec/security` 导入真实的 `TenancyPosture`,漂移即编译失败
- `/auth/config` 的 `tenancyPosture` / `multiOrgEnabled` / `degradedTenancy`,
  以及 `organization/create` 闸门读的是**生效** posture(#5233 / #5261)
- 启动闸门区分 import 阶段(可被 `OS_ALLOW_DEGRADED_TENANCY` 放行)与 mount 阶段
  (不可放行),降级告警是黄色而非原文所写的红色
- 环境变量表补 `OS_TENANCY_POSTURE` / `OS_AUTH_MEMBERSHIP_POLICY`,并修正
  `OS_ORG_LIMIT` 的口径(计的是自己拥有的组织,被邀请加入的不计)

纯文档,不改任何 `packages/**` 源码;changeset 空 frontmatter,releases nothing。

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

vercel Bot commented Aug 5, 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 5, 2026 12:44am

Request Review

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tooling labels Aug 5, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review August 5, 2026 00:51
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 5, 2026
Merged via the queue into main with commit 23e9c90 Aug 5, 2026
20 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-5269-tenancy-posture-docs branch August 5, 2026 01:02
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 tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs(tenancy-modes): 整页仍教被降级的 OS_MULTI_ORG_ENABLED,对权威 OS_TENANCY_POSTURE 零提及 —— #5233 那句过期注释的文档版

2 participants