Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/adr/0096-execution-surface-identity-admission.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ Rollout is gated on evidence, not dates (ADR-0049/0073 idiom):
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.
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).

> **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.

### D6 — Action-level `runAs` is an application of this mechanism, in ADR-0073's vocabulary

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