@sema-agent/core
Version:
Stateless, task-oriented AI agent core
81 lines (80 loc) • 4.97 kB
TypeScript
/**
* The session capture opt-out's ENTITLEMENT ADJUDICATOR (slice 3's core): one pure
* function every ingress shares — the prepare-time declaration, the resume-time standing-record
* re-check (§3.3), and the Runner flip verb's fresh-resolve closure — so the posture table cannot
* fork across call sites.
*
* The separation law (§3.3) is the module's spine: THIS adjudicator answers "may the declaration /
* the continued run proceed"; the one-way control-plane RECORD answers "how does this session run"
* (record wins for capture — nothing here ever re-enables capture for a recorded session; the
* governed/capture-required continuation arm refuses to RUN instead, keeping both promises: zero
* capture and zero out-of-policy running, availability paid).
*
* The two fault polarities, and why both are deliberate (the code-side home of the §3.1 cost
* table):
* - `"open"` (and absent): a resolver fault ALLOWS the opt-out (+ named disclosure). Wrongly
* allowing costs one uncaptured session — recoverable. Wrongly denying captures a session whose
* user explicitly said no — irreversible (read, foldable into products, syncable). The
* fail-safe faces the irreversible side's OPPOSITE, which is why this member is the documented
* exception to the caps family's deny-on-outage degrade.
* - `"governed"`: the deployment has EXPLICITLY declared the compliance side's irreversibility
* (a retention-required principal acquiring an opt-out through an outage window) the heavier
* one, so a fault/absent verdict refuses the run — fail-closed, the declared direction.
* A mutation flipping the governed fault arm to the open polarity must turn the G-姿态 escape pin
* red (m12).
*/
/** The screened posture (prepare-config-doors folds absent → `"open"`). */
export type MemoryCapturePosture = "open" | "governed" | "capture-required";
/** The per-principal entitlement input as RESOLVED for this adjudication:
* - `value` — `RuntimeCaps.allowMemoryOptOut` when the resolver answered a boolean; `undefined`
* when absent OR when the resolver faulted (the F2 fault-transit contract: a fault must never
* be encoded as an explicit value);
* - `faulted` — the resolve THREW / timed out / answered a non-boolean (the non-boolean case is
* a fault by the member's own contract, never truthiness-read). Distinguished from a clean
* `undefined` only for DISCLOSURE under `"open"` (both allow there) — under `"governed"` both
* are the same refusal (verdict absent = face fault). */
export interface CaptureEntitlementInput {
value: boolean | undefined;
faulted: boolean;
}
export type CaptureOptOutVerdict = {
allowed: true;
/** Present ⇔ the open-posture fault arm fired: the opt-out takes effect AND the caller owes
* the named `onError({phase:"config"})` disclosure line (this string). */
faultDisclosure?: string;
} | {
allowed: false;
/** Always `memory.capture_optout_denied` (terminal). The caller throws it; a DECLARATION
* denial must leave zero record residue (§2.1 order invariant — adjudicate BEFORE marking). */
code: "memory.capture_optout_denied";
detail: string;
};
/**
* Adjudicate one capture opt-out ingress. `subject` names what is being adjudicated, for the
* refusal detail only: `"declaration"` (a `capture:"off"` spelling / the flip verb) or
* `"standing-record"` (a resumed session whose one-way record stands — §3.3: under
* governed/capture-required the question is whether the run may CONTINUE; the record's zero-capture
* promise is not on the table).
*/
export declare function adjudicateCaptureOptOut(input: {
posture: MemoryCapturePosture;
entitlement: CaptureEntitlementInput;
subject: "declaration" | "standing-record";
}): CaptureOptOutVerdict;
/** The typed terminal refusal builder (one spelling for every ingress). */
export declare function captureOptOutDeniedError(detail: string): Error & {
code: string;
};
/** The typed could-not-record refusal (§2.8 — never a success notice's sibling; the caller mints
* {@link import("../memory-engine/engine.js").memoryCaptureOptOutUnpersistedNotice} beside it).
*
* `ingress` is REQUIRED (internal builder, both call sites in prepare-memory state it): the two
* arms' throws settle different things and the message must say which. The declaration arm's throw
* is whitelisted out of prepare-memory's fail-open catch and refuses the RUN; the host flip verb's
* throw rejects only the verb promise — `captureOptedOut` is assigned below it — so the run
* continues with capture still ON. One sentence for both said "refusing to run", which was false
* in the direction that matters: it told the caller the session had stopped capturing when it had
* not. */
export declare function captureOptOutUnpersistedError(sessionId: string, ingress: "declaration" | "flip-verb"): Error & {
code: string;
};