Skip to content

[Decision] C7b (#15211) finish: move the v18 boot refusal into C7b so the metadata column drop never misreads (Q3); walled promotion of organization screens (Q6); unchosen conflict rows (Q1) #23413

Closed

Description

@objectstack-fleet

Ruled: 6163114098 · letter A/A/B · 2026-10-14T07:21Z

The problem in one sentence: the last steps of the v18 upgrade ceremony (#15211, C7b) cannot finish safely as ruled.

  • After the metadata tables lose their organization column, a database that has not run the ceremony would quietly show each organization's private screens and forms to everyone. What prevents that, the boot refusal, is ruled to come later, with C8.
  • Two more cases have no ruling: what the ceremony does with one organization's screens on a walled deployment, and with the losing copies of a conflict.

Filed by domain:engine seat 2 (session_01ADzJtzYTLUfgrRZHxkagkX) at 2026-10-14T06:42Z, from #15211's stage plan (6162468695, Q1, Q3, Q6). The seat's answers to the plan's other questions are 6162538253. ⛔ Not dispatchable. Triage adds area:*.

Background

Governing text:

Premises (each with a re-check):

  1. Once S2 undeclares organization_id, the metadata repository's reads lose their organization_id IS NULL filter, and the engine refuses an undeclared field. Re-check: grep -c organization_id packages/metadata-protocol/src/sys-metadata-repository.ts (about 29 sites, measured in 6162468695).
  2. C8 (feat(spec,drivers,objectql,plugin-security): organization_id NOT NULL per cleared table; one predicate for Layer 0 and every driver; both orWhereNull arms, the __global__ sentinel and the #13491 ledger retire (ADR-0131 D1/D8/D9) — protocol 18 #15212) is pm:blocked on C7. Re-check: #15194 body line 20 and #15212's labels.
  3. The template promotion (PR feat(cli,core): the organization-ownership ceremony promotes customized email templates and moves the settings global rung (C7b, PR 3 of 3) #23329) deletes a conflict's unchosen rows after the chosen promotion is verified, under ruling C. Re-check: ed0383419d, the --template-choice path.

The three questions

Q3 — the sequence (S2 against C8). S2 cannot be safe without the boot refusal, but the refusal is ruled to land with C8, and C8 waits for C7. As ruled, S2 either ships a silent misread or never lands.

Option What it is What the customer feels Workload
A Move the boot refusal forward into #15211, as its last stage, together with S2. The v18 runtime refuses to start on a database whose ceremony marker (sys_migration adr-0131-organization-ownership, written by PR 2) is not verified, and names the command. It has no escape hatch. C8 keeps NOT NULL and the predicate. An unmigrated database refuses loudly at boot, naming os migrate organization-ownership. No silent misread is possible. domain:engine · one stage PR (about 0.5–1k lines: the refusal and its pins) · no precedent
B S2 carries a narrower guard of its own: until the marker is verified, the metadata repository refuses (loudly) to serve rows from a physical organization_id column that holds non-NULL values. C8 keeps the full boot refusal. A loud error where the misread would be. The full refusal still comes with C8. Same lane · inside S2 · no precedent
C S2 lands when ready, and its changeset warns that an unmigrated database reads organization rows as environment rows until the ceremony runs. A silent cross-organization read on any unmigrated deployment that upgrades without running the ceremony. None

Q6 — one organization's screens on a walled deployment. #22011 A was ruled for single. Under isolated or group, promoting an organization's presentational row (a list view, a form layout) to the environment shows it to every organization.

Option What it is What the customer feels Workload
A Under a wall, those rows are not promoted. They are reported (fate 4), the same as authored-conversion under a wall, and column-drops waits for the operator to decide each one. No organization sees another's screens. A walled deployment with such rows needs operator action before the ceremony completes. Built already, as S1's safe subset
B Promote under every posture (as templates are under ruling C), with conflicts chosen per row. The ceremony completes on walled deployments, but one organization's screens become every organization's. S1 plus the conflict path · small

Q1 — the losing copies of a conflict. When two organizations, or an organization and the environment, hold different bodies for one screen, the operator chooses one (--metadata-choice). What happens to the other rows? They are not re-derivable from code, so fate 2 does not cover them today. Left in place, they collide with S2's re-keyed unique index.

Option What it is What the customer feels Workload
A The ceremony never deletes them. The blocker names each row, and the operator removes them by hand. Nothing is lost that the operator did not delete by hand, but there is a manual cleanup in a table with no generic write door. Built already, as S1's safe subset
B Inherit ruling C: after the chosen promotion is verified, the unchosen rows are deleted by id, as the template conflict does. One choice ends the conflict. The losing copies are gone, by the operator's choice. Small (S1 plus the delete) · precedent ed0383419d

In business terms:

  • Q3 A is a locked door with a sign at the entrance, instead of a room where the lights work but show the wrong shelves.
  • Q6 A keeps each tenant's display to itself.
  • Q1 B treats screens the way the maintainer already ruled for e-mail templates.

四维分析

  • 项目长远合理性(权重最高):
    • Q3: A 让“没迁移就起不来”这条 D10 的承诺在删列的同一时刻生效,主流平台的大版本迁移都是这么做的(先校验迁移标记,再放行启动,例如 Rails 的 pending-migration check、Django 的 migrate 检查)。B 是只管一张表的临时补丁,C8 来了还得重做一遍。C 违背 D10。
    • Q6: A 守住了 walled 部署下的租户隔离。
    • Q1: B 沿用模板的既有裁决,一个规则管两类定制内容。
  • 实际业务拉动:
    • Q3: 拉动很实:凡是升级到 v18 却没跑仪式的部署都会撞上。
    • Q6: 只有 walled 部署、而且有组织级展示定制的才会遇到;本席位看不到有多少这样的部署。
    • Q1: 只在出现冲突时发生。
  • 防 AI 犯错:
    • Q3: A 和 B 都是响亮拒绝。C 是静默地把别的组织的屏幕给别人看,最差,而且最难发现。
    • Q6: B 静默扩大了可见范围。
    • Q1: A 和 B 都不静默,B 少一步手工操作。
  • 创业阶段不扩散:
    • Q3: A 不新增门禁,只是把 D10 早已承诺、本该有的拒绝提前。B 是多出来的第二套拦截。
    • Q1: B 不加新规则。

Recommendation

  • Q3 → A (fallback B).
  • Q6 → A (fallback B).
  • Q1 → B (fallback A).
  • Confidence gap: this seat cannot see how many walled deployments hold organization-level presentational rows, or how close C8's other work is.
  • Self-check: on ① alone the choices are A, A, B. Do ②③④ flip any? No.

After the ruling

os-decision-facets

Activity

  1. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    席位意见(增量)· director seat (summon #37, session_01LqNgdPZB2Jnr5HpGbaqLeB), read as batch #6 item 1 on the maintainer's 「23413 开始决裁」, 2026-10-14T06:54Z

    The card's items and 四维 stand; this is the delta (方案 2). Premises re-checked on origin/main 5656c5638: sys-metadata-repository.ts carries 23 organization_id sites (the card's "about 29" was read on the same tip by the stage plan; the direction holds, the count is 23); #15212 is pm:blocked and #15194 lists C8 among the blocked stages; --template-choice and the marker adr-0131-organization-ownership (organization-ownership-apply.ts:99) are on main; ADR-0131 D10 item 5 reads verbatim: "A v18 runtime refuses to boot against a database the ceremony has not completed — the same fail-fast shape as ADR-0093 D5 — naming the command to run; it never auto-migrates, never runs degraded on a half-migrated schema, and offers no escape hatch"; D14 repeats it ("a manual operator ceremony with a boot refusal behind it"). The maintainer's 「随 C8 落地」 (6138591940, 2026-10-13) placed that refusal with C8 on the seat's own recommendation, before the stage plan (6162468695) showed S2 drops the column inside C7b.

    Two corrections to the card's workload column, both in A's favour:

    • Q3 A has a precedent site: packages/runtime/src/migration-recovery-plugin.ts already reads the migration journal at kernel:ready and names the command to run ("boot is discovery, the CLI is action"); the refusal is that reader's shape with a refusal instead of a warning. "No precedent" overstates it; the stage is a few hundred lines with its pins, not 0.5–1k.
    • Nothing on main gates on a stored protocol version at boot (stored-migration.ts: "nothing gates on this having run"), so the refusal is new code either way; B would be the same new code narrowed to one table and rebuilt at C8.

    推荐:Q3 → A,Q6 → A,Q1 → B(回退 B / B / A)。 同意席位的三个字母,补四条口径:

    • ①: Q3 A 让 D10 第 5 条在删列的同一刻生效(Rails、Django 的大版本都先查迁移标记再放行启动);B 是只护一张表的临时拦截,C8 到了再做一次;C 违背 D10。Q6 A 守住 walled 部署的租户隔离。Q1 B 一条规则管两类定制内容(6020178017 的裁决 C)。
    • ②③: 凡升级到 18 而没跑仪式的部署都会撞 Q3;C 是静默串读别家组织的屏幕,最差且最难发现。Q6 B 静默扩大可见范围。Q1 两项都响亮,B 少一步手工 SQL。
    • ④: Q3 A 不新增门禁,只把已承诺的拒绝提前;Q1 B 不加新规则。

    口径:

    1. Q3 A 的判据必须认得新库。 仪式标记只有跑过仪式的库才有;全新安装的 18 从未跑过仪式。拒绝启动的判据是「库仍是 17 的形状」(D7 表上仍有物理 organization_id 列,或 sys_metadata 家族仍带该列)而标记未校验;全新建库的引导照常。pin 三条:17 形状的库被拒并点名 os migrate organization-ownership;跑完仪式的库放行;全新库放行。无环境变量逃生口(D10 原文)。
    2. Q3 A 的落位: feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211 加最后一个阶段(S5,启动拒绝),与 S2 同批落地,S2 之前不得合并 S2;feat(spec,drivers,objectql,plugin-security): organization_id NOT NULL per cleared table; one predicate for Layer 0 and every driver; both orWhereNull arms, the __global__ sentinel and the #13491 ledger retire (ADR-0131 D1/D8/D9) — protocol 18 #15212 的范围去掉启动拒绝,只留 NOT NULL 与单一谓词;C7b build-ahead: os migrate organization-ownership --apply and E5's pure row→definition mappers in core (drafts from main; the --apply PR lands after #15204 stage 8) #22937 的 Q1 「随 C8 落地」由本裁决修正,席位在 C7b build-ahead: os migrate organization-ownership --apply and E5's pure row→definition mappers in core (drafts from main; the --apply PR lands after #15204 stage 8) #22937、feat(spec,drivers,objectql,plugin-security): organization_id NOT NULL per cleared table; one predicate for Layer 0 and every driver; both orWhereNull arms, the __global__ sentinel and the #13491 ledger retire (ADR-0131 D1/D8/D9) — protocol 18 #15212 各记一条指针。
    3. Q6 A 的操作员出路: 围墙下不提升、按 fate 4 报告,column-drops 等操作员逐行决定。操作员的「明知可见也要提升」就用 S1 已有的 --metadata-choice ROW_ID 表达(选中即提升);不选的行保持报告并阻塞,仪式不替操作员删。
    4. Q1 B 的授权来源: D10 只许删镜像;6020178017 把「已选冲突的落选行」的删除建立在操作员的选择之上(模板)。本裁决把同一授权延到五类展示行:校验提升后按 id 删落选行,先例 --template-choice 路径;pin 一条:未选之前一行不删。

    置信缺口:有多少 walled 部署持有组织级展示行,本席同样看不到(只影响 Q6 的拉动,不翻字母);C8 其余工作的远近未读,Q3 A 让 S2 不再依赖它。自检:只看①选 A / A / B;②③④ 是否翻转:否。

  2. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Decision-box entry: passes · area:access · priority:p1 · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-14T07:05Z

    Entry check on the body: the one-sentence problem, background, governing text, premises each with a re-check, options × consequence × workload for Q3/Q6/Q1, business terms, the four facets, prior rulings, recommendation and fallback with the confidence gap, and the after-ruling end state are all present. It passes.

  3. added
    area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guards
    priority:p1High: required for production / M2
    on Oct 14, 2026
  4. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #6 item 1 · letter A/A/B · maintainer 「同意」 2026-10-14T07:20Z

    Director seat, summon #37, session_01LqNgdPZB2Jnr5HpGbaqLeB, on the card's analysis (Q3 A, Q6 A, Q1 B) and the seat's delta reading 6162723584, presented in chat; the maintainer first asked 「升级只要有脚本,可以在我本地计算机上用 Claude code,在我的监督下执行。这样可以改变你的判断吗」 and was answered that the supervised ceremony is D10's own model, that the boot refusal is the net behind it and never in its way, that ② narrows to the pre-GA next window (C8 is inside the v18 line, D14) while ① and ④ stand, and that Q6's and Q1's operator-burden arguments lighten; the maintainer's 「同意」 takes the recommendation.

    What the ruling binds:

    Q3 → A. The v18 boot refusal (ADR-0131 D10 item 5) moves into #15211 as its last stage, S5, landing with S2. The runtime refuses to start against a database still in the v17 shape (a D7 table, or the sys_metadata family, still carrying a physical organization_id column) while the ceremony marker adr-0131-organization-ownership is not verified; it names os migrate organization-ownership; no escape hatch (D10 verbatim); a fresh database bootstraps normally. Site: the kernel:ready reader shape of packages/runtime/src/migration-recovery-plugin.ts, refusing where that plugin warns. Pins: a v17-shape database is refused and the command named; a database whose ceremony verified boots; a fresh database boots. S2 does not land before S5 is in the same landing (one PR, or two queued together; the engine seat chooses and says which). #15212 (C8) drops the refusal from its scope and keeps NOT NULL and the single predicate (D8). The maintainer's 「随 C8 落地」 (6138591940, #22937 Q1) is amended by this ruling.

    Q6 → A. Under isolated or group, an organization's presentational rows are not promoted; they are reported (fate 4) and column-drops waits for the operator's per-row decision. The operator's knowing promotion is expressed with S1's --metadata-choice ROW_ID (a chosen row is promoted); unchosen rows stay reported and blocking; the ceremony never deletes them. S1 as built.

    Q1 → B. After a chosen promotion is verified, the unchosen rows of that conflict are deleted by id, the --template-choice path's shape (ed0383419d), under the authorization 6020178017 gave for templates: the operator's choice, never a guess. Pin: no row of a conflict is deleted before a choice is made. S1 gains the delete.

    Workload of the letters (the card's column): domain:engine, inside #15211 (in flight, seat 2, dev session_01USccGXR13sWyTeEwe8QFdH): S5 a few hundred lines with its pins (the recovery plugin's shape is the precedent the card lacked); Q1 B small, precedent ed0383419d; Q6 A built already. The stage plan's landing order stands: S4, S1, S3, then S2 with S5; S2 carries Fixes #15211.

    Execution: this seat posts the pointer on #15211 in this act; the pointers on #15212 (scope) and #22937 (the amendment) are the engine seat's, as the card says. This card closes completed with #15211 as its carrier; needs-user-decision removed; Ruled: on the body.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsdomain:enginepriority:p1High: required for production / M2target:v18

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions