/** * Standing orders (Studio OS behaviour 10) — the daemon evaluator. * * Fed by the daemon's single CoreEvent subscription (`awaitingHuman`) and the team relay * (`wicked.team.finding.raised`), and re-swept over the engine's open gate rows when the away flag * turns on or an order is added. For each gate or finding it finds the ACTIVE orders that match * (away gating, project scope, the reviewed phase or the finding's severity) and acts: * * hold — the gate stays open; `standing-order.held` says an order is keeping it for you. * A hold wins over an approve on the same gate. * approve — answers the gate through `decideGate`, THE gate decision path `POST /runs/:id/gate` * uses (ord check, 409 gate_changed / gate_unknown, confirmGate, `gate.decided` audit). * The actor is the order. A refusal (a person got there first) is logged, never retried. * notify — the message is QUEUED: the store records `standing-order.notified` (its outbox). * Nothing is sent: outbound always waits. * * THE INVARIANT: an order approves only a phase-review gate (`def`, `run_level`, `terminal`), or — * as a TRUST RECEIPT (brainstorm idea 13) — the plan approval of a run in its own project, of its * own preset, whose OPEN plan gate reports band `0-19` and no high risk (read off the gate's own * `gate.opened` row; unreadable = fail closed). The deliver gate, an escalation, a failure and a * triage are never answered by an order, and neither is any gate of a steering-author run (its * approval lands doctrine). * * A gate's PHASE, for matching, is the reviewed unit's `phase_ref` (the upcoming unit's when * nothing has run). The gate before the run's first unit, with nothing to review, is also * `intake` — the name studio and operators use for it (`IntakePlan.isIntakeGate`). */ import type { AuditLog } from '../api/audit.js'; import type { RegisteredRoutes } from '../api/routes.js'; import type { CoreEvent } from '../core/types.js'; import { type StandingOrderRule, type StandingOrderStore } from './store.js'; /** The only gate kinds an order may approve. */ export declare const APPROVABLE_GATE_KINDS: ReadonlySet; export interface GateFact { runId: string; ord: number; reviewingOrd: number | null; gateKind: string; prompt: string; } export interface FindingFact { runId: string; findingId: string; severity: string; claim: string; } /** What the evaluator needs to know about a run: its project and the phase of a unit. */ export interface RunFacts { projectId: string | undefined; problem: string; phaseOf: (ord: number) => string | undefined; /** The run's first unit ord — the gate before it, with nothing to review, is the INTAKE gate. */ firstOrd: number | undefined; /** Approving this run's gate would land doctrine (a steering-author run): never an order's call. */ landsDoctrine: boolean; /** The band the run's accepted plan landed in (`team_plan.accepted.band`); undefined when unscored. */ band: string | undefined; /** The preset the launch named (`team_plan.preset`); undefined on a user plan or a workflow. */ preset?: string | undefined; } /** The OPEN plan gate's own reading of the plan it holds (its `gate.opened` row). */ export interface PlanGateRisk { band: string; highRisk: boolean; } /** Whether an order may answer this plan gate: the trust receipt's every condition, re-read. */ export declare function planOrderMayApprove(rule: StandingOrderRule, run: Pick, risk: PlanGateRisk | undefined): boolean; /** * The phase a gate is matched on: `intake` for the gate before the run's first unit with nothing * to review, else the reviewed unit's phase (the upcoming unit's when nothing has run). `unitPhase` * is the unit's own phase either way. The ONE reading, shared with the decided-gate history. */ export declare function gatePhase(run: Pick, ord: number, reviewingOrd: number | null): { phase: string; unitPhase: string; }; /** THE INVARIANT as a predicate: an order may approve only a phase-review gate of a run whose * approval lands no doctrine. */ export declare function orderMayApprove(gateKind: string, run: Pick): boolean; export interface EvaluatorDeps { store: StandingOrderStore; decideGate: RegisteredRoutes['decideGate']; audit: Pick; runFacts: (runId: string) => Promise; /** The engine's open gate rows (a sweep); `[]` when the engine cannot say. */ openGates: () => Promise; /** The run's OPEN plan gate's band and risk; undefined when it cannot be read (fail closed). */ planGate?: (runId: string) => Promise; log?: (msg: string) => void; } export declare class StandingOrderEvaluator { private readonly deps; /** `:` keys already acted on — one action per gate/finding per order. */ private readonly done; private readonly log; constructor(deps: EvaluatorDeps); /** Every settled action, for tests: resolves when the evaluation it started is finished. */ onEvent(event: CoreEvent): Promise; /** A team relay frame (`{ type: 'teamEvent', event: }`). */ onTeamFrame(frame: CoreEvent): Promise; /** Re-read the engine's open gates (the away flag turned on, or an order was added). */ sweep(): Promise; private active; private inScope; private once; considerGate(g: GateFact): Promise; /** The open plan gate's band and risk; undefined (fail closed) when it cannot be read. */ private planRisk; considerFinding(f: FindingFact): Promise; /** The store records it (`standing-order.notified`, the order as actor) — queued, never sent. */ private notify; } //# sourceMappingURL=evaluator.d.ts.map