86 lines
4.3 KiB
TypeScript
86 lines
4.3 KiB
TypeScript
/**
|
||
* AdapterContext — the per-invocation execution environment handed to every
|
||
* adapter action's `precheck` / `execute` / `rollback`.
|
||
*
|
||
* Deliberately framework- and Playwright-free. The Layer-6 design doc listed
|
||
* `browserContext: BrowserContext`, `torCircuit`, and `captchaSolver` directly on
|
||
* the context; those are intentionally collapsed here into a single opaque
|
||
* {@link SurfaceSession} handle so that this shared contract — imported by every
|
||
* specialist and every action — never drags `playwright` into its dependency
|
||
* graph. The container/Tor/captcha machinery lives behind the session handle,
|
||
* owned by the adapter runtime, not exposed in the type.
|
||
*/
|
||
import type { AgentActionsClient } from './audit.js';
|
||
import type { BlocklistAccessor } from './blocklist.js';
|
||
import type { AdapterLogger, PlatformApiClient } from './platform-api.js';
|
||
import type { SurfaceKind } from './surface-kind.js';
|
||
|
||
/**
|
||
* Opaque handle to the live, authenticated surface session (the
|
||
* container-managed browser context + Tor circuit + captcha solver from
|
||
* `_engineering-surface-adapter-container.md` Layers 1–5). The contract treats it
|
||
* as a black box; the surface-specific adapter runtime supplies and interprets
|
||
* it. Each concrete specialist augments this via declaration merging or casts to
|
||
* its own session type — the base shape carries only what every action can rely
|
||
* on without importing Playwright.
|
||
*/
|
||
export interface SurfaceSession {
|
||
/** Which surface this session is authenticated against. */
|
||
readonly surface: SurfaceKind;
|
||
/** Whether the session currently holds live credentials (cookies still valid). */
|
||
readonly authenticated: boolean;
|
||
}
|
||
|
||
/**
|
||
* Session-free slice of the per-invocation context, handed to an action's
|
||
* `precheck`. Precheck runs the deterministic K-gates, which only read
|
||
* `blocklist` / `platformApi` — they NEVER need the live {@link SurfaceSession}.
|
||
* Splitting the context this way lets the dispatcher run precheck (and decline a
|
||
* K-gate failure) WITHOUT acquiring a container-managed session: a blocked or
|
||
* approval-required attempt costs no session spin-up.
|
||
*
|
||
* Carries `agentActions` so the dispatcher (the one place that owns the audit
|
||
* write on a decline) can record the declined row from this context; an action's
|
||
* own `precheck` never writes audit rows.
|
||
*/
|
||
export interface PrecheckContext {
|
||
/** Person tenant (`agent_actions.user_id`). Always present (person-first). */
|
||
readonly userId: string;
|
||
/** Optional Org overlay (`agent_actions.org_id`). Absent = Person-owned. */
|
||
readonly orgId?: string;
|
||
/** Client for reads/writes against platform.api on black. */
|
||
readonly platformApi: PlatformApiClient;
|
||
/** Accessor for the tenant's safety blocklist (K-gate data source). */
|
||
readonly blocklist: BlocklistAccessor;
|
||
/** Writer for the `agent_actions` audit spine. */
|
||
readonly agentActions: AgentActionsClient;
|
||
/** Structured logger (never logs credentials or raw page content). */
|
||
readonly logger: AdapterLogger;
|
||
}
|
||
|
||
/**
|
||
* Per-invocation context handed to an action's `execute` / `rollback`. The
|
||
* session-free {@link PrecheckContext} plus the two things only available once the
|
||
* dispatcher has decided to run the action: the live surface session and the
|
||
* dispatcher's `autoExecuted` decision.
|
||
*
|
||
* One {@link AdapterContext} is constructed per executed action and is scoped to a
|
||
* single (userId, [orgId], surface session).
|
||
*
|
||
* `autoExecuted` is the dispatcher's single source of truth for the audit flag:
|
||
* `autoExecutable && !approved`. An action that writes an `agent_actions` row in
|
||
* `execute` MUST set `auto_executed` from this field (never a literal) so the
|
||
* persisted value always equals the dispatcher's decision — even for an
|
||
* autoExecutable action that was ALSO explicitly approved (then `autoExecuted` is
|
||
* `false`, recording the run as operator-driven).
|
||
*/
|
||
export interface AdapterContext extends PrecheckContext {
|
||
/** Live authenticated surface session handle (container-managed). */
|
||
readonly session: SurfaceSession;
|
||
/**
|
||
* The dispatcher's decision for this run: `true` iff the action ran without a
|
||
* per-call approval (`autoExecutable && !approved`). Actions writing an audit
|
||
* row in `execute` set `auto_executed` from this — never from a hardcoded value.
|
||
*/
|
||
readonly autoExecuted: boolean;
|
||
}
|