Repository navigation
docs(adr-0131): amend D13's reach — the legacy-anchor retirement leaves it for the walled posture, on the 17.x line - #18646
Conversation
…es it for the walled posture Maintainer ruling, option B on #18336 (session session_01LmoCFLwGkcAGefVf7jryEV, 2026-09-16T09:54Z): #11663's design governs this leg, the work stays on the 17.x line, and ADR-0131 D13 drops `reportLegacyPlatformAdminGrant` and `resetLegacyPlatformAdminGrantReport`. D5's assignment of those symbols (and of the legacy unscoped anchor) to D13 is withdrawn for the walled posture. Two standing constraints the ruling did not touch — Choice 4A (#16682 comment 5587754690) and the maintainer's zero-config statement in the same session — narrow the retirement to the walled posture: `single` keeps its zero-config first-user promotion and its grant row until #11979 disposes of it. Closes the NULL-ownership question the drop leaves open, in the text: the `single` row still becomes Default-Organization-owned (D5's own answer, accepted 2026-09-04, untouched by the ruling), on the v18 line under C3; until C3 it keeps today's NULL organization, which D10's migration clears. The drop moves no row — the two symbols are a once-per-process deprecation pointer and its test latch; neither writes the row nor reads its organization. D14 gains one named exception for this leg, exhausted by it. D13's own retirement list is unchanged: it never named either symbol. Claude-Session: https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu Co-authored-by: Claude <noreply@anthropic.com>
维护者速读(终稿)skills 席 改了什么 — 只改 ADR-0131 一个文件(+129 / −4),把你 2026-09-16 在 #18336 上选的 B(「#11663 设计说了算,修订 D13 摘掉两个符号,本卡留在 17.x」)写进记录。五处:状态行加 为什么改 — ADR-0131 仍在 风险与代价(含回滚) — 治理面,只改文本;不动代码、不动别的 ADR、不动 #15193 的标签。卡上要求必须在文本里关掉的开口( 席位意见 — 荐合。它做的是裁决 B 要求的事,且把 B 明说的两条边界原文钉在了 ADR 里;开口按 ADR 自己的答案关掉,不需要新裁决。若你认为 你要做的(一个动作) — 认可这个写法即 Approve 本 PR(或直接人工合并);席位随后按裁定 C 落地,#18336(services 席)随之解锁。 Generated by Claude Code |
Fixes #18413
Governed surface (
docs/adr/**), one file, one amendment:docs/adr/0131-total-organization-ownership-no-null-organization-id.md(+129 / -4). Draft,skip-changeset, maintainer-merged — no seat flips this ready, queues it, or arms auto-merge (Prime Directive #14).node scripts/pm/check-governed-merges.mjs --test docs/adr/0131-…mdanswers GOVERNED, 1 of 1 path.1. The ruling and its authority
Maintainer ruling, option B on #18336, taken in session
session_01LmoCFLwGkcAGefVf7jryEVon 2026-09-16T09:54Z and recorded on that card (#issuecomment-5695555178). The option text the maintainer selected, verbatim and untranslated:Three things it decided: #11663's design governs this leg for these two symbols; the work stays on the 17.x line (not re-targeted to v18, not gated by #15193); the two symbols leave D13's retirements. Recorded under Prime Directive #13 — reversing a recorded decision needs an amended record, and this PR is that act. ADR-0131 stays Accepted; only the staging of one leg moves.
2. Reading correction — where the symbols actually were
The card states that D13's list names both symbols. Measured on
origin/main32be735e5, that is not where they are:docs/adr/docs/packages/(positive control)reportLegacyPlatformAdminGrant:362, inside D5resetLegacyPlatformAdminGrantReportD13's own retirement list (
:641–659onmain) names neither. What the record actually carries is D5's sentence 「reportLegacyPlatformAdminGrantand the legacy unscoped anchor retire with D13」 — an assignment to D13, which is what the ruling reaches. So this amendment edits D5, D14 and §7 and leaves D13's list as it stands. The substance of the card is unaffected: before, the retirement was D13's and therefore v18's; after, it is #11663's and 17.x's.premise_still_valid: true, with this correction.3. The D13 text, before and after
D5, before:
D5, after (the bolded half is what moved):
Plus: a
**Amended** (2026-09-17, …)clause on the status line; one named exception written into D14; the §7 post-17.2 audit line given the same exception; and a full## Amendment (2026-09-17, #18413)record at the end of the file carrying the authority, the two standing constraints, the closed question and the D14 reconciliation.4. How each standing constraint is honoured
Both are quoted verbatim and untranslated in the amendment. Neither was touched by the ruling, and both still bind.
Choice 4A — maintainer, 2026-09-08, #16682 comment
5587754690:Honoured: the amendment narrows the retirement to the walled posture in every place it names it — D5, D14's exception and the §7 line each say "walled". The
singlewrite, its grant row and its zero-config first-user promotion are stated as surviving until #11979 (Choice 4B) disposes of them. Nothing in the diff removes or narrows thesinglehalf.The zero-config constraint — maintainer, 2026-09-16, the same session as the ruling:
Honoured: the amendment states that
singlekeeps its zero-config first-user promotion, and it does not touch the derivation that delivers it — the unscoped-grant read at §6/§6b ofpackages/core/src/security/resolve-authz-context.ts. The amendment also records the mechanical reason the all-postures reading was never available for this leg: the deprecation pointer is already posture-keyed (postureEnforcesWall(resolveTenancyPosture())at the §6b-config arm), so undersinglethere is no pointer behaviour to retire at all.5. The open question — CLOSED in the text, not deferred
The STOP condition did not trigger. The two standing constraints do not conflict with the D13 change: the change reduces what retires, and a reduction cannot retire the
singlewrite; the zero-config channel is the unscoped read, which is not the reporter and is untouched. Closing the question needs no new maintainer decision — only two ruled texts that the option-B ruling explicitly left alone. The decision sentence, as it is written into the ADR:Why the drop moves no row — measured, not argued.
reportLegacyPlatformAdminGrant(packages/core/src/security/platform-admin.ts:351) is a once-per-processwarnnaming one holder and pointing atOS_PLATFORM_OWNER_EMAIL;resetLegacyPlatformAdminGrantReport(:371) drops that latch for tests. Neither writes the grant row, neither reads itsorganization, and neither participates in the derivation that confersPLATFORM_ADMIN— that is theunscopedUserPsIdsread atresolve-authz-context.ts:839and the check at:928, untouched by this amendment. So the 17.x retirement this amendment authorizes adds no NULL row, removes none, and re-owns none. D1 and D10 are therefore unaffected: the NULL-ownership question is not created by the drop and is not answered by it — it is answered by D5, on D5's own schedule.6. Reconciliation with D14 and with #15193
D14 「⛔ No 17.x card narrows or removes an arm, adds a name column beside an id column, or ships a half of this record」 gains exactly one named exception, written into D14 itself. Two independent reasons, either sufficient:
admin_full_accessbecomes a kernel metadata declaration; WHO holds it comes from env-configured verified emails — retiring the org-less row anchor #11663's design. Work this record no longer governs cannot be a half of it.orWhereNullarms insideapplyTenantScope— the record's own vocabulary (D13:641, D14:674, §7:836"the arms are insideapplyTenantScope… there are two"; the reads inresolve-authz-context.tsare called "NULL readings", never arms). The walled legacy-anchor read and its pointer are neither of those, add no column, and move no row.The exception is written as exhausted by that leg and those two symbols: every other retirement in D13 keeps D14's fence and stays gated on D10's zero-NULL report.
#15193 (the v18 gate, open p1) — confirmed it no longer gates #18336 under this ruling, and the amendment says so in D14's exception and in its "What the ruling decided" list. #15193's own rule binds "every ADR-0131 execution card"; the option-B ruling took this leg out of that set, and the ruling comment states it directly (「本卡留在 17.x 线,⛔ 不改挂
target:v18、⛔ 不阻塞于 #15193」). ⛔ No label or body of #15193 is touched by this PR — that is #18336's own re-pointing, out of scope here.7. Gates — derived, run, reconciled
Derived from this worktree with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(no hand-written path list; the tool took the change set three-dot against merge base32be735e5). 18 commands, every one run, exit code captured before any pipe:node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran …→18 derived, 18 run, 0 NOT-MEASURED, 0 UNRUN— "a DERIVED zero — all 18 recorded an exit code and none of them is 3".ⓘ
check:doc-formula-expressionsexited 3 on the first attempt —PREREQUISITE NOT MET, its own text: "Nothing was measured: this gate exited before running a single check". Its prescribed remedy was run (turbo run build --filter=@objectstack/formula --filter=@objectstack/lint, underscripts/pm/os-verify-lock.sh,VERDICT command-exit 0) and the gate re-run to a real exit 0. The 3 is recorded here as a non-measurement, ⛔ not as a failed gate.Repo-wide eslint — a proven narrowing, not a skip. ① The population is read from eslint's own config: every
files:entry ineslint.config.mjsnames only{ts,tsx,mts,cts,js,jsx,mjs,cjs}(includingCOMMENT_SWALLOW_FILES), andgrep -c '\.md' eslint.config.mjsreturns 0. ②pnpm exec eslint --no-inline-config --format jsonover the one changed path returns 1 result,errorCount: 0, whose single message is"File ignored because no matching configuration was supplied."— the file is outside the linted population entirely. ③ Invariance: the diff is one.mdfile and touches no eslint config and no TS/JS source, so no untouched file's verdict can move; type-aware linting does not enter into it, because the changed file is not in the population at all. Measured against final headef300b686.Changeset —
skip-changeset. Nothing indocs/adr/**is shipped by any package'sfiles[]; it is the documented fast-track surface, and the diff contains nopackages/**path.Not run here, by design: CI's own repo-wide roster.
dispatch-gatesnames 53 artifact-roster families, 11 wide-population families, 14 pending-changeset families and 1 path-scheduled CI job as outside the 18 derived commands; each is CI's run, not this PR's local debt.维护者速读(草稿)
改了什么:只改了一个文件 —— ADR-0131。把「那两个平台管理员报告符号在 v18 退役」这条安排摘掉,改成:它们按 #11663 的设计、在 17.x 线上退役,而且只限 walled(隔离墙)姿态。同时在文本里把一个悬着的问题答死:
single姿态那条授权行的组织归属不变 —— 仍然按 ADR-0131 原本的答案改成「默认组织所有」,仍然在 v18 的 C3 那张卡上做;在那之前它保持今天的 NULL,由 D10 的迁移来清。另外给 D14 加了一条具名例外,并更正了 §7 的一句话。⛔ 没动任何代码、没动任何其它 ADR。为什么改:2026-09-16 您在 #18336 上选了 B —— #11663 设计说了算,并要求修订 ADR-0131 D13。ADR-0131 今天是 Accepted 且在
main上,如果不先改它,#18336 的移除一落地,代码就和一份已接受的 ADR 直接抵触。次序是固定的:先本卡 → 再 #18336。另外您在同一会话说的「比如临时启动的开发环境,我不可能去配置啊」,加上 2026-09-08 关于 Choice 4A 的裁决(「retiring the walled write must not retire thesingleone」),这两条本次裁决一个字都没碰,所以范围被机械地收成「只限 walled」——零配置开发环境不受任何影响。风险与代价(含回滚):代价很小。改的是治理记录的措辞与分线,不改变任何运行时行为:被摘掉的两个符号一个是「每进程一次的提醒日志」、一个是「测试用的开关复位」,它们既不写那条授权行、也不读它的组织字段,所以这次修订不新增、不删除、不改写任何一行数据的归属,D1(非空约束)和 D10(零-NULL 迁移)完全不受影响。风险面只有一个:D14 原本禁止「17.x 上只发本记录的一半」,现在它多了一条例外 —— 例外写成一次性用尽(只覆盖这条腿和这两个符号),D13 其余退役仍然照旧受 D10 把关。回滚成本为零:单文件 revert 即可,没有代码、没有迁移、没有发布物。
席位意见:(留空,待维护者裁定)
你要做的:审一遍这个 PR 并手动合并(受管面按章程只能由您合)。
Acceptance notes
docs/qa/platform-checklist/areas/access-security.json:2462/:2492describe the legacy-anchor deprecation pointer as live behaviour, namingreportLegacyPlatformAdminGrant. Those two clauses go stale for walled rigs the moment platform-admin re-anchor L5 EXIT (re-file of the unreadable #13515): retire the legacy row-id grant dual read and its deprecation log — the 17.4.0 boundary is measured MET #18336 lands. Not filed: it is neither a reproducible defect, a declared-contract violation, nor a metadata-authoring trap — and it has a named taker, platform-admin re-anchor L5 EXIT (re-file of the unreadable #13515): retire the legacy row-id grant dual read and its deprecation log — the 17.4.0 boundary is measured MET #18336 itself, whose diff removes the symbol those clauses name. ⛔ Out of scope for this PR's declared file surface (one ADR).singleposture — first-user promotion becomes development-only fallback #11979, [gate] the v18 development line is not open — ADR-0131 execution cards are blocked on this card #15193 and [Design] Re-anchor platform-admin:admin_full_accessbecomes a kernel metadata declaration; WHO holds it comes from env-configured verified emails — retiring the org-less row anchor #11663 are cited, never modified.Generated by Claude Code