Repository navigation
docs(adr): ADR-0123 D2 records the two inserts its refusal now answers — the union-scope insert and the crossing operator's - #24918
Conversation
…s — the union-scope insert and the crossing operator's ADR-0123 D2's scope paragraph and its "What does not change" line were narrower than the runtime after PR #24819 (8a058d8) and PR #24868 (98c3d00). A dated amendment in the status block names both arms and their reasons (ADR-0105 D5; ADR-0095 D3 with ADR-0131 D9); the scope paragraph keeps its text with a dated pointer, and the "Platform operators" entry is struck and corrected in place. Claude-Session: https://claude.ai/code/session_01M82feuetLzrCiBz41BJb7L Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Face: rules ( ① Derived judgmentsThe accept set here is the ADR's claims about the runtime. Each sentence of the diff, judged against the cited code on Status-block amendment, lead.
Arm 1, the union-scope insert. Arm 2, the crossing platform operator. Reach paragraph. Scope-paragraph pointer. What does not change. No sentence says more than the code does. The one that says less is 20, covered by its governing paragraph. Instrument, under Prime Directive 13. An amendment note, not a superseding ADR, is the right instrument. The decision's direction — D2 "tenant-scoped writes are refused loudly", the TL;DR's "no silent NULL stamping, anywhere ... no layer gets an exemption", D3 — is unchanged, and the two merged PRs implement it more completely rather than reversing it; what was wrong was the scope paragraph's stated reach and the Consequences summary. Prime Directive 13 names "an amended status line on the old one" as the lighter form, and this PR's dated amendment sits directly under the Status line in the form ADR-0047 took at ② Semver levelRIGHT. The diff is one file under ③ Boundary flags
Check-runs on the head, read at 2026-10-21T00:44Z: 45 runs, every one completed — 32 success, 13 skipped, 0 failing. Required contexts — Implemented-by: VERDICT: PASS Generated by Claude Code |
维护者速读改了什么:只改了一个文件 ADR-0123(「已登录但没有当前组织」的会话语义),共三处,都标注日期 2026-10-20:
为什么改:两个已经合并的修复让运行时比 ADR 原文写的拒得更多:
这两种写入以前本来就会失败,只是返回的是看不出原因的 500。ADR 原文还写着「平台运维人员不受影响」,已经不准确。第一指令 13 要求 ADR 如实反映已落地的行为,否则后来的人和 AI 会照着错误的描述写代码。 风险与代价(含回滚):纯文档,一个文件 +9/−2,不发包、不改运行时、没有 changeset。回滚就是 revert 这一个提交。 席位意见:建议批准。达档契约复核(评论 6305136018)把修订说明的每一句和 你要做的:在 PR #24918 上点 Approve,席位随后落地。 席位核对ACCEPT ·
Generated by Claude Code |
Fixes #24823
Clause-②: no
ADR-0123 D2's text was narrower than the runtime after two merged changes. PR #24819 (
8a058d85a) made the D2 refusal answer a union-scope insert from a session with no active organization. PR #24868 (98c3d00447) made it answer a crossing platform operator's insert from such a session. This PR records both in a dated amendment on the ADR. It is docs only: one file, no package touched, no code, no test.What changed:
docs/adr/0123-no-active-organization-session-semantics.mdonly (+9 / −2)Amendment (2026-10-20)blockquote under the**Status**:line, in the shape PR docs(adr): ADR-0047 records the 18.0 retirement of filterableFields — no replacement key, no rewrite #24756 gave ADR-0047 (795ff708d): a bold lead with its provenance in parentheses, then the body. It records:403 PERMISSION_DENIED, naming the missing active organization, D4), thrown from one place, anchored aspackages/plugins/plugin-security/src/security-plugin.ts#refuseNoActiveOrganization;500 ERR_SYSTEM_WRITE_ORGANIZATION_REQUIRED. Only the answer moved;beforeInsertchain. Reads, updates of existing rows, deletes, inserts from a session with an active organization, and system contexts are unchanged.No other ADR text moves. The
**Status**:line, the TL;DR, D2's bullets, D3, D4 and the "What changes" paragraph are untouched.Before / after
Scope paragraph, last sentence. Before (
origin/maina8b44d407, line 60):After (line 67): the same sentence, then:
What does not change. Before (line 78):
Reads. System contexts. Platform operators. Single-posture deployments …After (line 85):
Reads. System contexts. ~~Platform operators.~~ Platform operators' reads, their updates of existing rows, and their inserts from a session with an active organization. *(Corrected by the 2026-10-20 amendment — …; see the status block above.)* Single-posture deployments …Rendered locally with
marked16.4.2 (GFM):Platform operators.renders inside adelelement;A blank line follows the blockquote, so the
**Deciders**/**Builds on**/**Consumers**/**Surfaced by**lines stay one paragraph of their own and are not folded into the quote by lazy continuation. One visible side effect: the**Status**:line now renders as its own paragraph, where before it ran into the Deciders paragraph.Premise readings (the dispatch's mechanism hypotheses H1–H3)
Base: the worktree was created at
origin/maina8b44d407. The dispatch namedfcb40ad67.git log fcb40ad67..origin/main -- docs/adr/0123-no-active-organization-session-semantics.mdis empty, so the ADR did not move between the two.security-plugin.tsstep 3.7 ata8b44d407), not from either PR's body:git merge-base --is-ancestor 98c3d00447 HEADexits 0.8a058d85ais ingit logofsecurity-plugin.tson the same tree.insertLacksActiveOrganization. It needs all four: the operation isinsert;postureUsesUnionScopeholds; the caller's own Layer 0 is non-null;carriesActiveOrganization(context)is false.operatorInsertLacksActiveOrganization. It needs all three: the operation isinsert;callerCrossesTenantWallholds (fromcomputeWriteTenantWall'scrossedByPlatformAdmin); there is no active organization.refuseNoActiveOrganization('caller', …)inside thepostHookWriteImageCheckseam, and only when some stored row names no organization.opCtx.context.userId, andisSystemshort-circuits the middleware earlier, so system contexts never reach either arm.updateordelete.795ff708d) puts a status-block blockquote under the**Status**:line and strikes the affected text in place, followed by an italic pointer. That is the form matched here. The repo has other forms too: a## Amendment (date, #n): …section is the most common, and ADR-0099 carries an inline> **Amendment note (date):**beside the corrected row. ADR-0123 had no amendment chain of its own to join.check-adr-symbol-anchorsreads backtickedpath#symboltokens. The one anchor added (security-plugin.ts#refuseNoActiveOrganization) is extracted from the new file and not from the base file. It resolves asdeclaration(aconstbinding). A probe with an unknown symbol on the same source resolvesnull. The gate's total went to 2370 anchors, all resolving.a8b44d407.fcb40ad67and ona8b44d407.Gates: all at
e9913cb22, the final commitnode scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackwas re-derived on the actual diff, with no paths. It gives the same 20 commands as the dispatch. Each ran with its output redirected first and its exit captured before any read.--ranreads20 derived, 20 run, 0 NOT-MEASURED, 0 UNRUN, a derived zero.node scripts/check-adr-links.mjsnode scripts/check-adr-links.mjs --self-testnode scripts/check-adr-symbol-anchors.mjsnode scripts/check-adr-symbol-anchors.mjs --self-testnode scripts/check-ci-filter-parity.mjsnode scripts/check-closing-keyword-parity.mjsnode scripts/check-closing-keyword-parity.mjs --self-testnode scripts/check-comment-mask-corpus.mjspnpm --filter @objectstack/lint run check:doc-formula-expressionspnpm check:adr-anchorspnpm check:closed-ceremony-textpnpm check:cross-package-test-inputspnpm check:doc-authoringpnpm check:driver-memory-censuspnpm check:gitlink-declaredpnpm check:nul-bytespnpm check:pm-governed-mergespnpm check:pm-prior-rulingspnpm check:refd-timer-probepnpm check:watch-hint-literalcheck:doc-formula-expressionsreads the built@objectstack/formula/@objectstack/lint. Those were built first, under the verify lock (turbo run build --concurrency=2, 4/4 tasks,VERDICT command-exit 0).docs/adr/**publishes nothing, so this PR carriesskip-changeset.Acceptance notes
canWriteObject's row-less create preview still answerstruefor both arms' callers. PR fix(plugin-security): under group, a no-active-organization insert gets the ADR-0123 D2 403, not a 500 #24819 and PR fix(plugin-security): a platform operator's insert with no active organization gets the ADR-0123 D2 403, not a 500 #24868 each recorded this as a known boundary in their own acceptance notes. The amendment does not restate it. Carrier: none.**Status**:line is left alone. It still reads "Accepted (2026-08-13)". The dated amendment block carries the 2026-10-20 change, as ADR-0047's amendment did.维护者速读(草稿)
改了什么:只动了一个文件 ADR-0123(“已登录但没有当前组织”的会话语义),三处改动,都标了日期 2026-10-20:
为什么改:两次已合并的修复让运行时的行为比 ADR 原文写的更宽:
group多组织模式下,没有当前组织的成员新建记录,现在返回 403 并说明“没有当前组织”。新记录要落在当前组织里,没有当前组织就无处可落。这两种写入以前本来就被拒绝,只是返回的是看不出原因的 500。现在换成能看懂原因的 403。原文还写着“平台运维人员不受影响”,已经不准确。按第一指令 13,ADR 要如实反映已落地的行为;否则后来读 ADR 的人(和 AI)会误以为运维人员没有当前组织也能新建记录。
风险与代价(含回滚):纯文档改动,没有运行时影响,不发包,没有 changeset。回滚就是 revert 这一个提交。
席位意见:
你要做的:审阅这处 ADR 修订;同意的话,在 PR 上点 Approve(席位随后落地)。
Generated by Claude Code