@sema-agent/core
Version:
Stateless, task-oriented AI agent core
49 lines (48 loc) • 3.61 kB
TypeScript
/**
* F-012 L2 — the ENGINE-INTERNAL ask-class envelope.
*
* An `ask` verdict's SEMANTIC CLASS decides whether a deployment-declared sandbox may auto-admit it
* (the ruling: a declared sandbox admits everything inside it — the boundary crossings park to a
* human, escape prevention belongs to the sandbox, not to engine re-policing). The class deliberately
* lives OUTSIDE the public `PermissionResult`: a decision object is caller-supplied data, and a
* self-reported "this ask is sandbox-local" field would be the same trust hole as the
* `decisionReason:"safety"` self-declaration this codebase already refuses. Instead, BUILT-IN policy
* factories register their instances here (private WeakMap brand — nothing a deployment policy can
* self-declare by shaping its return value), and everything unregistered reads as `unknown`.
*
* Classes and their dominance (STRICT — merge keeps the strongest; only an all-`sandbox_local` set
* may auto-admit):
* - `sandbox_local` — an engine-authored "confirm a potentially destructive LOCAL action" ask
* (name/pattern confirmation lists). Sandbox containment answers it.
* - `external_authority` — an ask whose whole point is real judgment (the safety-rule policies with
* `requiresRealApproval`); containment answers nothing about it.
* - `hook` — a screening-face ask (a deployment's PreToolUse verdict folded to policy
* form); the face's authority is the deployment's, not the sandbox's.
* - `mandate` — an ask bound to durable-park semantics (inherited durable mandate /
* approver-unavailable float); it must reach the park untouched.
* - `unknown` — everything unregistered, every deployment policy. Fail-closed: never
* admitted.
*/
export type AskClass = "sandbox_local" | "external_authority" | "hook" | "mandate" | "unknown";
/**
* Brand a built-in policy instance with its ask class (engine factories only — not exported from the
* package). The `check` binding is LOCKED as a non-writable, non-configurable DATA property before the
* policy is returned (falsification-style round 4, HIGH): reading `policy.check` and INVOKING it must
* name the same callable, atomically. A plain `===` re-read was TOCTOU-able by an accessor — a getter
* could return the branded function to `policyAskClassOf` and a deployment ask to the gate's
* invocation. Locking the property makes the callable un-swappable and un-redefinable, so the class
* travels with the exact decision function. An `check` that is ALREADY accessor-backed (or a frozen
* object we cannot lock) is refused branding — it reads back `unknown` (fail-closed), never trusted.
*/
export declare function brandPolicyAskClass<T extends {
check: unknown;
}>(policy: T, cls: AskClass): T;
/** The registered class of a policy instance — `unknown` for anything unregistered, whose `check` is
* no longer the locked data value, or whose `check` became accessor-backed (fail-closed: a
* replaced/decorated/getter-shadowed decision function is not the branded one). Reads the property
* DESCRIPTOR's value (never invokes a getter), so the check is atomic with what the gate will call. */
export declare function policyAskClassOf(policy: (object & {
check?: unknown;
}) | null | undefined): AskClass;
/** The strongest class in a set (strict dominance — any non-`sandbox_local` member dominates). */
export declare function dominantAskClass(classes: readonly AskClass[]): AskClass;