Repository navigation
storage.notNull has ONE adopter in the whole framework — the stamping story for required-at-storage columns never happened, and control-plane drift audits pay for it #13206
Description
Activity
os-project-manager commented
on Aug 29, 2026 CollaboratorMore actions入决策箱(domain:spec 席,
session_01KX8wnyjStaZcuMyAMNsy3N,R1)。本卡由 hotlong 亲立、正文自述「Decision needed」,却挂着pm:queue—— 派发等于让 dev 代裁契约词表方向,本席按决策通道转箱并补齐分析。取证改变了问题的形状:一句话问题
数据库里「这列不许为空」的约束该不该写回声明 —— 以及三张多租户表的 organization_id 到底要不要在库层强制非空(这决定一条脏数据是被数据库当场拒绝,还是静默落库变成别家租户看不见的孤儿行)。
前提(每条带 re-check 命令,本席实测)
storage.notNull不是没人用的词表,是 ADR-0113 裁定的列约束本体:required= 写入契约,storage.notNull= 物理列约束,两者在 ADR-0113 显式分家。
re-check:git grep -n "ADR-0113" origin/main -- packages/drivers/driver-sql/src/builtin-column-collision.ts- 活读者存在:
driver-sql/schema-drift.ts:798以它为 drift 比对基准(expectNullable = field.storage?.notNull !== true)—— cloud#1736 的 8 条 relax_not_null 发现正是这个读者在工作。 - stamp 机械真实存在:17 号 D2 conversion(
conversions/registry.ts:2056)把required: true的字段自动补storage: { notNull: true }—— 「os migrate meta stamps it」不是空话。 - 框架内手写采纳 = 1 处(plugin-sharing)——但鉴于 3,低采纳读数部分是「conversion 代劳了」而非「词表死了」。
选项 × 真实代价
选项 做什么 真实代价(客户可感知) A. 保词表 + 给点名列 stamp sys_invitation/sys_member/sys_team.organization_id 声明 storage.notNull(cloud 侧按 ADR-0057 附录定姿态后)一条没 org 的脏行会被数据库当场响亮拒绝;但若有历史空值行,迁移先要处置它们 B. 保词表,点名列不 stamp 只修卡上的知识账(词表活着,cloud 已 relax 是既成事实) 那三列永远接受 NULL —— 多租户表的 org 归属靠应用层自律,孤儿行静默可能 C. 退役词表 撤 ADR-0113 的半边 不可行级:要推翻在案 ADR、拆掉活的 drift 读者与 17 号 conversion 业务含义直译:A = 数据库替你把门;B = 把门的只有代码;C = 把门拆了。
推荐
A 方向,但分两步且第二步是 cloud 席的:① 本仓无事可做级(词表健在、机械健在)—— 本卡的框架半边其实已经闭合;② 三列的 stamp 是 cloud 侧姿态决定(org_id 可空性 = 多租户语义,ADR-0057 附录点名),裁后落 cloud 车道执行。回退:B(接受既成 relax,记录在案)。
置信缺口:历史数据里那三列有多少 NULL 行未测(决定 A 的迁移代价);ADR-0057 附录原文本席未逐字核。裁后执行段(你不用管)
裁 A ⇒ 本卡收窄为记录卡关闭 + cloud 仓立执行卡(带三列清单与 NULL 行盘点为第一步);裁 B ⇒ 关卡留档;任一裁定同笔摘
needs-user-decision。<!-- os-decision-facets -->
① 项目长远合理性:A 兑现 ADR-0113 的既定分家(declared=enforced);C 是拆在案裁决,不在桌上。
② 实际业务拉动:cloud 生产 8 条 relax 已实际发生(run 33247881206),约束已没了 —— 现在决定的是「要不要要回来」,拉动为实。
③ 防 AI 犯错:库层 NOT NULL 是最响亮的拒绝;靠应用层自律正是 AI 批量写数据时静默漏 org 的温床。
④ 创业阶段不扩散:A 零新词表零新机制(全部既有);唯一新工作是三列的姿态决定 + stamp。
推荐:A(分两步,第二步归 cloud 席)。
本分析看不见什么:三列历史 NULL 行数;ADR-0057 附录逐字;cloud 侧是否有依赖 NULL 的既有流程。
Generated by Claude Code
zhuangjianguo commented
on Aug 30, 2026 CollaboratorMore actions⚖️ RULED — 维护者,2026-08-30,第 5 场总监席决裁批 #2,verbatim「同意」
裁定:采选项 A 方向(保词表 + 给点名列 stamp),分两步且第二步归 cloud 席。
- 框架半边(objectstack)已闭合,本仓无 code 变更:实测更正已确认
storage.notNull不是死词表,是 ADR-0113 裁定的列约束本体——活读者存在(schema-drift.ts:798的 drift 基准)、stamp 机械存在(17 号 D2 conversion 自动补)。词表健在、机械健在 ⇒ 本仓侧无事可做级。 - 第二步(cloud 侧姿态决定 + stamp):
sys_invitation/sys_member/sys_team的organization_id是否库层强制非空,是 cloud 侧多租户语义决定(ADR-0057 附录点名),⚠️ 第一步必须是这三列的 NULL 行盘点(cloud 2026-08-29 已在生产 relax 8 条约束,可能有历史空行,决定迁移代价与顺序)。 - 裁据:库层 NOT NULL 是最响亮的拒绝;靠应用层自律正是 AI 批量写数据时静默漏 org 的温床;A 不加新词表新机制(全部既有),唯一新工作是三列姿态决定 + stamp。
跨仓交接(缝卡):本卡作为 objectstack 侧记录卡保留在队列,具名读者 =
repo:cloud执行席——请在 cloud 仓立执行卡(NULL 行盘点为第一步 → 按盘点结果定迁移 → stamp 三列storage.notNull),并在本卡回链。cloud 仓本会话不可达,⛔ 本席不代立 cloud 卡;回链落地后本卡按记录卡关闭。置信缺口(交 cloud 席带走):三列历史 NULL 行数未测;ADR-0057 附录原文未逐字核。
席位边界(裁不派):录裁 + 转
pm:queue+repo:cloud(缝卡,具名读者)。同笔摘needs-user-decision。裁决入本场追认摘要表。
Generated by Claude Code
- 框架半边(objectstack)已闭合,本仓无 code 变更:实测更正已确认
Cross-repo hand-off executed by the named reader (
repo:cloudexecution seat, seat post #6026, sessionsession_017Wu48ZSjk7HJjyJmGNBtUk, R35): the cloud execution card is filed — objectstack-ai/cloud#1874 — carrying the ruling verbatim, the threeorganization_idcolumns, and step 1 as the maintainer's read (the exact NULL-row count SQL for both control planes; the card sitspm:awaiting-maintaineruntil those six numbers are posted, then the stamp/backfill step is dispatched with its shape decided by them). The confidence gaps the ruling handed over (NULL-row counts unmeasured; ADR-0057 appendix not read verbatim) are recorded on that card as the dev's first reads.Per the ruling's own exit (「回链落地后本卡按记录卡关闭」), this record card closes as completed with that back-link; the framework half needs no code.
Generated by Claude Code
From cloud#1736's audit: all 8 relax_not_null findings on cloud's control DB were the same defect — columns whose DB NOT NULL predates declarations that never said storage.notNull. The plan's own suggested remedy ('ratify by declaring storage.notNull; os migrate meta stamps it') has effectively never been used: exactly one occurrence in the framework at the pin (plugin-sharing's sys-sharing-rule.object.ts). Decision needed: is storage.notNull the real vocabulary for required-at-storage? If yes, stamp the backlog where it is intended (audit names sys_invitation/sys_member/sys_team.organization_id as candidates needing a cloud-side posture decision per ADR-0057 addendum); if no, retire the attribute so plans stop suggesting a remedy nobody uses. Note: cloud applied the 8 relaxes on production 2026-08-29 (run 33247881206) — the DB constraints are gone; whatever this decides becomes declarations, not DDL archaeology.