Skip to content

Commit 799eb00

Browse files
docs(adr): ADR-0096 D5 dated note — strict mode lands ON ahead of D2 and the telemetry gate (#22298)
Refs #21908 **Tier H — governed surface (`docs/adr/**`).** This PR lands only on the maintainer's approval: an authorized APPROVED review, or the maintainer's own merge. No seat readies, queues or arms it. ## Summary A dated note under ADR-0096 D5 records the maintainer's ruling Q3 (甲) on #21908 ([comment 6019001864](#21908 (comment)), 2026-10-06). The note says: - strict mode lands ON at the security plugin's hand-off sites, ahead of the D2 `systemContext(reason)` door and the telemetry gate; - the explicit opt-in is the wire-level `isSystem: true` flag, which is E1's own prescription; - no `security.identityStrict` switch is built, so there is no OFF mode. The note cites what licenses that order: the published contract sentence on `ChatWithToolsOptions.toolExecutionContext` ("unauthenticated (RLS-on, sees-nothing)") and the maintainer's ruling 2B on objectstack-ai/cloud#2006. The ADR's own text is not rewritten, and its status stays `Proposed`. The behaviour the note records ships in #22297, the deny round, which is a separate PR and not governed. ## The diff One blockquote note, 2 added lines, placed at the end of D5 and before D6. Nothing else in ADR-0096 changes. ## 维护者速读(草稿) ### 改了什么 在 ADR-0096 的 D5(严格模式)末尾加一段带日期的注记,不改动 ADR 原文与状态。注记记录:严格模式现在就默认开启,先于 D2 的 `systemContext(reason)` 入口和遥测门;显式提权沿用线上已有的 `isSystem: true`;不提供关闭开关。 ### 为什么改 你在 #21908 的 Q3 选了「甲」:只加注记,不重写 ADR。代码那一半(拒绝没有主体的数据引擎调用)在 #22297。ADR 是受管面,所以单独成 PR,由你批准。 ### 风险与代价(含回滚) 纯文档,对运行时零影响。回滚就是撤掉这两行。真正的行为风险在 #22297(进程内未带上下文的调用会被 403 拒绝),那边有迁移说明和合同级复核。 ### 席位意见 ### 你要做的 读一遍注记的措辞,同意就批准(APPROVED);要改措辞就在 PR 上留言。 ## Evidence - `dispatch-gates --commands` derived 19 families at `2becf9015f`. All 19 ran and exited 0. `--ran`: "19 derived famil(ies) accounted for — 19 run, 0 NOT-MEASURED (a DERIVED zero — all 19 recorded an exit code and none of them is 3)". The first `check:doc-formula-expressions` run exited 3 (prerequisite not met: `formula` and `lint` were unbuilt in this worktree). They were built, and it then exited 0. - `check-governed-merges --branch claude/issue-21908-adr-0096-d5-note`: GOVERNED, landing tier H, `docs/adr/**` ×1 (`docs/adr/0096-execution-surface-identity-admission.md`), 2 changed lines. --- _Generated by [Claude Code](https://claude.ai/code/session_01WkL6Eijt432S1Y7ekb6ovQ)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 79c35d4 commit 799eb00

1 file changed

Lines changed: 2 additions & 0 deletions

File tree

‎docs/adr/0096-execution-surface-identity-admission.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ Rollout is gated on evidence, not dates (ADR-0049/0073 idiom):
155155
2. **Telemetry gate**: the audit stream (landed for actions in #2964, extended by D2 to all elevation) answers "how many distinct call sites still hit the fall-open in real deployments, and which reasons dominate?" — the same question #2849's Phase-3 plan needed answered before flipping action defaults.
156156
3. **Major**: default ON. The empty-principal skip in `security-plugin.ts` keeps exactly one behavior: honoring `SystemGrant`/`isSystem`. Anonymous-but-authenticated-elsewhere flows must arrive with a principal by then (they already should — REST's `enforceAuth` is upstream).
157157

158+
> **Note (2026-10-08) — strict mode lands ON now, ahead of D2 and the telemetry gate.** The maintainer's ruling Q3 (甲) on [#21908](https://github.com/objectstack-ai/objectstack/issues/21908) ([comment 6019001864](https://github.com/objectstack-ai/objectstack/issues/21908#issuecomment-6019001864), 2026-10-06) lands step 3 of this decision out of the order above. An engine context that carries no principal (no user, no position, no permission set) and is not a system context is refused with `PermissionDeniedError` (`403 PERMISSION_DENIED`) wherever the security plugin used to hand it through: the engine middleware refuses every verb before the operation runs, `canReadObject`, `canWriteObject` and `canExport` answer `false`, and `getReadFilter` answers the deny filter. The field projections answer such a context as they answer any caller that resolves no permission set. The explicit opt-in is the wire-level `isSystem: true` flag, which is E1's own prescription, because the D2 `systemContext(reason)` door does not exist yet. Every producer the closure measured carries the caller's principal or that flag inside its owning code. No `security.identityStrict` switch is built, so there is no OFF mode and no telemetry stage. Two facts license the order. First, the published contract sentence on `ChatWithToolsOptions.toolExecutionContext` (`packages/spec/src/contracts/ai-service.ts`) already promises that an empty context runs "unauthenticated (RLS-on, sees-nothing)". Second, the maintainer's ruling 2B on [objectstack-ai/cloud#2006](https://github.com/objectstack-ai/cloud/issues/2006) holds that privilege comes only from an explicit system opt-in, never from a missing field. D2, D3, the audit stream and the rest of this ADR stand as written; this note does not rewrite them.
159+
158160
### D6 — Action-level `runAs` is an application of this mechanism, in ADR-0073's vocabulary
159161

160162
#2849's Phase 2/3 (give business actions a `runAs`, eventually default bounded) is **confirmed as direction but re-sequenced and re-based**:

0 commit comments

Comments
 (0)