ObjectStackObjectStack

Explain

Explain protocol schemas

[ADR-0090 D6] Access-explanation contract — `explain(principal, object,

operation)` as a first-class API.

The explain engine (@objectstack/plugin-security) walks the SAME code

paths as the enforcement middleware — the same permission-set resolution,

the same evaluator, the same RLS compiler — and reports what each layer of

the evaluation pipeline contributed to the final decision. "Explained by

construction": the report can never drift from enforcement because it IS

enforcement, minus the throw.

Layer order mirrors the runtime pipeline:

tenant_isolation → principal → required_permissions → object_crud → fls →

owd_baseline → depth → sharing → vama_bypass → rls.

[C2 / ADR-0095] Record-grained explanation. The contract carries an optional

recordId on the request and, when present, a per-layer record attribution

plus a top-level record verdict on the response — so the sharing / rls / owd

layers can report the ROW-LEVEL story for one concrete record (which share

admitted it, which filter excluded it, whether the effective row filter

matches). Object-level requests (no recordId) stay byte-compatible.

[ADR-0095 D1/D2] The contract also reserves the kernel-chain vocabulary the

β engine + UI will fill: the always-first tenant wall as tenant_isolation

(Layer 0), a per-layer kernelTier marking Layer 0 vs. business RLS

(Layer 1), and the monotonic posture ladder

(PLATFORM_ADMIN > TENANT_ADMIN > MEMBER > EXTERNAL) on the resolved principal.

Source: packages/spec/src/security/explain.zod.ts

TypeScript Usage

import { AccessMatrix, AccessMatrixEntry, AuthzPosture, ExplainDecision, ExplainLayer, ExplainMatchedRule, ExplainOperation, ExplainRecordAttribution, ExplainRequest } from '@objectstack/spec/security';
import type { AccessMatrix, AccessMatrixEntry, AuthzPosture, ExplainDecision, ExplainLayer, ExplainMatchedRule, ExplainOperation, ExplainRecordAttribution, ExplainRequest } from '@objectstack/spec/security';

// Validate data
const result = AccessMatrix.parse(data);

AccessMatrix

Properties

PropertyTypeRequiredDescription
versionnumber
entriesObject[]

AccessMatrixEntry

Properties

PropertyTypeRequiredDescription
permissionSetstring
objectstring
createboolean
readboolean
editboolean
deleteboolean
viewAllRecordsboolean
modifyAllRecordsboolean
readScopestringoptional
writeScopestringoptional
sharingModelstringoptional

AuthzPosture

ADR-0095 D2 posture rung — PLATFORM_ADMIN crosses the tenant wall where object posture permits; TENANT_ADMIN sees all rows in the org; MEMBER gets business RLS; EXTERNAL sees only explicitly shared rows.

Allowed Values

  • PLATFORM_ADMIN
  • TENANT_ADMIN
  • MEMBER
  • EXTERNAL

ExplainDecision

Properties

PropertyTypeRequiredDescription
allowedboolean
objectstring
operationEnum<'read' | 'create' | 'update' | 'delete' | 'transfer' | 'restore' | 'purge'>
principalObject
layersObject[]
readFilteranyoptional
recordObjectoptionalRow-level verdict for the specific record; set only for record-grained requests.

ExplainLayer

Properties

PropertyTypeRequiredDescription
layerEnum<'tenant_isolation' | 'principal' | 'required_permissions' | 'object_crud' | 'fls' | 'owd_baseline' | 'depth' | 'sharing' | 'vama_bypass' | 'rls'>
kernelTierEnum<'layer_0_tenant' | 'layer_1_business'>optionalADR-0095 kernel layer: layer_0_tenant = the always-first org wall; layer_1_business = business RLS/sharing/ownership.
verdictEnum<'grants' | 'denies' | 'narrows' | 'widens' | 'neutral' | 'not_applicable'>
detailstring
contributorsObject[]
recordObjectoptionalRow-level determination for the specific record under explanation; set only for record-grained requests.

ExplainMatchedRule

Properties

PropertyTypeRequiredDescription
kindEnum<'tenant_filter' | 'owd_baseline' | 'ownership' | 'record_share' | 'sharing_rule' | 'team' | 'territory' | 'rls_policy'>The row-visibility source kind evaluated for this record at this layer.
namestringStable identifier of the concrete rule, share, or policy that was evaluated.
grantsEnum<'read' | 'edit' | 'full'>optionalAccess level a sharing source grants on the record (mirrors SharingLevel).
viastringoptionalHow the rule reached the principal — recipient group/position, ownership, or the matching criteria.
predicateanyoptionalThe row predicate this rule contributed, when it is filter-shaped (null = unrestricted).
effectEnum<'admits' | 'excludes' | 'neutral'>The rule's effect on THIS record: admits, excludes, or neutral.

ExplainOperation

Allowed Values

  • read
  • create
  • update
  • delete
  • transfer
  • restore
  • purge

ExplainRecordAttribution

Properties

PropertyTypeRequiredDescription
outcomeEnum<'admitted' | 'excluded' | 'not_evaluated'>This layer's row-level outcome for the record: admitted, excluded, or not_evaluated (skipped/not row-scoped).
rowFilteranyoptionalThe effective row predicate this layer contributed for the record set (null = unrestricted, deny_all = zero rows).
matchesRecordbooleanoptionalWhether the specific record satisfies rowFilter — the judgement behind outcome.
rulesObject[]Concrete rules, shares, or policies this layer evaluated against the record, in evaluation order.
detailstringoptionalHuman-readable, record-specific explanation of this layer's outcome.

ExplainRequest

Properties

PropertyTypeRequiredDescription
objectstring
operationEnum<'read' | 'create' | 'update' | 'delete' | 'transfer' | 'restore' | 'purge'>
recordIdstringoptionalOptional id of one concrete record to explain at row granularity; omitted = object-level (pre-C2) request.
userIdstringoptional

On this page