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
{{ message }}
Repository navigation
ADR-0105 D13's "scoping field" has no metadata home — the 0105↔0117 linkage gap #4611
Found while scoping the D13 promotion tool (commercial side, cloud#874). This is a spec-level gap in what ADR-0105 D13 presumes, and its fix already exists as a Proposed ADR — the decision needed is which side moves.
The gap
ADR-0105 D13 prescribes the promotion tool's third step as: "backfill organization_id on scoped business data from the subtree's scoping field" — which presumes each scoped object declares which field carries BU ownership. No such declaration exists:
ownership on the object schema is 'user' | 'org' | 'none' (packages/spec/src/data/object.zod.ts:818) — no business-unit tier;
depth scopes (unit / unit_and_below) compile to owner_id IN (…) sets, not to a BU column (IHierarchyScopeResolver returns owner ids);
owning_business_unit_id appears nowhere in code — only in ADR-0117's text;
Appendix A of ADR-0105 confirms the current shape is app-level convention only: "business objects carry a plant reference."
The consequence
The D13 tool cannot discover which rows belong to a promoted subtree. It must take an explicit per-object { object: field } map from the operator — fail-closed and safe (auto-guessing "any lookup → sys_business_unit" would conflate reference semantics with ownership semantics and silently move rows behind the wrong wall). But the promise in D13's text is then not machine-checkable: an object the operator forgets to list silently stays behind in the source org, and the tool's dry-run candidate report is advice, not semantics.
The fix already has a name
ADR-0117 (Proposed, 2026-07-31) introduces exactly the missing declaration: ownership: 'business_unit' + the owning_business_unit_id stamp, with D3's invariant record.organization_id == BU(owning_business_unit_id).organization_id — which is precisely the equation D13's backfill establishes. With 0117 landed, promotion gains a checkable postcondition: no row whose owning BU lies in the promoted subtree remains in the source org.
Decision needed (either/or)
Accelerate ADR-0117 review/landing. The D13 tool then defaults its scoped-object map from ownership metadata; the explicit map becomes an override. Recommended — it is what makes promotion verifiable rather than merely configurable.
Amend ADR-0105 D13's text to state the scoping field is deployment-supplied, making the explicit per-object map the contract rather than a workaround.
The D13 tool ships either way with the explicit-map interface (it stays correct as an override under option 1 — no rework).
AssertionError: ADR-0117 D1: business_unit tier must NOT get owner_id:
expected { type: 'lookup', …(6) } to be undefined
+ Received: { type: "lookup", reference: "sys_user", label: "Owner",
system: true, readonly: false, … }
Test Files 1 failed | 119 passed (120)
Tests 1 failed | 1923 passed (1924)
即:owner_id 被注入、owning_business_unit_id 不存在。
这不是"惰性新增",而是把今天的响亮拒绝换成了明天的静默错误:作者现在写 ownership: 'business_unit' 会吃到 Zod 报错(枚举列出合法值);加了枚举值之后,他会得到一个"看起来被接受、语义完全相反"的对象。这正是 ADR-0049(Spec must not declare security properties the runtime does not enforce)要消灭的形态,也是"让 AI 写的元数据难以出错"这条轴上最差的一档。
Activity
os-zhuang commentedon Aug 5, 2026
维护者裁定(2026-08-05,经 spec 车道 PM
session_018fxLGQdatPbBUvCgiVxg6D誊写):选 1 —— 加速 ADR-0117 评审与落地。ownership: 'business_unit'+owning_business_unit_id+ D3 不变量(record.organization_id == BU(owning_business_unit_id).organization_id)进入协议;promotion 由此获得可校验的后置条件。ownership元数据推导 —— 无返工。转入队列。派发时 dev 须先核 ADR-0117 当前状态(Proposed):工作面 = ADR-0117 定稿文本(维护者合并即接受)+
object.zod.tsownership 枚举扩展及配套;若定稿评审中出现形状分歧,按惯例回报 needs_decision 而非自行定夺。Generated by Claude Code
os-zhuang commentedon Aug 5, 2026
PM 认领(spec 车道 PM,
session_018fxLGQdatPbBUvCgiVxg6D,2026-08-05)claude/issue-4611-ownership-business-unit;工作树:../objectstack-4611-ownership(基于最新origin/main);域:domain:specpackages/spec/src/data/object.zod.ts的ownership枚举扩展('business_unit')+owning_business_unit_id配套 + 测试 + 生成物(走生成器){节点id.字段}输出引用、assignment 无assignments包裹、legacy loop、字符串filter、brace-CEL 出边条件 #5500(flow.test.ts)、ui/app.zod.ts导航项:4 条expanded别名在另外 8 个变体上把作者指向该变体同样拒绝的键(二次拒绝) #5555(ui/app.zod.ts)、HookContext.input的契约注释声明批量写携带input.ast,引擎从不设置它(AST 只在 opCtx 上);同一张表也未描述 #5038 后 after 事件的按行形状 #5273(hook.zod.ts);Generated by Claude Code
os-zhuang commentedon Aug 5, 2026
os-dev 复核结论:前提成立,但按"仅 spec 半边"实现会产出一个"声明即错"的枚举值 —— 回报 needs_decision,未提 PR。
一、前提复核(对
origin/main@ 23dba62)docs/adr/0117-owning-business-unit-record-stamp.md:3——状态: Proposed(提案,待评审),2026-07-31ownership为'user'|'org'|'none'packages/spec/src/data/object.zod.ts:1152(issue 记的:818已失效)owning_business_unit_id全仓无代码.ts命中packages/spec/src/contracts/sharing-service.ts:415resolveOwnerIds(...);plugin-sharing/src/sharing-service.ts:61const OWNER_FIELD = 'owner_id'硬编码二、阻断发现:注入判定是排除式,新增枚举值会被当成
userpackages/objectql/src/registry.ts:359-363:这是黑名单语义:只有
org/none被排除。因此只要把'business_unit'加进 spec 枚举、而不动 registry,ownership: 'business_unit'就会照常注入owner_id—— 与 ADR-0117 D1 表格(business_unit档owner_id❌、owning_business_unit_id✅)恰好相反。已用一次性探针实测(跑完即删,未入库),断言按 D1 写:
即:
owner_id被注入、owning_business_unit_id不存在。这不是"惰性新增",而是把今天的响亮拒绝换成了明天的静默错误:作者现在写
ownership: 'business_unit'会吃到 Zod 报错(枚举列出合法值);加了枚举值之后,他会得到一个"看起来被接受、语义完全相反"的对象。这正是 ADR-0049(Spec must not declare security properties the runtime does not enforce)要消灭的形态,也是"让 AI 写的元数据难以出错"这条轴上最差的一档。派发单同时要求"实现 spec 半边的枚举扩展"与"不要写引擎代码、把 runtime 部分留作后续",在当前代码形态下这两条互相不可同时满足 —— 故上报而非自裁。
附带发现:枚举值的消费半径超出
packages/specpackages/cli/test/commands.test.ts:83——expect(new Set(tokens)).toEqual(new Set(['user','org','none'])),os explain object的目录精度钉子(explain:os explain objectdocumentsownershipas "own" | "extend" — real values are user | org | none #3244);packages/spec/src/data/object.test.ts:857—— 逐值接受性断言。任何枚举扩展都必须连带改这两处,否则 CI 在 cli 包红(与 PR #5046 "按规则消费半径而非按改动包扫 fixture" 同型)。
另:
owning_business_unit_id的 spec 侧落点是有先例的packages/spec/src/system/constants/system-names.ts:166的SystemFieldName是名字登记表而非注入集合,且其约定明确要求"每一条都记录 open-core 是否真的注入",已有TENANT_ID/USER_ID/DELETED_AT三条"不注入"先例。因此把OWNING_BUSINESS_UNIT_ID: 'owning_business_unit_id'登记为"ADR-0117 预留、open-core 暂不注入"是一个诚实且被闸门覆盖的纯 spec 交付物(packages/objectql/src/system-managed-fields-conformance.test.ts校验"拒收名单 == 实际注入 ∪ 文档化预留")—— 与枚举值不同,它不构成 author-facing 的行为承诺。三、待裁定(两问,均为契约形状,不自裁)
Q1:
ownership: 'business_unit'这一档,本 PR 的落地边界取哪个?wantOwner由黑名单改白名单(ownership === undefined || ownership === 'user')——owner_id正确不注入;但 BU 列仍不存在,该档运行时与'none'无法区分。半真。owning_business_unit_id列(比照organization_id,可空未盖章)—— D1 结构完整;但列恒为 NULL,盖章(D2)、D3 不变量、D4 守卫仍缺,且触碰派发单划出的引擎代码。SystemFieldName.OWNING_BUSINESS_UNIT_ID预留登记;枚举值与其注入实现同 PR 落地。建议 D。 长期健全性:ADR-0049 的存在本身就是这个仓库为"声明先行、执行后补"付过的学费,把 author-facing 的枚举档位与它的执行拆到两个 PR 是在小尺度上复刻同一个反模式;#4611 真正的缺口是决策缺口(0105↔0117 没接上),ADR 定稿 + 名字预留就已经把它补上了。防错性:D 保留了今天那个响亮的 Zod 拒绝,直到这一档整体可用为止 —— B/C 都会让作者拿到一个"写了但不完全生效"的档位,而这正是 AI 生成的元数据最容易藏错的地方。若维护者希望协议 token 立刻存在,则取 C 而非 B(B 的"与 none 无法区分"是纯负债)。
Q2:ADR-0117 带着 4 条未决问题,能否直接定稿为 Accepted?
维护者 2026-08-05 的裁定回答了 ADR 自列未决问题中的第 2 条(这一档值得新增)。其余仍悬空,而合并即接受会一并背书:
pinned(未决问题 3):ADR 自陈平台既有对象以 CRM 形态居多,默认pinned与其直觉相反;allowTransfervs 新增allowChangeOwningUnit;resolveOwnerIds→resolveScope),派发单已将其排除在本 PR 外,但"接受 ADR"在文本上等于批准该变更方向。可选路径:(a) 维护者逐条裁定后全文 Accepted;(b) 定稿为"Accepted(限 D1/D3)",其余决策显式保留 Proposed 并留在未决清单 —— 与仓库既有的分级状态写法同型(如 ADR-0022 / ADR-0025 / ADR-0038 都在 Status 行标注了"部分实现"的范围)。建议 (b):它精确对应维护者实际裁定的范围,不требует为 D5/D2/D8/D4 现在就给出答案,也不会让一份"4/5 未决"的文档挂上 Accepted 的名义。
未提 PR;工作树已拆除。裁定后可直接复用本复核结论续做。
Generated by Claude Code
os-zhuang commentedon Aug 5, 2026
勘误(承上条 os-dev 复核结论):Q2 建议 (b) 一段中 "不требует" 系笔误,应为 "不要求" —— 完整句为:"它精确对应维护者实际裁定的范围,不要求为 D5/D2/D8/D4 现在就给出答案,也不会让一份 '4/5 未决' 的文档挂上 Accepted 的名义。"结论与选项不变。
Generated by Claude Code
os-zhuang commentedon Aug 5, 2026
PM 裁决(step 8 可决类,维护者否决窗口开放)(spec 车道 PM,
session_018fxLGQdatPbBUvCgiVxg6D,2026-08-05):dev 的 needs_decision 复审通过,Q1 取 D,Q2 取 (b),已回派同一认领继续交付。business_unit注入owner_id,与 ADR-0117 D1 相反,响亮拒绝退化为静默错误);C 触packages/objectql/src/registry.ts(engine-core 车道文件面),须契约先行拆分。均属既有规范已定 + 排序问题,不上升。SystemFieldName.OWNING_BUSINESS_UNIT_ID注册 documented-reserved(conformance 门禁看守);③ 枚举不动,加 pin 钉住当前拒绝行为并指向实施链;④ 立 spec+engine 双子单实施链(Blocked-by:本轮 ADR 接受 PR,engine 半边domain:engine-core)。Generated by Claude Code
docs(adr): ADR-0117 落地状态表补上后续实施链单号 (#4611)
os-zhuang commentedon Aug 5, 2026
验收通过(spec 车道 PM,
session_018fxLGQdatPbBUvCgiVxg6D,2026-08-05)—— PR #5675,按 D+(b) 裁决交付。Accepted (D1/D3 scoped)(限定式 Status 沿 ADR-0022/0025/0038 先例;四项遗留显式标注不随合并通过,D6 点名除外);OWNING_BUSINESS_UNIT_ID进名字登记处(documented-reserved,conformance 门先证红后归类);公开表单面预收该名(fail-closed 加分项,PM 认可);枚举不动 + 既有拒绝 pin(诚实标注非回归证明型)。落地方式:本 PR 的合并即 ADR-0117 scoped 接受——这是维护者行为,故转 ready 后合并权留给维护者,不由 PM 入队。
Generated by Claude Code
feat(spec): ADR-0117 scoped 接受 —— owning_business_unit_id 规范名进入登记处 (o…
fix(objectql): wantOwner becomes an allow-list; inject owning_busines…
feat(spec): extend the ownership enum with ADR-0117 D1's `business_un…
test(spec): the first system/ file group's test titles state each cit…