@vostride/agent-qa-runner 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { StepEvidence, RecordingEntry, Action as Action$1, RecordingAnnotationWitness, Platform, ActionsFor as ActionsFor$1, LiveStreamKind, LiveFrame, ScreenState, RecordingContentType, ScopeKey, BriefBlock, ServedRetrievalTraceV1, SearchOptions, IndexEntry, RecordId, ReadOptions, RecordBody, Anchor, CautionBlock, ProcedureBindingAvailability, ProcedureMatch, CanaryOutcome, ElementState, ElementLabels, Ref, ElementInfo, ScreenStateMetadata, CacheKey, ClipboardEvidence, SubmitOutcome, SubmitReason, FillVerdict, InputPath, DownloadEvidence, IdempotentNoopMeta, AssertValueOp, ConditionFileCheck, OperationEvidence, GroundingAttempt, WorkingMemoryEntry, ConditionVerdict, ConditionNeed, CitationSource, InterpolatedVariable, ToolExchangeEvidence, ModelCallRecord, RunEventEnvelope, CompletedRunHandoff, HookStartedPayload, HookFinishedPayload, TestRetryScheduledPayload, DeclaredModelProfile, ModelIdentity, RunId, PostProcessingDisposition, RunStatus, RunArtifactStageInput, RunArtifactFinalizeInput, ExecutionContext, QuarantineAppliedEntry, PlannerLimitsRecord, ServingRecordMetadata, ServingAdmissionDecision, ServedAdmissionSurface, ServedAdmissionEvent, ArtifactRef, EvidenceDocument, RecordingRef, StepFinalizedPayload, ModelUsageObservations, SubActionEvidence, SubActionRecordedPayload, RecordedRetrievalRung, ProcedureBodyPayload, ReadTrace, Surface, SamplingParams, BriefLine, ServedBrief, ServedPromptTurn, ActionResult as ActionResult$1, CautionLine, PlanningFailureEvidence, ReportedValueEvidence, TerminationEvidence, LimitStopEvidence, ConditionVerdictsEvidence, OperationCaptureAvailability, StepLimitUsage, AiJudgmentEvidence, AssertValueEvidence, VerdictSource, StepPlanSource, CacheMissReason, Decision, VerifierVerdict, Viewport, ActionAnnotation, MaskFn, RedactedEnvVar, CacheableStepInput, NonCacheableStepInput, RunEventType, RunEventPayload, LiveFrameEndReason, LiveFrameSubscription, LiveStreamDeclaration, RunSession, PerTestOutcome, MemberTestOutcome, Verdict, RiskActionDescriptor } from '@vostride/agent-qa-schema';
1
+ import { StepEvidence, RecordingEntry, Action as Action$1, RecordingAnnotationWitness, Platform, ActionsFor as ActionsFor$1, LiveStreamKind, LiveFrame, ScreenState, RecordingContentType, ScopeKey, BriefBlock, ServedRetrievalTraceV1, SearchOptions, IndexEntry, RecordId, ReadOptions, RecordBody, Anchor, CautionBlock, ProcedureBindingAvailability, ProcedureMatch, CanaryOutcome, ElementState, ElementLabels, Ref, ElementInfo, ScreenStateMetadata, CacheKey, ClipboardEvidence, SubmitOutcome, SubmitReason, FillVerdict, InputPath, DownloadEvidence, IdempotentNoopMeta, AssertValueOp, ConditionFileCheck, OperationEvidence, GroundingAttempt, WorkingMemoryEntry, ConditionVerdict, ConditionNeed, CitationSource, InterpolatedVariable, ToolExchangeEvidence, ModelCallRecord, RunEventEnvelope, CompletedRunHandoff, HookStartedPayload, HookFinishedPayload, TestRetryScheduledPayload, DeclaredModelProfile, ModelIdentity, RunId, PostProcessingDisposition, RunStatus, RunArtifactStageInput, RunArtifactFinalizeInput, ExecutionContext, QuarantineAppliedEntry, PlannerLimitsRecord, ServingRecordMetadata, ServingAdmissionDecision, ServedAdmissionSurface, ServedAdmissionEvent, ArtifactRef, EvidenceDocument, RecordingRef, StepFinalizedPayload, ModelUsageObservations, SubActionEvidence, SubActionRecordedPayload, RecordedRetrievalRung, ProcedureBodyPayload, ReadTrace, Surface, SamplingParams, BriefLine, ServedBrief, ServedPromptTurn, ActionResult as ActionResult$1, CautionLine, PlanningFailureEvidence, ReportedValueEvidence, TerminationEvidence, LimitStopEvidence, ConditionVerdictsEvidence, OperationCaptureAvailability, StepLimitUsage, AiJudgmentEvidence, AssertValueEvidence, VerdictSource, StepPlanSource, CacheMissReason, Decision, VerifierVerdict, Viewport, ActionAnnotation, MaskFn, RedactedEnvVar, CacheableStepInput, NonCacheableStepInput, RunEventType, RunEventPayload, LiveFrameEndReason, LiveFrameSubscription, LiveStreamDeclaration, RunSession, PerTestOutcome, MemberTestOutcome, Verdict } from '@vostride/agent-qa-schema';
2
2
  export { IdempotentNoopMeta, Ref, asRef, readIdempotentNoopMeta } from '@vostride/agent-qa-schema';
3
3
  import { LanguageModel, ModelMessage, LanguageModelUsage, ToolSet, SystemModelMessage, Tool } from 'ai';
4
4
  import { z } from 'zod';
@@ -147,12 +147,6 @@ interface StepResult {
147
147
  screenshot?: Buffer;
148
148
  screenshotBefore?: Buffer;
149
149
  trace?: StepTrace;
150
- /**
151
- * The §A8 evidence accumulated by the runner loop, produced by construction (D-14).
152
- * ADDITIVE (Phase 353): the legacy `trace` is projected FROM this, never the reverse
153
- * (Open Q5). Core's transitional orchestration persists it via the run-artifact path
154
- * (D-16) until Phase 361 lifts the accumulator into RunSession/CompletedRunHandoff.
155
- */
156
150
  evidence?: StepEvidence;
157
151
  retryCount?: number;
158
152
  capturedVariables?: Record<string, string>;
@@ -185,23 +179,8 @@ interface TestResult {
185
179
  };
186
180
  }
187
181
 
188
- interface ObserveOptions {
189
- extractDom?: boolean;
190
- }
191
182
  type Action = Action$1;
192
183
  type ActionsFor<P extends Platform = Platform> = ActionsFor$1<P>;
193
- /**
194
- * An adapter's LIVE STREAM capability (403 D-05). The adapter owns the producer (a CDP screencast,
195
- * an MJPEG broadcaster, a WebRTC track, or a snapshot producer over a capture that is safe to run
196
- * beside a step); the runner owns nothing but this object, so no `Page` and no session handle ever
197
- * leaves the adapter. Lifecycle is lazy and refcounted by the run's {@link LiveStreamHub}: `start`
198
- * on the first viewer, `ack` per consumed frame (the producer's flow control), `stop` on the
199
- * last — idempotent, so a double stop is a no-op rather than a throw.
200
- *
201
- * The labelled 1s snapshot producer (`createSnapshotLiveStream`) sits behind this same contract
202
- * (428 D-11): the composition registers it as the whole preview when an adapter has no continuous
203
- * stream, and as the fallback the hub starts when a continuous stream fails to start (D-12).
204
- */
205
184
  interface LiveStreamCapability {
206
185
  readonly kind: LiveStreamKind;
207
186
  start(onFrame: (frame: LiveFrame) => void): Promise<void>;
@@ -227,10 +206,6 @@ interface OperationCaptureSupport {
227
206
  /** Why a capture is unsupported, e.g. the browser name. */
228
207
  reason?: string;
229
208
  }
230
- /**
231
- * 2026-10-08 (436-15, D-19): what the loop hands one dispatch. `remainingStepMs` is set only when
232
- * a step deadline is armed; adapters that run no post-action wait ignore both.
233
- */
234
209
  interface ExecuteOptions {
235
210
  remainingStepMs?: number;
236
211
  abortSignal?: AbortSignal;
@@ -239,33 +214,15 @@ interface PlatformAdapter<P extends Platform = Platform> {
239
214
  readonly platform: P;
240
215
  setup(config: PlatformConfig): Promise<void>;
241
216
  cleanup(): Promise<void>;
242
- observe(options?: ObserveOptions): Promise<ScreenState>;
217
+ observe(): Promise<ScreenState>;
243
218
  execute(action: ActionsFor<P>, options?: ExecuteOptions): Promise<ActionResult>;
244
219
  screenshot?(): Promise<Buffer | undefined>;
245
- /**
246
- * 403 D-05: the optional live-stream producer for this adapter's current target. ABSENT means
247
- * "no continuous stream" (non-Chromium, remote farm), not "no preview": the composition's
248
- * `liveStreamFor` wraps `screenshot()` in the labelled 1s snapshot producer instead, and uses
249
- * that producer as the fallback when a continuous stream fails to start (428 D-11/D-12). Only an
250
- * adapter with neither reads `{ kind: 'none' }`. An adapter whose `screenshot()` mutates shared
251
- * state (the mobile adapters switch the Appium context) must expose its own snapshot
252
- * `liveStream` over a side-effect-free capture instead, so `screenshot()` is never wrapped.
253
- */
254
220
  readonly liveStream?: LiveStreamCapability;
255
221
  readonly recording?: RecordingCapability;
256
- /**
257
- * 436 D-23: which operation-specific captures this adapter runs. ABSENT means none; the loop
258
- * then records both as unavailable, with `reason` or else 'platform'.
259
- */
260
222
  readonly operationCaptureSupport?: OperationCaptureSupport;
261
223
  drainConsoleLogs?(level?: string): ConsoleLogEntry[];
262
224
  drainNetworkLogs?(urlPattern?: string): NetworkLogEntry[];
263
- /** 439 D-14: the undrained network log, read without consuming it; the step-end drain still sees it. */
264
225
  peekNetworkLogs?(urlPattern?: string): NetworkLogEntry[];
265
- /**
266
- * 439 D-04: the bytes of a completed download with this sha256, held in memory and bounded by
267
- * the adapter; undefined when the adapter holds none (over its cap, evicted, or disposed).
268
- */
269
226
  readDownloadBytes?(sha256: string): Uint8Array | undefined;
270
227
  }
271
228
  declare function assertNever(value: never): never;
@@ -313,7 +270,6 @@ interface PlatformConfig {
313
270
  deepLinkAppId?: string;
314
271
  appState?: 'preserve' | 'reset';
315
272
  appPath?: string;
316
- browserstackApp?: string;
317
273
  appiumUrl?: string;
318
274
  timeouts?: TimeoutConfig;
319
275
  recording?: {
@@ -325,12 +281,6 @@ interface PlatformConfig {
325
281
  };
326
282
  };
327
283
  verbose?: boolean;
328
- farmSession?: {
329
- hostname: string;
330
- port: number;
331
- path: string;
332
- capabilities: Record<string, unknown>;
333
- };
334
284
  logCapture?: {
335
285
  console?: boolean;
336
286
  network?: boolean;
@@ -348,7 +298,6 @@ interface BrowserConfig {
348
298
  interface DeviceConfig {
349
299
  name: string;
350
300
  platform: 'android' | 'ios';
351
- transport: 'local' | 'browserstack';
352
301
  match: Record<string, unknown>;
353
302
  }
354
303
  interface TimeoutConfig {
@@ -357,14 +306,6 @@ interface TimeoutConfig {
357
306
  navigation?: number;
358
307
  }
359
308
 
360
- /**
361
- * The Channel-1 brief and the serve-time trace that explains it, as ONE value (KREV-02 · D-16).
362
- *
363
- * The pairing is the guarantee, not a convenience. A reader implementation cannot satisfy this
364
- * port while producing a brief and no trace, and a consumer cannot receive a brief without also
365
- * being handed how it was chosen — which is what makes 387-06's why-verb able to answer about the
366
- * moment of serving rather than about a re-query of today's index.
367
- */
368
309
  interface ServedRunBrief {
369
310
  brief: BriefBlock;
370
311
  trace: ServedRetrievalTraceV1;
@@ -379,22 +320,10 @@ interface KnowledgeHintReader {
379
320
  search(query: string, options: SearchOptions): IndexEntry[];
380
321
  read(id: RecordId, options?: ReadOptions): RecordBody | undefined;
381
322
  getCautions(anchors: Anchor[], budget: number): ServedCautions;
382
- /**
383
- * D-08 port evolution: source-tagged binding NAMES cross here (variables, memory, secrets) so
384
- * matcher fillability mirrors loop binding; no value ever crosses the reader port in any form.
385
- * Value binding stays loop-side at replay time. Absent availability is treated as empty, so a
386
- * referenced-parameter procedure downranks to hint (fail-conservative).
387
- */
388
323
  getProcedure(intent: string, screenState: ScreenState, availability?: ProcedureBindingAvailability): ProcedureMatch | undefined;
389
324
  emitCanaryOutcome(payload: CanaryOutcome): void;
390
325
  }
391
326
 
392
- /**
393
- * Adapter -> builder input for a single observed node.
394
- *
395
- * Structural links are carried as INDICES because refs do not exist yet — the
396
- * builder mints them in document order (RESEARCH Pitfall #7).
397
- */
398
327
  interface InterimNode {
399
328
  /** Schema role vocabulary — adapters map native roles BEFORE the builder. */
400
329
  role: string;
@@ -414,16 +343,6 @@ interface InterimNode {
414
343
  x: number;
415
344
  y: number;
416
345
  };
417
- /**
418
- * ONLY real platform signals (D-08 — never fabricated). The builder derives the
419
- * required booleans from documented defaults when a signal is absent:
420
- * enabled = state.enabled ?? true (absence of a disabled signal means enabled)
421
- * focused = state.focused ?? false
422
- * visible = state.visible ?? true (present in the a11y tree means exposed;
423
- * adapters set false explicitly for offscreen)
424
- * Optional bits (selected/checked/editable/clickable) pass through only when the
425
- * platform supplied them — typed-absent otherwise.
426
- */
427
346
  state?: Partial<ElementState>;
428
347
  labels?: ElementLabels;
429
348
  /** Raw platform bag, passed through to ElementInfo.attributes (default {}). */
@@ -432,7 +351,6 @@ interface InterimNode {
432
351
  text?: string;
433
352
  /** Adapter-private hint (e.g. android class / XCUI type); the builder ignores it. */
434
353
  nativeType?: string;
435
- /** D-10; the builder maps containerIndex -> the minted container Ref. */
436
354
  scrollContext?: {
437
355
  containerIndex?: number;
438
356
  offsetX: number;
@@ -447,10 +365,6 @@ interface BuildScreenStateInput {
447
365
  width: number;
448
366
  height: number;
449
367
  };
450
- /**
451
- * EXACT on web; BEST-EFFORT on mobile (D-10) — mobile callers pass a best-effort
452
- * scroll derived from scrollable-node bounds. The field is precise only on web.
453
- */
454
368
  scroll: {
455
369
  offsetX: number;
456
370
  offsetY: number;
@@ -461,13 +375,7 @@ interface BuildScreenStateInput {
461
375
  /** Caller-supplied — keeps the builder pure and deterministic. */
462
376
  timestamp: number;
463
377
  url?: string;
464
- /** Web-only (D-04); lands in metadata.domContext. */
465
- domContext?: string;
466
378
  }
467
- /**
468
- * Execute-time resolution stays adapter-private: `index` is the live node's place in the
469
- * input nodes array. No same-screen position is minted for anything to pick by (438 D-13).
470
- */
471
379
  interface RefBinding {
472
380
  index: number;
473
381
  }
@@ -477,10 +385,6 @@ interface BuildScreenStateResult {
477
385
  /** Execute-time ref -> live-node resolution; stays adapter-private. */
478
386
  binding: Record<Ref, RefBinding>;
479
387
  }
480
- /**
481
- * The capture stamp the loop applies after compression (D-11). `full` carries the
482
- * real image dimensions; `textOnly` attaches no image.
483
- */
484
388
  type CaptureStamp = {
485
389
  mode: 'full';
486
390
  imageWidth: number;
@@ -494,33 +398,10 @@ type CaptureStamp = {
494
398
  * yields byte-identical output.
495
399
  */
496
400
  declare function buildScreenState(input: BuildScreenStateInput): BuildScreenStateResult;
497
- /**
498
- * Deterministic LLM-facing tree text, derived from the structured elements (D-02) —
499
- * one grammar for all platforms. Exported so Phase 357's slim/rich dual-projection is
500
- * a renderer-only change with zero adapter edits.
501
- *
502
- * Grammar (pinned; RESEARCH Pitfall #10):
503
- * [Viewport: {viewportWidth}x{viewportHeight}] [{elements.length} elements]
504
- * {2 spaces × depth}- {role}{ "name"?} [ref={ref}]{ @(x,y wxh)?}{ [disabled]?}{ [offscreen]?}{ [checked]?}{ [selected]?}{ [editable]?}{ text: <row text as a JSON string>?}
505
- * depth = length of the parentRef chain (root elements depth 0).
506
- * A rendered name collapses each line break, with the whitespace around it, to one space, so
507
- * every element stays on one line; element.name and value keep the raw text.
508
- * ` text: "…"` appears only on a row container (ROW_CONTAINER_ROLES) whose element.text is
509
- * non-empty (438 D-02: the planner must see a row to state it); line breaks collapse the same
510
- * way and the rendered text is capped at 120 characters plus `…`. The row text is a JSON string
511
- * (JSON.stringify, as quoted() renders names in the refusal line), so a quote or backslash in app
512
- * text cannot end the string or forge a ref, flag or line (438 gap round, WR-02, T-438-04).
513
- * element.text keeps the full text the judge and replay compare against.
514
- */
515
401
  declare function renderScreenTree(elements: ElementInfo[], metadata: ScreenStateMetadata): string;
516
- /**
517
- * Pure re-stamp of the discriminated captureMode metadata member (D-11). Constructs a
518
- * fresh metadata object from the base fields and returns a NEW ScreenState — zero `as`
519
- * casts, zero mutation of the input.
520
- */
521
402
  declare function stampCaptureMode(state: ScreenState, capture: CaptureStamp): ScreenState;
522
403
 
523
- /** The element the planner meant beside its ref (D-01); `row` names a repeated label's row. */
404
+ /** The element the planner meant beside its ref; `row` names a repeated label's row. */
524
405
  interface StatedTarget {
525
406
  role?: string;
526
407
  name: string;
@@ -528,7 +409,7 @@ interface StatedTarget {
528
409
  }
529
410
  /** The element lanes an action can carry a stated target on. */
530
411
  type StatedTargetLane = 'ref' | 'fromRef' | 'toRef';
531
- /** The stated target per element lane, kept by the gate for the pre-dispatch check (D-01, D-04). */
412
+ /** The stated target per element lane, kept by the gate for the pre-dispatch check. */
532
413
  type StatedTargets = Partial<Record<StatedTargetLane, StatedTarget>>;
533
414
  type TargetMismatchReason = 'role-kind' | 'name-no-shared-word' | 'name-number' | 'row';
534
415
  type StatedTargetJudgement = {
@@ -542,52 +423,23 @@ type StatedTargetJudgement = {
542
423
  rowStated: boolean;
543
424
  observedRow?: string;
544
425
  };
545
- /**
546
- * Judge a stated target against the element its ref names (D-03). `elements` is the observation
547
- * the element belongs to; the element's row is read from it (D-02).
548
- */
549
426
  declare function judgeStatedTarget(stated: StatedTarget, element: ElementInfo, elements: readonly ElementInfo[]): StatedTargetJudgement;
550
427
 
551
- /**
552
- * The subset of the action union that may be persisted in a cached plan (D-08). The
553
- * non-deterministic AI-assertion verbs — `assertAI` (judge lane) and `extractAI`
554
- * (extraction lane) — are `Exclude`d from the composed `Action` union so a plan carrying
555
- * one CANNOT typecheck into a cache write. Plan 10's runtime guard at the write site is the
556
- * narrowing proof; this static boundary is the belt-and-suspenders (the 356
557
- * `NonCacheableStepInput` type-level idiom, mirrored at the value shape).
558
- */
559
428
  type CacheablePlannedAction = Exclude<Action, {
560
429
  type: 'assertAI';
561
430
  } | {
562
431
  type: 'extractAI';
563
432
  }>;
564
- /**
565
- * Descriptor-only locator (D-12, 438 D-10/D-11). Identity is the observed role, the exact
566
- * observed name with spacing tidied (numbers and badges kept) and, when the planner stated a
567
- * row the element's row holds, those row words. Never a position, a ref, a selector or
568
- * coordinates: replay re-finds the one element with this identity in a fresh observation.
569
- */
570
433
  interface GroundedLocator {
571
434
  role: string;
572
435
  name: string;
573
436
  row?: string;
574
437
  }
575
- /**
576
- * The cached plan value. `plannedActions` are stored in sanitized (locator-free,
577
- * data-free) form AND statically exclude the AI-assertion verbs (D-08); grounding is carried
578
- * only by `groundedLocator` descriptors so no run-specific ref/selector/coordinate or step
579
- * `data` value ever persists (D-12).
580
- */
581
438
  interface CachedPlanValue {
582
439
  plannedActions: CacheablePlannedAction[];
583
440
  groundedLocator: GroundedLocator[];
584
- verificationOutcome: 'passed' | 'failed';
441
+ completesStep: boolean;
585
442
  }
586
- /**
587
- * Redesigned per-key cache port (D-11). Get/set/invalidate over a branded CacheKey
588
- * — the v1 prefix/index sub-action model is dropped. A storage implementation (Plan
589
- * 05's FsActionCache) implements this interface; runner stays storage-neutral.
590
- */
591
443
  interface ActionPlanCache {
592
444
  get(key: CacheKey): Promise<CachedPlanValue | null>;
593
445
  set(key: CacheKey, value: CachedPlanValue): Promise<void>;
@@ -603,15 +455,10 @@ declare function toGroundedLocator(action: Action, elements: readonly ElementInf
603
455
  interface BuildCachedPlanValueInput {
604
456
  plannedActions: readonly Action[];
605
457
  elements: readonly ElementInfo[];
606
- verificationOutcome: 'passed' | 'failed';
458
+ completesStep: boolean;
607
459
  /** The completing decision's stated target per lane; supplies a locator's row words. */
608
460
  statedTargets?: StatedTargets;
609
461
  }
610
- /**
611
- * Assemble a descriptor-only CachedPlanValue. Planned actions are sanitized of every
612
- * locator binding and step `data` value; grounding is carried solely by the
613
- * descriptor locators so nothing run-specific is ever persisted (D-12 overfit guard).
614
- */
615
462
  declare function buildCachedPlanValue(input: BuildCachedPlanValueInput): CachedPlanValue;
616
463
 
617
464
  declare const ROW_CONTAINER_ROLES: readonly string[];
@@ -620,10 +467,6 @@ declare const ROW_CONTAINER_ROLES: readonly string[];
620
467
  * letter or digit.
621
468
  */
622
469
  declare function wordTokens(text: string | undefined): string[];
623
- /**
624
- * The row text of an element in its observation, or undefined when the element has no row
625
- * container or the container's text is empty (D-02: the row is unknown).
626
- */
627
470
  declare function rowTextOf(element: ElementInfo, elements: readonly ElementInfo[]): string | undefined;
628
471
  /** Whether every stated row word is in the row text (equal, or a prefix of a non-number word). */
629
472
  declare function rowContains(rowText: string, statedRow: string): boolean;
@@ -645,18 +488,15 @@ interface FillRereadMeta {
645
488
  }
646
489
  /** What ended a scroll: the target appeared, the swipe budget ran out, or a boundary signal. */
647
490
  type ScrollEndedBy = 'target-visible' | 'max-swipes' | 'boundary';
648
- /** Outcomes new runs write (436-02, D-24). */
491
+ /** Outcomes new runs write. */
649
492
  declare const SCROLL_OUTCOMES_WRITTEN: readonly ["found", "not-found", "unresolved"];
650
- /** Outcomes only pre-436 runs wrote; still read so persisted metadata stays parseable (D-17). */
651
493
  declare const SCROLL_OUTCOMES_READ_ONLY: readonly ["no-change", "cap"];
652
- /** EXEC-02 scroll outcome block. `endedBy` is absent on pre-436 metadata. */
653
494
  interface ScrollUntilVisibleMeta {
654
495
  swipes: number;
655
496
  reversedOnce: boolean;
656
497
  outcome: (typeof SCROLL_OUTCOMES_WRITTEN)[number] | (typeof SCROLL_OUTCOMES_READ_ONLY)[number];
657
498
  endedBy?: ScrollEndedBy;
658
499
  }
659
- /** EXEC-03 openApp resolution block. */
660
500
  interface OpenAppMeta {
661
501
  resolvedId: string;
662
502
  matchKind: 'exact' | 'fuzzy' | 'explicit';
@@ -665,21 +505,19 @@ interface OpenAppMeta {
665
505
  declare function readFillRereadMeta(actionResult?: ActionResult): FillRereadMeta | undefined;
666
506
  declare function readScrollUntilVisibleMeta(actionResult?: MetadataCarrier): ScrollUntilVisibleMeta | undefined;
667
507
  declare function readOpenAppMeta(actionResult?: ActionResult): OpenAppMeta | undefined;
668
- /** EXEC-05 reportValue answer block (D-01/D-03). Keyed `reportedValue`. */
669
508
  interface ReportedValueMeta {
670
509
  value: string;
671
510
  }
672
- /** EXEC-06 uniqueValue mint block (D-16). Keyed `uniqueValue`. */
673
511
  interface UniqueValueMeta {
674
512
  value: string;
675
513
  prefix: string;
676
514
  }
677
- /** EXEC-07 AI-judgment block (D-05/D-06/D-07/D-09). Keyed `aiJudgment`. */
515
+ /** The AI-judgment block, keyed `aiJudgment`. `unresolved` marks one the model could not make. */
678
516
  interface AiJudgmentMeta {
679
517
  verb: 'assertAI' | 'extractAI';
680
518
  verdict?: boolean;
519
+ unresolved?: true;
681
520
  }
682
- /** EXEC-07 assertValue outcome block (D-10/D-11). Keyed `assertValueOutcome`. */
683
521
  interface AssertValueOutcomeMeta {
684
522
  source: string;
685
523
  op: string;
@@ -687,12 +525,6 @@ interface AssertValueOutcomeMeta {
687
525
  expected?: string;
688
526
  actual?: string | null;
689
527
  }
690
- /**
691
- * The minimal structural input the 360 metadata readers narrow: any ActionResult-like carrier of a
692
- * metadata bag. Broader than `ActionResult` so the seam's loosely-typed sub-action result surfaces
693
- * (which only guarantee an optional `metadata`) narrow cleanly — the defensive idiom returns
694
- * undefined on any shape miss regardless.
695
- */
696
528
  type MetadataCarrier = {
697
529
  metadata?: Record<string, unknown>;
698
530
  };
@@ -706,17 +538,13 @@ interface FillRefusalMeta {
706
538
  cause: 'not-editable' | 'target-not-found' | 'single-line-field';
707
539
  evidence: 'no-editable-signal' | 'no-keyboard-focus' | 'focus-elsewhere' | 'stale-target' | 'text-has-line-breaks';
708
540
  }
709
- /**
710
- * What happened to a requested submit after a fill (437 D-17). Keyed `fillSubmit`. Pre-437 blocks
711
- * carry `sent` alone or `{ sent: false, reason: 'multi-line-field' }` and still read.
712
- */
713
541
  interface FillSubmitMeta {
714
542
  sent: boolean;
715
543
  outcome?: SubmitOutcome;
716
544
  reason?: SubmitReason;
717
545
  detail?: string;
718
546
  }
719
- /** A shell-routed action refused or failed by the driver (437 D-18). Keyed `shellAction`. */
547
+ /** A shell-routed action refused or failed by the driver. Keyed `shellAction`. */
720
548
  interface ShellActionMeta {
721
549
  verb: 'keyevent' | 'openQuickSettings';
722
550
  outcome: 'unavailable' | 'failed';
@@ -724,7 +552,7 @@ interface ShellActionMeta {
724
552
  detail?: string;
725
553
  }
726
554
  declare function readFillRefusalMeta(actionResult?: MetadataCarrier): FillRefusalMeta | undefined;
727
- /** How a fill or clear's read-back compared with the requested text (437 D-06). Keyed `fillVerdict`. */
555
+ /** How a fill or clear's read-back compared with the requested text. Keyed `fillVerdict`. */
728
556
  interface FillVerdictMeta {
729
557
  verb: 'fill' | 'clearText';
730
558
  verdict: FillVerdict;
@@ -814,13 +642,6 @@ interface DocumentScrollOffsets {
814
642
  maxX: number;
815
643
  maxY: number;
816
644
  }
817
- /**
818
- * The offset rule for a gesture that lands on whatever is under the pointer (web wheel, WebView
819
- * touch swipe), over every scroller the gesture may have acted on, as aligned before/after arrays
820
- * (436-18 · D-25). Any member that moved is movement. A boundary needs at least one member with
821
- * range on the swiped axis and every member with range at its extent; a member short of its
822
- * extent, no member with range, or missing, empty or misaligned arrays prove nothing.
823
- */
824
645
  declare function scrollerSetSwipeSignal(direction: Direction, before: readonly DocumentScrollOffsets[] | undefined, after: readonly DocumentScrollOffsets[] | undefined): SwipeSignal;
825
646
  /**
826
647
  * The scroller-set rule over the document scroller alone: a document with no scroll range on the
@@ -861,11 +682,6 @@ type AppResolution = {
861
682
  label?: string;
862
683
  }[];
863
684
  };
864
- /**
865
- * Minimum score a fuzzy top candidate must clear to be launchable. Internal runner constant;
866
- * injectable via ScorerOptions for tests only. Do NOT promote to user-facing config or thread
867
- * through LoopPorts / any config schema (353 K=2 precedent).
868
- */
869
685
  declare const DEFAULT_FUZZY_THRESHOLD = 0.5;
870
686
  /**
871
687
  * Minimum lead the top fuzzy candidate must hold over the runner-up to launch (else ambiguous).
@@ -891,33 +707,13 @@ type MintVerb = (typeof MINT_VERBS)[number];
891
707
  interface ReportValueInput {
892
708
  value: string;
893
709
  }
894
- /**
895
- * Mint the D-01/D-03 `reportValue` success result. The answer rides `metadata.reportedValue`
896
- * (readReportedValueMeta narrows it). NOTE: `value` here is the emission value — the Plan 10 seam
897
- * masks before recording into StepEvidence.reportedValue (masked-before-record, T-360-01).
898
- */
899
710
  declare function mintReportedValue(input: ReportValueInput): ActionResult;
900
711
  /** Emission params for a `uniqueValue` mint (mirrors uniqueValueSchema). */
901
712
  interface UniqueValueInput {
902
713
  prefix: string;
903
714
  }
904
- /**
905
- * The injectable suffix generator (353 K=2 determinism, D-16): a pure `() => string` overridden in
906
- * tests for deterministic output, defaulting to {@link defaultUniqueValueGenerator}.
907
- */
908
715
  type UniqueValueGenerator = () => string;
909
- /**
910
- * Mint the D-16 `uniqueValue` success result: `prefix` + a generated suffix, carried on
911
- * `metadata.uniqueValue` ({ value, prefix }). The generator is injectable for deterministic tests;
912
- * uniqueness is the semantic, so cache replay re-mints fresh. The Plan 10 seam auto-writes the
913
- * minted value into run-scoped working memory keyed by the prefix.
914
- */
915
716
  declare function mintUniqueValue(input: UniqueValueInput, generator?: UniqueValueGenerator): ActionResult;
916
- /**
917
- * Default suffix source (D-16): timestamp + entropy, base36-encoded, non-empty and distinct across
918
- * calls. Injectable so deterministic tests pass a fixed generator instead. Randomness/time IS the
919
- * semantic here (uniqueness), unlike the deterministic app-resolution ladder.
920
- */
921
717
  declare function defaultUniqueValueGenerator(): string;
922
718
 
923
719
  /** Comparator input: the source label, the closed op, the (optional) expected, and the raw actual. */
@@ -939,11 +735,6 @@ interface AssertValueResult {
939
735
  actual?: string | null;
940
736
  passed: boolean;
941
737
  }
942
- /**
943
- * Apply the closed assertValue op deterministically. Type-aware per the Block A pins: gt/lt coerce
944
- * numeric; equals/notEquals/contains compare as strings; isNull passes only on a null read. An
945
- * unread value fails every op (439 D-14). A network read passes only on a matching entry.
946
- */
947
738
  declare function compareAssertValue(input: AssertValueInput): AssertValueResult;
948
739
 
949
740
  /** The most characters of each side `firstDifference` shows. */
@@ -1059,8 +850,7 @@ declare class StepRecordAccumulator {
1059
850
  declare function renderStepRecord(record: VerifierStepRecord): RenderedStepRecord;
1060
851
 
1061
852
  /**
1062
- * A planned action plus the frozen v45 plan envelope (D-09). Structural mirror of
1063
- * core's ActionPlanSchema output; the v45 tool registry (this plan, task 3) produces it.
853
+ * A planned action plus its plan envelope, produced by the tool registry.
1064
854
  */
1065
855
  interface ActionPlan {
1066
856
  reasoning: string;
@@ -1071,45 +861,13 @@ interface ActionPlan {
1071
861
  confidence: number;
1072
862
  stepComplete: boolean;
1073
863
  stepFailed?: boolean;
1074
- /**
1075
- * D-09/GROUND-01 grounding-attempts carriage. When the planning turn grounds the
1076
- * action in-turn (via the injected groundability callback), the gate's §A8
1077
- * GroundingAttempt trail rides here so the resolved-descriptor evidence reaches
1078
- * executeStep (threaded onto StepEvidence in Plan 07). Absent when no grounding
1079
- * callback is injected or the gate recorded no attempts.
1080
- */
1081
864
  groundingAttempts?: GroundingAttempt[];
1082
- /** D-01: the element the planner meant per element lane, judged before dispatch. */
1083
865
  statedTargets?: StatedTargets;
1084
- /**
1085
- * WM-01 write channel (spec §12.15, ratified 2026-07-05). Verbatim facts the planner captured
1086
- * this turn via the `remember[]` plan-field; the loop hands them to the run-scoped
1087
- * `WorkingMemoryStore` (Plan 08 wiring). Absent when the planner captured nothing this turn.
1088
- */
1089
866
  remember?: WorkingMemoryEntry[];
1090
- /**
1091
- * D-09 bulk-loop completion predicate. On a "do X to all" step the planner declares the positive
1092
- * completion predicate here and re-states it each turn; the verifier backstops. Absent for
1093
- * non-bulk steps.
1094
- */
1095
867
  bulkCompletionPredicate?: string;
1096
- /**
1097
- * D-04 infeasible terminal outcome (EXEC-05, spec §12.10). The additive plan-field envelope
1098
- * (358 remember[] precedent) by which a turn declares the step terminally infeasible — the
1099
- * requested capability/screen does not exist in this build. Closed literal union ('infeasible'
1100
- * today, extensible later); machine-distinguishable from a plain `stepFailed`. When set, the
1101
- * loop routes it into a typed StepEvidence.termination block and a distinct verdict outcome
1102
- * (Plan 10 seam). Absent for an ordinary failure.
1103
- */
1104
868
  failureKind?: 'infeasible';
1105
- /**
1106
- * D-04 infeasible reason — required whenever `failureKind` is set (enforced at the
1107
- * toolCallToActionPlan parse boundary). The human-readable why, recorded verbatim in the
1108
- * termination evidence block. Absent unless `failureKind` is present.
1109
- */
1110
869
  failureReason?: string;
1111
870
  }
1112
- /** 436 D-08: debits one planner model call before it is made; false refuses the call. */
1113
871
  interface PlanningCallGate {
1114
872
  tryDebitPlanningCall(): boolean;
1115
873
  }
@@ -1121,18 +879,10 @@ interface PlannerConfig {
1121
879
  interface PlanResult {
1122
880
  plan: ActionPlan;
1123
881
  tokenUsage?: TokenUsage;
1124
- /**
1125
- * Ordered non-action exchanges from this live planning decision (D-01).
1126
- * Absent for cache-replay-produced results, which have no live planning turn.
1127
- */
1128
882
  exchanges?: ToolExchangeEvidence[];
1129
- /**
1130
- * Observed final-response metadata for this live planning decision (D-05/D-08).
1131
- * Absent when the provider exposes no call record or no live model call occurred.
1132
- */
1133
883
  callRecord?: ModelCallRecord;
1134
884
  }
1135
- /** One condition as the verifier judged it (439 D-02, D-10); the runner decides what it counts for. */
885
+ /** One condition as the verifier judged it; the runner decides what it counts for. */
1136
886
  interface ConditionJudgment {
1137
887
  quote: string;
1138
888
  verdict: ConditionVerdict;
@@ -1149,16 +899,12 @@ interface ConditionJudgment {
1149
899
  }[];
1150
900
  reasoning: string;
1151
901
  }
1152
- /** An open dialog as the verifier accounted for it (439 D-16). */
902
+ /** An open dialog as the verifier accounted for it. */
1153
903
  interface DialogAccount {
1154
904
  name: string;
1155
905
  account: 'bears-on-condition' | 'requested' | 'unrelated';
1156
906
  reasoning: string;
1157
907
  }
1158
- /**
1159
- * The verifier's per-condition output. There is no overall success: the runner computes the pass
1160
- * (439 D-10). `verifierError` is set only by the fallback when the model call failed.
1161
- */
1162
908
  interface VerificationResult {
1163
909
  conditions: ConditionJudgment[];
1164
910
  dialogs: DialogAccount[];
@@ -1189,64 +935,16 @@ interface StepContext {
1189
935
  verifierModel: LanguageModel;
1190
936
  modelId?: string;
1191
937
  variables?: Record<string, string>;
1192
- /**
1193
- * The `{{env:NAME}}` bindings that interpolated into `stepInstruction` before this step
1194
- * was planned (PROC-01 · 381 D-03/D-08). DESTINATION: stamped verbatim onto
1195
- * `StepEvidence.interpolatedVariables` at finalize, where the procedure-extraction emit
1196
- * fold reads it to classify a trajectory value slot back to its source binding NAME.
1197
- *
1198
- * Carried VERBATIM end to end — never masked (unlike `variables` above, which is
1199
- * secret-redacted for the planner). See the masking prohibition documented on
1200
- * `StepEvidence.interpolatedVariables`: masking would break the consumer's exact-match
1201
- * classification for email-valued and credential-named bindings.
1202
- *
1203
- * Absent/empty when the step's text interpolated nothing — finalize then stamps nothing.
1204
- */
1205
938
  interpolatedVariables?: readonly InterpolatedVariable[];
1206
- /**
1207
- * D-12/D-13 compatibility slot for a directly supplied learned brief. Reader-backed runs use
1208
- * the structured L1/L2/truncation fields below; buildVolatileTier applies the same hypotheses
1209
- * frame to either source. Empty/undefined omits the learned section entirely.
1210
- */
1211
939
  knowledgeBrief?: string;
1212
- /**
1213
- * BRIF-01 human-authored/sovereign L0 policy material. It is isolated from learned spans so
1214
- * buildContextTier can keep only this byte-stable material in the cached-prefix region.
1215
- */
1216
940
  knowledgePolicyL0?: string;
1217
- /** BRIF-01 learned caution summaries rendered under the volatile hypotheses frame. */
1218
941
  knowledgeBriefL1?: string;
1219
- /** BRIF-01 learned procedure/high-trust-fact summaries rendered in the volatile tier. */
1220
942
  knowledgeBriefL2?: string;
1221
- /** BRIF-01 reader-provided clipping signal; empty/undefined means no signal is rendered. */
1222
943
  knowledgeBriefTruncation?: string;
1223
- /**
1224
- * CR-08 immutable UTC date for planner prompt evidence, captured once per step as
1225
- * `YYYY-MM-DD`. When absent, direct legacy prompt-builder callers retain the current
1226
- * UTC-date fallback. Bound values cross this type unchanged; the production capture
1227
- * boundary validates the closed date form before persistence.
1228
- */
1229
944
  promptDate?: string;
1230
- /**
1231
- * D-12/D-13 working-memory channel (structured turn content). The run-scoped
1232
- * `WorkingMemoryStore` set, injected verbatim as its own turn message by `composeTurnMessages`
1233
- * — the second v2 channel replacing the retired single memory-context string. Phase 358
1234
- * SANCTIONED BREAK (D-12/D-13): this was a plain `string` slot; it is now `WorkingMemoryEntry[]`
1235
- * (no shim, no string overload) so the planner receives the structured verbatim set. Empty
1236
- * array/undefined ⇒ omitted from the turn entirely (empty-slot omission).
1237
- */
1238
945
  workingMemory?: WorkingMemoryEntry[];
1239
- /**
1240
- * D-09 active bulk-completion predicate (per-turn VOLATILE turn content). While a bulk
1241
- * "do X to all" loop is running, the planner's declared positive predicate is re-stated each
1242
- * turn with the re-evaluate/cite-positive-evidence instruction. Absent for non-bulk steps.
1243
- */
1244
946
  bulkCompletionPredicate?: string;
1245
947
  failureContext?: string;
1246
- /**
1247
- * Sub-actions already attempted in this step (multi-action mode), with each outcome and any
1248
- * returned data. Screen change is not recorded here: outcomes decide (HARN-01).
1249
- */
1250
948
  subActionHistory?: {
1251
949
  action: string;
1252
950
  reasoning?: string;
@@ -1257,19 +955,9 @@ interface StepContext {
1257
955
  evidence?: string;
1258
956
  }[];
1259
957
  plannerConfig?: PlannerConfig;
1260
- /** 436 D-08: the step's planning-call meter, bound by the loop before each plan() call. */
1261
958
  planningCallGate?: PlanningCallGate;
1262
959
  screenshot?: Buffer;
1263
- /**
1264
- * Vision-gate prompt note for this run (D-11). Non-empty only for text-only
1265
- * models; injected into the planner prompt when present.
1266
- */
1267
960
  promptNote?: string;
1268
- /**
1269
- * D-13 re-run-after-failure context (LOOP-03). A re-run carries everything (full
1270
- * memory/context, no ablation) plus an explicit run-level flag and the prior
1271
- * attempt's failure summary, surfaced to the planner as prompt context.
1272
- */
1273
961
  isRerun?: boolean;
1274
962
  rerunAttempt?: number;
1275
963
  previousFailureSummary?: string;
@@ -1283,27 +971,53 @@ interface VerifierAuthorContext {
1283
971
  stepNumber?: number;
1284
972
  stepCount?: number;
1285
973
  }
974
+ type AiJudgment = {
975
+ outcome: 'judged';
976
+ verdict: boolean;
977
+ rationale: string;
978
+ } | {
979
+ outcome: 'unresolved';
980
+ reason: string;
981
+ };
982
+ type AssertAiMode = Extract<Action, {
983
+ type: 'assertAI';
984
+ }>['mode'];
985
+ type ExtractField = Extract<Action, {
986
+ type: 'extractAI';
987
+ }>['schema'][number];
988
+ type AiExtraction = {
989
+ outcome: 'extracted';
990
+ fields: Record<string, unknown>;
991
+ } | {
992
+ outcome: 'unresolved';
993
+ reason: string;
994
+ };
1286
995
  interface Verifier {
1287
996
  verify(step: string, before: ScreenState, after: ScreenState, action: Action, screenshot?: Buffer, abortSignal?: AbortSignal, promptNote?: string, bulkCompletionPredicate?: string, authorContext?: VerifierAuthorContext, operationEvidence?: OperationEvidence, record?: VerifierStepRecord): Promise<VerifyResult>;
1288
997
  /**
1289
- * D-05 AI judge lane (EXEC-07, spec §9.6/§12.2) — OPTIONAL so every existing Verifier
1290
- * implementor keeps compiling (D-05: no new port). Plan 09 implements this on LLMVerifier
1291
- * against the injected model handle; the loop (Plan 10 seam) routes `assertAI` through it
1292
- * exactly once per attempt (single-model law). A single-shot judgment over the current
1293
- * observation returning the verdict + rationale. `opts` carries the requested-but-deferred
1294
- * M3/M4 knobs (consensus/video/effort) so demand is recorded (D-09).
1295
- */
1296
- judgeClaim?(claim: string, screen: ScreenState, opts?: Record<string, unknown>): Promise<{
1297
- verdict: boolean;
1298
- rationale: string;
1299
- }>;
1300
- /**
1301
- * D-07 AI extraction lane (EXEC-07, spec §9.6) — OPTIONAL, same no-new-port rationale as
1302
- * `judgeClaim`. Plan 09 implements it on LLMVerifier; the loop routes `extractAI` through it,
1303
- * writes the extracted fields into run-scoped working memory (`scope:'run'`), and degrades
1304
- * `scope:'global'` to the same run-scoped write (D-07). Returns the extracted field map.
1305
- */
1306
- extractData?(query: string, screen: ScreenState, opts?: Record<string, unknown>): Promise<Record<string, unknown>>;
998
+ * One structured judgment of the claim over the current observation. Returns the verdict and
999
+ * rationale, or unresolved with the reason when the model call failed or its answer was not a
1000
+ * valid verdict. An abort rethrows.
1001
+ * multimodal judges from the screen text, plus the screenshot when there is one.
1002
+ * visual judges from the screen text and the screenshot, and is unresolved without a call when
1003
+ * there is no screenshot.
1004
+ * text judges from the screen text only and never sends the screenshot.
1005
+ */
1006
+ judgeClaim?(claim: string, screen: ScreenState, opts: {
1007
+ mode: AssertAiMode;
1008
+ screenshot?: Buffer;
1009
+ abortSignal?: AbortSignal;
1010
+ }): Promise<AiJudgment>;
1011
+ /**
1012
+ * One structured extraction of the declared fields over the current observation. Returns the
1013
+ * fields, or unresolved with the reason when the model call failed or its answer did not match
1014
+ * the declared fields. An abort rethrows.
1015
+ */
1016
+ extractData?(query: string, screen: ScreenState, opts: {
1017
+ fields: readonly ExtractField[];
1018
+ screenshot?: Buffer;
1019
+ abortSignal?: AbortSignal;
1020
+ }): Promise<AiExtraction>;
1307
1021
  }
1308
1022
  type AssertionType = 'text-presence' | 'element-visibility' | 'url-match' | 'element-count' | 'ai';
1309
1023
  interface AssertionInput {
@@ -1414,6 +1128,7 @@ interface HookResult {
1414
1128
  error?: string;
1415
1129
  }
1416
1130
  declare const RUNTIME_IMAGE_MAP: Record<HookRuntime, string>;
1131
+ declare function hookRunnerImage(runtime: HookRuntime, version: string): string;
1417
1132
 
1418
1133
  /** Structurally compatible with model-owner reports; no provider implementation dependency. */
1419
1134
  interface StepModelCallReport {
@@ -1499,94 +1214,37 @@ interface StepModelScopeOptions {
1499
1214
  mask(text: string): string;
1500
1215
  createConsumers(models: Pick<StepModelConsumers, 'plannerModel' | 'verifierModel'>): Pick<StepModelConsumers, 'planner' | 'verifier'>;
1501
1216
  }
1502
- /**
1503
- * The two 356 A5 config digests the run actually keyed on, computed once at the CLI
1504
- * composition root and passed in the resolved {@link RunConfig} (D-20). Carried verbatim
1505
- * into `runStarted`/the handoff so run identity and handoff identity cannot fork.
1506
- */
1507
1217
  interface ConfigDigests {
1508
1218
  suiteConfigDigest: string;
1509
1219
  testConfigDigest: string;
1510
1220
  }
1511
- /**
1512
- * The run-start baseline health-probe outcome (D-04, RCC-02): ONE GET against the web
1513
- * target's base URL, executed at the CLI composition root (the runner bans node:* — only
1514
- * the RESULT crosses this seam). ALL probe failures arrive as values on `error`; a probe
1515
- * never aborts the run. Consumed by the deterministic root-cause classifier's environment
1516
- * branch (run/root-cause.ts).
1517
- */
1518
1221
  interface BaselineProbeResult {
1519
1222
  status?: number;
1520
1223
  elapsedMs: number;
1521
1224
  error?: string;
1522
1225
  }
1523
- /**
1524
- * The JSONL event-log seam (D-05/D-06). BOTH legs are SYNC and fire-and-forget — the bus
1525
- * NEVER awaits telemetry (a synchronous one-line append; D-06/D-07). `append` persists one
1526
- * envelope per emitted event; a throw degrades the bus to memory-only with a single
1527
- * `runWarning` (D-07). `read(fromSeq)` supplies older-than-window envelopes for deep replay.
1528
- * The runner-local `FsEventLog` (Plan 07) implements this against `events.jsonl`.
1529
- */
1530
1226
  interface EventLogPort {
1531
1227
  append(envelope: RunEventEnvelope): void;
1532
1228
  read(fromSeq: number): RunEventEnvelope[];
1533
1229
  }
1534
- /**
1535
- * The per-hook execution options the orchestration threads into the {@link HookExecutorPort}
1536
- * (D-06). `env` is the accumulated-variables + user-env map the orchestrator merges per hook;
1537
- * `secretEnv` is the ALREADY-RESOLVED secret name→value map for container injection — the CLI
1538
- * composition root resolves the SecretStore and the runner never touches the store itself. The
1539
- * secret VALUES double as the output-variable filter (a hook-emitted variable equal to a secret
1540
- * value is dropped). `secretRedactor` redacts stdout/stderr/error; `authState` mounts + injects
1541
- * the active auth state (container-local paths only). Pitfall 3: all sandbox-side
1542
- * redaction/filtering stays inside the impl — the sink mask is additive.
1543
- */
1544
1230
  interface HookExecuteOptions {
1545
1231
  env: Record<string, string>;
1546
1232
  secretEnv: Record<string, string>;
1547
1233
  secretRedactor?: SecretRedactorPort;
1548
1234
  authState?: RuntimeAuthStateConfig;
1549
1235
  }
1550
- /**
1551
- * The D-06 hook-execution seam: a runner-owned port whose only implementation is the
1552
- * runner-local `DockerHookExecutor` (the 356/361 port-in-runner/impl-in-runner-local
1553
- * precedent). `execute` runs ONE hook in the sandboxed container and resolves a
1554
- * {@link HookResult} — a per-hook timeout resolves a FAILED result with an exit-124-style
1555
- * error, NEVER a throw (the orchestration relies on a resolved result to synthesize
1556
- * fail-fast skips). node:child_process / node:fs live behind this port in runner-local;
1557
- * the runner stays storageNeutral (validate:arch is the arbiter).
1558
- */
1559
1236
  interface HookExecutorPort {
1560
1237
  execute(hook: HookDefinition, opts: HookExecuteOptions): Promise<HookResult>;
1561
1238
  }
1562
- /**
1563
- * The durable handoff seam (D-05/D-17). SYNC single-document persist of the one
1564
- * `CompletedRunHandoff` at run end; the runner-local `FsHandoffStore` (Plan 07) writes
1565
- * `handoff.json` beside `events.jsonl`. Failure degrades with a `runWarning`, never gates
1566
- * the verdict (D-07).
1567
- */
1568
1239
  interface HandoffStorePort {
1569
1240
  save(handoff: CompletedRunHandoff): void;
1570
1241
  }
1571
- /**
1572
- * What the post-verdict step is told about the run whose posture it is deciding (404 D-10).
1573
- *
1574
- * The two markers are read off the ASSEMBLED `RunConfig` — the same values `startRun` was handed
1575
- * — never off ambient state, so a gate-run skip (D-08) is decided from the run's own record.
1576
- * Absent means absent: `?: true` carriers are conditionally spread, never written as `undefined`.
1577
- */
1578
1242
  interface PostVerdictStepInput {
1579
1243
  readonly runId: RunId;
1580
1244
  readonly verdict: RunStatus;
1581
1245
  readonly gateRun?: true;
1582
1246
  readonly excludedFromOutcomes?: true;
1583
1247
  }
1584
- /**
1585
- * The step's answer: the posture, and — when the consult could not decide — the reason, by name.
1586
- *
1587
- * A warning rather than a fourth union arm (D-11). `detached` is the honest "nothing will be
1588
- * drained from here", and the cause travels on the `runWarning` channel a surface already reads.
1589
- */
1590
1248
  interface PostVerdictOutcome {
1591
1249
  readonly disposition: PostProcessingDisposition;
1592
1250
  readonly warning?: {
@@ -1594,54 +1252,16 @@ interface PostVerdictOutcome {
1594
1252
  readonly message: string;
1595
1253
  };
1596
1254
  }
1597
- /**
1598
- * The post-verdict step (404 D-10) — the `HandoffStorePort` idiom applied to the ONE decision the
1599
- * shell delays `runFinished` for.
1600
- *
1601
- * WHAT IT MAY DO: the durable enqueue and ONE writer-lease consult. Milliseconds. The runner
1602
- * names no queue, no sqlite and no lease vocabulary (validate:arch storageNeutral) — the HOST
1603
- * supplies the implementation, and the shell only awaits it.
1604
- *
1605
- * WHAT IT MAY NOT DO: gate `done`. A throw, a resolution past
1606
- * {@link POST_VERDICT_STEP_BUDGET_MS}, or an absent port all yield `detached` plus a named
1607
- * `runWarning`, and `runFinished` still publishes last with `bus.close()` behind it (403-03 D-3).
1608
- * The step returns a VALUE and never touches the bus: the shell keeps sole ownership of the
1609
- * terminal sequence.
1610
- *
1611
- * THE SHELL HOLDS NO LEASE. Whatever the step acquired stays with the host, which hands it to its
1612
- * own pump — acquire → pump → release is ONE lease, never re-acquired (RESEARCH Pitfall 3).
1613
- */
1614
1255
  interface PostVerdictPort {
1615
1256
  run(input: PostVerdictStepInput): Promise<PostVerdictOutcome>;
1616
1257
  }
1617
- /**
1618
- * The hard bound the shell races the step against (404 D-10, RESEARCH Pitfall 1).
1619
- *
1620
- * `acquireWriterLease` has contention/deadline semantics of its own, and a busy sqlite enqueue can
1621
- * stall; without a bound here `runFinished`, `done`, the SSE close and the dashboard finalize all
1622
- * slide behind it. Five seconds is generous for "enqueue + one consult" and still far below any
1623
- * drain budget — reaching it means the consult is not going to answer, which is `detached`.
1624
- */
1625
1258
  declare const POST_VERDICT_STEP_BUDGET_MS = 5000;
1626
- /**
1627
- * The D-08 run-artifact persistence seam: a runner-owned port whose only implementation is the
1628
- * runner-local `FsRunArtifactStore` (the 356/361 port-in-runner/impl-in-runner-local precedent).
1629
- * BOTH legs are SYNC and fire-and-forget — the shell NEVER awaits artifact persistence, and a
1630
- * throw degrades with a `runWarning`, never gates the verdict (the event-log/handoff
1631
- * discipline; D-07). The store writes ONE `artifact.json` into the SAME
1632
- * `<root>/runs/<slug(runId)>/` family as `events.jsonl`/`handoff.json` (one self-contained run
1633
- * directory). `stage(document)` persists the config + source snapshot once after `runStarted`;
1634
- * `finalize(patch)` merges terminal errors + the end timestamp before `runFinished` — matching
1635
- * the dashboard DB staged/finalize idiom so a crashed run still leaves a staged artifact. Per the
1636
- * RESEARCH Q5 keep/drop table the FILE artifact keeps config/source/errors only; the top-level
1637
- * `runtime` section is dropped (derived from events/handoff). An absent port is a silent no-op.
1638
- */
1639
1259
  interface RunArtifactStorePort {
1640
1260
  stage(document: RunArtifactStageInput): void;
1641
1261
  finalize(patch: RunArtifactFinalizeInput): void;
1642
1262
  }
1643
1263
  /**
1644
- * Injectable timer seam for the heartbeat + run-budget clocks (spec §2.2 liveness / D-03).
1264
+ * Injectable timer seam for the bus heartbeat, the frame hub's bounds and the post-verdict bound.
1645
1265
  * `schedule(delayMs, fn)` arms a one-shot and returns a cancel handle; `now()` supplies the
1646
1266
  * envelope `ts`. The default impl wraps global setTimeout/clearTimeout (unref'd so it never
1647
1267
  * keeps the process alive); unit pins inject a deterministic fake — no real timers, no watch
@@ -1651,101 +1271,27 @@ interface RunTimerPort {
1651
1271
  schedule(delayMs: number, fn: () => void): () => void;
1652
1272
  now(): number;
1653
1273
  }
1654
- /**
1655
- * One ordered member of the run (D-04). `failFastGroup` scopes today's suite fail-fast: a
1656
- * failed/timed-out member skips the remaining SAME-group members; ungrouped members never
1657
- * fail-fast, preserving the single-test path's run-all behavior.
1658
- *
1659
- * `testIndex` is optional: the shell owns iteration and derives the authoritative index
1660
- * from array position (a caller-supplied value is a hint at most). `name` is REQUIRED so
1661
- * the compiler enforces every descriptor construction site supplies the parsed test name;
1662
- * handoff assembly copies it verbatim onto `PerTestOutcome.testName`.
1663
- */
1664
1274
  interface RunMemberDescriptor {
1665
1275
  testId: string;
1666
1276
  testIndex?: number;
1667
1277
  name: string;
1668
1278
  failFastGroup?: string;
1669
- /**
1670
- * The member test file's WORKSPACE-RELATIVE path — rooted at the config directory,
1671
- * forward-slashed, no leading `./`. REQUIRED since 381-01 (ABRF-02): stable test identity =
1672
- * filePath + testName, copied verbatim onto `PerTestOutcome.filePath` by the handoff assembly —
1673
- * the required field makes the compiler enforce that every descriptor construction site supplies
1674
- * it.
1675
- *
1676
- * 390-08 (CR-02 / D-01): this is IDENTITY, not a file handle. It is deliberately checkout-
1677
- * independent — the same bytes on every machine — because the committed `quarantine.jsonl` keys
1678
- * entries on it and matches with `===`, so an absolute path here would produce a ledger that
1679
- * could only ever apply on the machine that wrote it. Nothing in the run reads bytes off disk
1680
- * through this field; the CLI mints it via core's `workspaceRelativeIdentityPath` and keeps the
1681
- * absolute path on the side for every read.
1682
- */
1683
1279
  filePath: string;
1684
- /**
1685
- * 363 D-01 parity fields (RESEARCH Q1). All OPTIONAL and additive — the shell rides them onto
1686
- * the widened `testStarted` payload so reporters can render the full v1 console/JUnit/wire
1687
- * surface from the bus alone. Suite grouping (`suiteId`/`suiteName`/`suiteIndex`/`suiteTotal`)
1688
- * rides testStarted rather than a suite lifecycle event — the shell stays suite-agnostic and
1689
- * reporters derive suite boundaries by watching the grouping change. `totalSteps` is the
1690
- * per-member parsed step count. The CLI populates these at both startRun sites; absent
1691
- * ⇒ omitted from the payload (no undefined-hole survives JSON round-trip).
1692
- */
1693
1280
  suiteId?: string;
1694
1281
  suiteName?: string;
1695
1282
  suiteIndex?: number;
1696
1283
  suiteTotal?: number;
1697
1284
  totalSteps?: number;
1698
- /**
1699
- * G-428-2 (2026-09-26): the raw authored text of each step, in order. It is the same string
1700
- * member-runner announces at `stepStarted` (`memberStepText`). The shell masks it onto
1701
- * `testStarted.stepTexts`; callers never pre-mask. Absent ⇒ omitted from the payload.
1702
- */
1703
1285
  stepTexts?: readonly string[];
1704
- /**
1705
- * THIS MEMBER'S OWN TARGET's run-start health baseline (D-04, 401-19 WR-04).
1706
- *
1707
- * PER MEMBER, NOT PER RUN, because a run's members may name different targets and a reading taken
1708
- * against one of them says nothing about another. It lived on `RunConfig` and was handed to the
1709
- * classifier for EVERY member, so a 503 observed against member B's target was recorded as member
1710
- * A's environment failure. The CLI composition root fills this in behind the verdict, probing each
1711
- * DISTINCT member URL once; absent means no probe applies to this member — the mobile posture,
1712
- * where the device-session-create failure is the equivalent environment signal, and equally the
1713
- * posture of a member whose target could not be resolved.
1714
- */
1715
1286
  baselineProbe?: BaselineProbeResult;
1716
- /**
1717
- * 402-02 (D-09): members declaring the SAME lane share a mutable execution resource and MUST NOT
1718
- * run concurrently — the bounded member pool runs them strictly one at a time, in index order.
1719
- * Absent means "this member owns everything it touches" and the pool may schedule it freely.
1720
- *
1721
- * This is a PRECONDITION the producer states, never something the shell infers. D-09 requires
1722
- * each concurrent member its own browser/CDP handle; today's suite path does not satisfy that
1723
- * (every member of a suite drives the ONE adapter its suite set up, and `createSuiteLifecycle`
1724
- * admits one active suite at a time), while the direct path does (each direct test constructs
1725
- * its own adapter). A producer that starts handing each member its own session drops the lane
1726
- * and gets concurrency; nothing in the shell has to be re-argued for that to be safe.
1727
- */
1728
1287
  exclusiveLane?: string;
1729
1288
  }
1730
- /**
1731
- * The run-scoped event sink handed to the executor per member test (D-02). The shell binds
1732
- * `runId`/`testIndex`/masking; core curries `stepIndex` via `loopEmitFor`. `stepStarted`
1733
- * fires as a step opens; `loopEmitFor(stepIndex)` yields the {@link LoopEventEmitPort} the
1734
- * loop emits `stepFinalized`/`subActionRecorded` through.
1735
- */
1736
1289
  interface MemberEventSink {
1737
1290
  stepStarted(input: {
1738
1291
  stepIndex: number;
1739
1292
  stepText: string;
1740
1293
  }): void;
1741
1294
  loopEmitFor(stepIndex: number): LoopEventEmitPort;
1742
- /**
1743
- * 363 D-01 parity legs, each routed through its Plan 01 projection + the sink mask (never a raw
1744
- * `bus.publish` from the caller — T-363-06). `hookStarted`/`hookFinished` are emitted by the
1745
- * runner hook orchestration (Plan 04 populates them; `hookFinished` stdout/stderr/error and every
1746
- * `variables` value are masked at the sink, T-363-05). `testRetryScheduled` is emitted by the
1747
- * member-runner retry loop (Plan 10) and marks a per-test accumulation reset for subscribers.
1748
- */
1749
1295
  hookStarted(input: HookStartedPayload): void;
1750
1296
  hookFinished(input: HookFinishedPayload): void;
1751
1297
  testRetryScheduled(input: TestRetryScheduledPayload): void;
@@ -1764,187 +1310,50 @@ interface MemberTestRunContext {
1764
1310
  testIndex: number;
1765
1311
  events: MemberEventSink;
1766
1312
  setEvidenceContext(context: MemberEvidenceContext): void;
1767
- /**
1768
- * CASS-02 run-scoped decision-screenshot byte store (the same instance the shell holds on
1769
- * {@link RunPorts}). The member threads it onto `LoopPorts.evidenceArtifacts`; absent ⇒ a
1770
- * memory-only run with no screenshot persistence.
1771
- */
1772
1313
  evidenceArtifacts?: EvidenceArtifactStorePort;
1773
- /**
1774
- * 403 D-05: declare (or withdraw) this member's live-stream producer. Optional on the SAME
1775
- * `setEvidenceContext` precedent above — the executor pushes a capability the shell knows
1776
- * nothing about, and the shell owns the per-run hub that refcounts it. Passing `undefined`
1777
- * withdraws the declaration (the handle then reads `{ kind: 'none' }`). Absent on the context
1778
- * ⇒ a composition that predates live view; the executor's optional call is a no-op.
1779
- * `fallback` is the labelled snapshot producer the hub switches to when the primary fails to
1780
- * start (428 D-12).
1781
- */
1782
1314
  registerLiveStream?(capability: LiveStreamCapability | undefined, fallback?: LiveStreamCapability): void;
1783
1315
  }
1784
- /**
1785
- * The injected per-test execution port (D-01). The CLI composition root wraps core's
1786
- * `runTest` behind this seam (core depends on runner, so runner can never import core);
1787
- * Phase 363 dissolves the core side of the port when it migrates hooks/variables/reporters.
1788
- * A staged migration, not a workaround — this is the exact seam 363 needs.
1789
- */
1790
1316
  type MemberTestExecutor = (member: RunMemberDescriptor, ctx: MemberTestRunContext) => Promise<TestResult>;
1791
- /**
1792
- * The durable/telemetry/clock seams the run wires behind ports (D-04/D-05). All optional —
1793
- * an absent leg degrades gracefully (no persistence, memory-only telemetry, default clock).
1794
- * Grouped under `ports` so the resolved config keeps the run identity fields flat and the
1795
- * injectable I/O seams together (the Wave-0 `run-shell.test.ts` pins this nesting).
1796
- */
1797
1317
  interface RunPorts {
1798
1318
  handoffStore?: HandoffStorePort;
1799
1319
  eventLog?: EventLogPort;
1800
- /**
1801
- * The D-08 run-artifact store. Staged after `runStarted`, finalized before `runFinished`;
1802
- * absent ⇒ no artifact.json is written (memory-only run, byte-identical pre-363-06 behavior).
1803
- */
1804
1320
  runArtifactStore?: RunArtifactStorePort;
1805
1321
  /**
1806
- * The run-budget clock (D-03). The shell arms `runBudgetMs` on this timer; it is NOT
1807
- * routed into the bus heartbeat (the two clocks stay distinct so firing the injected
1808
- * budget timer is unambiguous — see the shell's timer note).
1322
+ * The clock the post-verdict step's bound and the frame hub's bounds run on. It is NOT routed
1323
+ * into the bus heartbeat: the clocks stay apart so a fake timer drives those bounds
1324
+ * deterministically.
1809
1325
  */
1810
1326
  timer?: RunTimerPort;
1811
- /**
1812
- * The CASS-02 run-scoped decision-screenshot artifact store (Plan 11). The runner-local
1813
- * `FsEvidenceArtifactStore` is constructed run-scoped at the CLI composition root and injected
1814
- * here; the shell hands the same instance to every member. Absent ⇒ no screenshot bytes are
1815
- * persisted (memory-only run, byte-identical pre-Plan-11 behavior).
1816
- */
1817
1327
  evidenceArtifacts?: EvidenceArtifactStorePort;
1818
- /**
1819
- * Where a VIEWER's fault is reported (403 WR-06): a live-frame subscriber that throws during
1820
- * delivery is detached by the hub and the fact lands here. NEVER the bus — the run's permanent
1821
- * transcript must not depend on who happened to be watching (LIVE-03). Same signature as the
1822
- * hub's own option, so the shell forwards rather than adapts; absent ⇒ reported nowhere.
1823
- */
1824
1328
  onSubscriberFault?: (code: string, message: string) => void;
1825
- /**
1826
- * The 404 D-10 post-verdict step, awaited between `runArtifactStore.finalize` and
1827
- * `runFinished`. Absent ⇒ `disposition: 'detached'` with NO warning — a host that composed no
1828
- * step is not an error, it is a host from which nothing will be drained, and the wire says so.
1829
- */
1830
1329
  postVerdict?: PostVerdictPort;
1831
1330
  }
1832
- /**
1833
- * The fully-resolved run configuration `startRun` receives (D-04). The CLI keeps pattern
1834
- * discovery, parsing, config merge, and target/device/model resolution; `startRun` never
1835
- * touches fs or providers (validate:arch stays clean) — hence NO fs/provider/discovery-shaped
1836
- * members here. A future cloud RPC surface reuses this same resolved-config contract.
1837
- *
1838
- * `members`/`ports` shapes are pinned by the Wave-0 `run-shell.test.ts` scaffold.
1839
- */
1840
1331
  interface RunConfig {
1841
1332
  runId: RunId;
1842
1333
  scope: ScopeKey;
1843
1334
  executionContext: ExecutionContext;
1844
1335
  configDigests: ConfigDigests;
1845
1336
  buildOrdinal: number;
1846
- /**
1847
- * D-14 §6 gate-run exclusion copied into the durable completed-run handoff. Only literal
1848
- * true excludes; absence denotes an ordinary counted run and remains absent in JSON.
1849
- */
1850
1337
  excludedFromOutcomes?: true;
1851
- /**
1852
- * D-10 verify-before-present gate-run marker (Phase 384, 2026-07-28) copied into the
1853
- * durable completed-run handoff. A DISTINCT axis from `excludedFromOutcomes` above:
1854
- * C8-ratified, gate runs still feed curation. Only literal true marks a gate run;
1855
- * absence denotes an ordinary run and remains absent in JSON. 384 threads the carrier
1856
- * only — the exclusion semantics land in 388/393.
1857
- *
1858
- * ═══ 2026-08-26 — Phase 404 D-08 amends "gate runs still feed curation" ═══
1859
- *
1860
- * They still feed the FOLD — a gate run's handoff, folded, still emits curation candidates, and
1861
- * the outcome-side exclusion still keys on `excludedFromOutcomes` alone. What changed is the
1862
- * QUEUE: the post-verdict step enqueues NOTHING for a run carrying either marker, so no
1863
- * `analyze-run` row exists for a `write_test` keep-filter probe. The reasons are all about the
1864
- * gate loop rather than about correctness — no strong-model analysis cost per keep-gate
1865
- * iteration, no draft evidence reaching curation through the chain, and no post-processing chips
1866
- * about a run nobody will ever open. The marker still rides the handoff and the payload schema
1867
- * still carries it, because the exclusion is a decision the enqueue takes and not a fact the
1868
- * record forgets.
1869
- */
1870
1338
  gateRun?: true;
1871
1339
  members: readonly RunMemberDescriptor[];
1872
1340
  executor: MemberTestExecutor;
1873
- /**
1874
- * The run's redactor over the secrets its producer read at the run's start (441-12, D-06/D-11).
1875
- * Every bus event, and so `events.jsonl` and the dashboard rows, is masked with it and nothing
1876
- * else. Absent ⇒ the run's events are published as written.
1877
- */
1878
1341
  secretRedactor?: SecretRedactorPort;
1879
- runBudgetMs?: number;
1880
1342
  ports?: RunPorts;
1881
- /**
1882
- * The D-08 config + source artifact snapshot the CLI composition root assembles (the
1883
- * `buildRunArtifactContext` document). Staged verbatim into `artifact.json` after `runStarted`
1884
- * via `ports.runArtifactStore`. Optional — absent ⇒ an empty stage (schema-version-only doc),
1885
- * so the store leg stays a no-op-shaped write and the memory-only path is unchanged.
1886
- */
1887
1343
  runArtifact?: RunArtifactStageInput;
1888
- /**
1889
- * Phase 390 D-16: the quarantined-test set, resolved ONCE at run start by the composition layer
1890
- * (the CLI folds the committed ledger before the first member executes) and threaded in as PLAIN
1891
- * DATA. This is deliberately NOT a port: the runner gains zero new I/O seams and stays
1892
- * storageNeutral, and the disposition is deterministic for the whole run, so a mid-run ledger
1893
- * edit can never retroactively change a running build. Mirrors how `executionContext` is
1894
- * resolved once at run start.
1895
- *
1896
- * Members are matched on `(filePath, name)` — the stable test identity — never `testId`. A match
1897
- * makes the member's failure skippable in the aggregate rule (`deriveAggregateVerdict`) and
1898
- * stamps the disposition beside its truthful outcome in the handoff. Absent or empty ⇒
1899
- * byte-identical pre-390 behavior.
1900
- */
1901
1344
  quarantined?: readonly QuarantineAppliedEntry[];
1902
- /**
1903
- * 436 D-06: the planner limits the producer resolved for this run and the members whose own
1904
- * limits differ, as plain data. Copied verbatim onto the handoff; absent stays absent.
1905
- */
1906
1345
  plannerLimits?: PlannerLimitsRecord;
1907
- /**
1908
- * 402-02 (D-09/D-12): how many members may execute CONCURRENTLY in this run's process. Defaults
1909
- * to 1 — one worker is a plain sequential loop, byte-identical to the pre-402 shell, so nothing
1910
- * changes until a config resolves a higher value. Effective concurrency is
1911
- * `min(members.length, workers)`; values below 1 and non-finite values resolve to 1.
1912
- *
1913
- * CONFIG-RESOLVED, NEVER REQUEST-SUPPLIED (D-12). It arrives on the already-resolved RunConfig
1914
- * the composition root builds, exactly like `runBudgetMs` — `RunsStartInput` carries no
1915
- * concurrency field, so a remote token-holder cannot raise the concurrency of a target whose
1916
- * owner tuned it down (the refused-request-fields posture), and unbounded concurrency
1917
- * (T-402-08) has no reachable input.
1918
- */
1919
1346
  workers?: number;
1920
1347
  }
1921
1348
 
1922
- /**
1923
- * The raw storage-state blob (adapter-produced; e.g. a Playwright storageState object). Opaque
1924
- * to the runner — persisted and returned verbatim, never inspected or masked here (D-14).
1925
- */
1926
1349
  type StorageStateBlob = unknown;
1927
- /**
1928
- * The evidence-safe reference to a persisted storage state (D-14). This — and ONLY this — is
1929
- * what may transit into `StepEvidence`/the handoff: the name plus a one-way fingerprint of the
1930
- * stored blob. The blob itself never leaves the store.
1931
- */
1932
1350
  interface StorageStateReference {
1933
1351
  /** The caller-supplied slot name (as authored; the store slugs it before it becomes a path). */
1934
1352
  name: string;
1935
1353
  /** One-way fingerprint of the stored blob (the 343 `fingerprint()` idiom — identity, not the data). */
1936
1354
  fingerprint: string;
1937
1355
  }
1938
- /**
1939
- * The runner-facing storage-state persistence seam (D-14). A runner-local implementation owns
1940
- * the `.agent-qa/storage-states/` filesystem writes; the loop injects it beside `cache` and
1941
- * records only the returned reference.
1942
- */
1943
1356
  interface StorageStatePort {
1944
- /**
1945
- * Persist the raw storage-state blob under `name` and return the evidence-safe reference.
1946
- * The name is slugged traversal-safe before it becomes a filename (T-360-03).
1947
- */
1948
1357
  save(name: string, state: StorageStateBlob): Promise<StorageStateReference>;
1949
1358
  /**
1950
1359
  * Load the raw blob previously saved under `name`, or `undefined` when no such slot exists
@@ -1986,19 +1395,12 @@ declare function createRecordLedger(input: {
1986
1395
  seedRecords: readonly ServingRecordMetadata[];
1987
1396
  }): ProductionRecordLedger;
1988
1397
 
1989
- /** Compression output — v1's CompressResult shape (Pitfall 9). */
1398
+ /** Compression output, shaped like runner-local's `CompressResult`. */
1990
1399
  interface CompressedScreenshot {
1991
1400
  buffer: Buffer;
1992
1401
  imageWidth: number;
1993
1402
  imageHeight: number;
1994
1403
  }
1995
- /**
1996
- * Screenshot compression + dimension port. The core-side implementation owns
1997
- * `sharp` (storageNeutral forbids it in runner, Pitfall 9). `compress` covers the
1998
- * LLM-planner compression call site; `dimensions` covers the action-space-width
1999
- * metadata fallback done inline via `sharp(screenshot).metadata()` at v1
2000
- * loop.ts:199-201. The loop applies `stampCaptureMode` itself (runner-owned since 352).
2001
- */
2002
1404
  interface ScreenshotCompressor {
2003
1405
  compress(screenshot: Buffer, options: {
2004
1406
  effectiveResolution: number;
@@ -2010,36 +1412,16 @@ interface ScreenshotCompressor {
2010
1412
  height: number;
2011
1413
  }>;
2012
1414
  }
2013
- /**
2014
- * Structural secret-lookup port. The concrete `SecretStore` (moved into runner in
2015
- * this plan, task 2) satisfies it by construction; `resolveSecretTemplatesInValue`
2016
- * consumes it. Named distinctly from the concrete class to avoid a barrel collision.
2017
- */
2018
1415
  interface SecretResolver {
2019
1416
  get(name: string): string | undefined;
2020
1417
  require(name: string): string;
2021
1418
  has(name: string): boolean;
2022
- /**
2023
- * OPTIONAL name enumeration (PROC-02 · 381 D-08). The loop assembles the procedure
2024
- * consult's binding-NAME set from the ports already in scope; secret template names are
2025
- * part of that set so secret-parameterized procedures stay replay-eligible. Names only —
2026
- * the callback receives the value because the concrete `SecretStore.forEachSecret`
2027
- * already carries it, but the loop only ever collects the name; no value crosses the
2028
- * reader port in any form. Absent implementations simply contribute no names.
2029
- */
2030
1419
  forEachSecret?(callback: (name: string, value: string) => void): void;
2031
1420
  }
2032
1421
  /** Structural secret-redactor port — the concrete `SecretRedactor` satisfies it. */
2033
1422
  interface SecretRedactorPort {
2034
1423
  redactString(value: string): string;
2035
1424
  }
2036
- /**
2037
- * Structural run-scoped working-memory port (WM-01 · D-11/D-12). The concrete
2038
- * `WorkingMemoryStore` (working-memory/store.ts) satisfies it by construction; declared
2039
- * structurally here (the SecretResolver naming precedent) so the ports module never imports the
2040
- * concrete class. `capture` writes verbatim entries (registered secrets redacted at capture);
2041
- * `entries` returns the whole set in capture order; `dispose` empties it at run end.
2042
- */
2043
1425
  interface WorkingMemoryPort {
2044
1426
  capture(entries: readonly WorkingMemoryEntry[], ctx?: {
2045
1427
  test?: number;
@@ -2058,21 +1440,10 @@ interface LoopScopedLogger {
2058
1440
  interface LoopLogger {
2059
1441
  createScopedLogger(scope: string): LoopScopedLogger | undefined;
2060
1442
  }
2061
- /**
2062
- * Runner-local structural copy of model's DegradeOptions (D-05/D-07). Runner cannot
2063
- * import the model package, so the shape is duplicated here; Plan 05's cli conformance
2064
- * proof asserts model's `DegradeOptions` structurally matches this. Policy-free: the
2065
- * caller (Phase 355) supplies the concrete budget + pin predicate.
2066
- */
2067
1443
  interface RunnerDegradeOptions {
2068
1444
  budget: number;
2069
1445
  pin?: (message: ModelMessage, index: number) => boolean;
2070
1446
  }
2071
- /**
2072
- * Runner-local structural copy of model's DegradeOutcome (D-09). `ok:true` carries the
2073
- * fitted messages; `ok:false` is the structured cannot-fit outcome (system + final +
2074
- * pinned content alone exceed the budget) — degrade never throws and never violates a pin.
2075
- */
2076
1447
  type RunnerDegradeOutcome = {
2077
1448
  ok: true;
2078
1449
  messages: ModelMessage[];
@@ -2081,13 +1452,6 @@ type RunnerDegradeOutcome = {
2081
1452
  reason: 'pinned-content-exceeds-budget';
2082
1453
  messages: ModelMessage[];
2083
1454
  };
2084
- /**
2085
- * Provider-neutral token-accounting port (D-05/D-07) — the 354↔355 seam. A types-only
2086
- * structural duplicate of model's `TokenAccounting` (accounting/types.ts): runner cannot
2087
- * import model, so the shape is mirrored here and message types are imported from `'ai'`
2088
- * only (never `@ai-sdk/*`, PROVIDER_ORCHESTRATION_ALLOWED). Policy-free — prompt tokens
2089
- * only. This plan declares the seam; Phase 355 wires estimate/degrade consumption.
2090
- */
2091
1455
  interface TokenAccounting {
2092
1456
  estimate(messages: ModelMessage[]): number;
2093
1457
  recordUsage(usage: LanguageModelUsage, messages: ModelMessage[]): void;
@@ -2097,32 +1461,11 @@ interface TokenAccounting {
2097
1461
  };
2098
1462
  degrade(messages: ModelMessage[], options: RunnerDegradeOptions): RunnerDegradeOutcome;
2099
1463
  }
2100
- /**
2101
- * D-02 run-scoped event-emit seam. The loop emits `stepFinalized`/`subActionRecorded` at the
2102
- * moment they occur (live semantics from day one) — the bus assigns `seq` centrally. Both legs
2103
- * are fire-and-forget SYNCHRONOUS void: the loop must NEVER await telemetry (D-02/D-07). Follows
2104
- * the optional-port idiom (masking/workingMemory): structural, optional on {@link LoopPorts},
2105
- * optional-chained at the emit site, never throw-on-absent (D-05 degrade-when-absent). The
2106
- * concrete curry lands at the run shell (`MemberEventSink.loopEmitFor`); the port survives 363's
2107
- * migration unchanged.
2108
- */
2109
1464
  interface LoopEventEmitPort {
2110
- /**
2111
- * 363 D-01: the additive-optional `extra` carries the StepResult-derived
2112
- * `{status, durationMs, error}` the reporters need (RESEARCH Q1 parity). Sourced from the
2113
- * runner `StepResult` at the loop's single terminal `finish()` funnel — NOT fields on the §A8
2114
- * `StepEvidence` DTO (Pitfall 2). `error` is masked at the sink chokepoint (T-363-05). Absent
2115
- * ⇒ the base evidence-only payload, source-compatible with pre-363 callers.
2116
- */
2117
1465
  stepFinalized(evidence: StepEvidence, extra?: {
2118
1466
  status?: StepFinalizedPayload['status'];
2119
1467
  durationMs?: number;
2120
1468
  error?: string;
2121
- /**
2122
- * 405 D-05: the step's measured usage, from the loop's own planner + verifier tally.
2123
- * Absent when nothing was measured — the loop's `tokenUsage()` already answers
2124
- * `undefined` in that case, so absence is produced, never fabricated here.
2125
- */
2126
1469
  tokenUsage?: StepFinalizedPayload['tokenUsage'];
2127
1470
  /** Finished member scope, including late extraction; overrides the legacy loop tally. */
2128
1471
  modelObservations?: ModelUsageObservations;
@@ -2136,14 +1479,6 @@ interface LoopEventEmitPort {
2136
1479
  recordingOffsetMs?: number;
2137
1480
  }): void;
2138
1481
  }
2139
- /**
2140
- * Run-scoped content-addressed evidence artifact store (CASS-02). Storage-neutral: a
2141
- * runner-local `FsEvidenceArtifactStore` owns the sha-keyed blob persistence; the runner
2142
- * declares only the shape. `persistDecisionScreenshot` returns the identity for the exact
2143
- * byte payload so a decision screenshot becomes addressable by `ArtifactRef.sha`; `getBlob`
2144
- * serves those bytes back, letting a host adapter satisfy eval's structurally identical
2145
- * `ArtifactSource` without a runner-to-eval dependency. Both legs are synchronous.
2146
- */
2147
1482
  interface PersistedRecording {
2148
1483
  ref: RecordingRef;
2149
1484
  byteLength: number;
@@ -2161,28 +1496,17 @@ interface EvidenceArtifactStorePort {
2161
1496
  readBlobRange?(sha: string, start: number, end: number): Uint8Array | undefined;
2162
1497
  discardRecording?(stagingPath: string): void;
2163
1498
  }
2164
- /**
2165
- * The member-scoped procedure-flow carry (F-381-51-1 · 381 D-09): the replay position a
2166
- * completed test step hands to the NEXT test step so a committed multi-step flow replays
2167
- * exactly one body step per test step. Transports ONLY the consult match, the parsed body
2168
- * payload, and the cursor — never a pre-resolved ref, never a screen: every carried body
2169
- * step re-earns dispatch through the full fresh-screen descriptor/guard/page-anchor/
2170
- * grounding-gate ladder at its own test step (D-10 — a stored action can never dispatch
2171
- * against a screen its guards did not pass on at that step).
2172
- */
2173
1499
  interface ProcedureFlowCarry {
2174
1500
  match: ProcedureMatch;
2175
1501
  payload: ProcedureBodyPayload;
2176
1502
  nextIndex: number;
2177
1503
  }
2178
- /** 439 D-04: a completed download from an earlier step of this test, labelled by its producer. */
2179
1504
  interface CarriedDownload {
2180
1505
  stepNumber: number;
2181
1506
  /** 1-based position of the producing action in its step. */
2182
1507
  actionIndex: number;
2183
1508
  evidence: DownloadEvidence;
2184
1509
  }
2185
- /** 439 D-04: the latest app clipboard write from an earlier step of this test. */
2186
1510
  interface CarriedClipboard {
2187
1511
  stepNumber: number;
2188
1512
  actionIndex: number;
@@ -2192,83 +1516,24 @@ interface CarriedArtifacts {
2192
1516
  downloads: CarriedDownload[];
2193
1517
  clipboard?: CarriedClipboard;
2194
1518
  }
2195
- /**
2196
- * The runner-owned port bundle the loop executes against — successor to v1's
2197
- * AgentLoopConfig (core types.ts:66-104), minus the D-10 healing/attempt-limit
2198
- * fields and minus the v1 cache-key inputs (those move behind the cache port).
2199
- */
2200
1519
  interface LoopPorts {
2201
1520
  recordingZeroMs?: number;
2202
1521
  adapter: PlatformAdapter;
2203
1522
  planner: Planner;
2204
1523
  verifier?: Verifier;
2205
- /**
2206
- * Redesigned per-key cache port (D-11): get/set/invalidate over a branded CacheKey,
2207
- * descriptor-only value. Plan 05's FsActionCache implements it; injected at the Plan 06
2208
- * CLI composition root. Absent ⇒ every step misses (no cache), never throws (D-05).
2209
- */
2210
1524
  cache?: ActionPlanCache;
2211
- /**
2212
- * D-05 declared decision context for both model roles. Composition roots pass the
2213
- * same profile objects to the planner/verifier constructors and this recording lane;
2214
- * the loop never derives model facts from a model handle. Absent preserves the
2215
- * provider-neutral degrade-when-absent contract.
2216
- */
2217
1525
  modelProfiles?: {
2218
1526
  planner: DeclaredModelProfile;
2219
1527
  verifier?: DeclaredModelProfile;
2220
1528
  };
2221
- /**
2222
- * D-16 once-per-member digest of the complete bound tool surface. It remains a
2223
- * separate optional port because tool attribution is distinct from model identity;
2224
- * absent callers continue without evidence stamping and never throw.
2225
- */
2226
1529
  toolSchemaDigest?: string;
2227
1530
  compressor?: ScreenshotCompressor;
2228
- /** D-05 optional read-only knowledge reader — the loop degrades gracefully when absent. */
2229
1531
  knowledgeReader?: KnowledgeHintReader;
2230
- /**
2231
- * 407 D-13/D-17 (2026-08-29) — the HOST's retrieval rung, resolved ONCE at the composition
2232
- * root by knowledge-local's single `resolveRetrievalRung`, never re-probed per step. It
2233
- * crosses as the schema type because the runner never imports knowledge-local (validate:arch
2234
- * enforces that); a promise because the resolver's embedder probe can cost a model load and
2235
- * overlapping it with run start keeps the probe off the critical path.
2236
- *
2237
- * It describes the ladder the machine was on when this run was served — NOT how this brief was
2238
- * ranked. Absent ⇒ no rung is stamped (D-05 degrade-when-absent); a rejection stamps nothing
2239
- * and never fails a step; and a rung is never stamped onto a step no reader served (D-16 —
2240
- * "no knowledge reader bound is not a rung").
2241
- */
2242
1532
  knowledgeRetrievalRung?: Promise<RecordedRetrievalRung>;
2243
- /**
2244
- * F-381-51-1 · D-09 member-scoped carry cell (the recordLedger shared-mutable-object
2245
- * precedent): the caller owns ONE cell per test member and threads the SAME object into
2246
- * every per-step ports literal. The loop TAKES the carry at step start (reading and
2247
- * immediately emptying the cell) and re-arms it only after the step's verifier accepts a
2248
- * successful replayed step with body steps remaining — take-then-rearm, the D-11 one-shot
2249
- * law extended across the step boundary: every other exit (guard miss, execution failure,
2250
- * verifier rejection, policy denial, step failure, abort, exhaustion) leaves the cell
2251
- * empty. Loop-side state only: never serialized, never recorded into evidence or the
2252
- * handoff, never crosses a test boundary. Absent ⇒ no cursor crosses steps (D-05
2253
- * degrade-when-absent).
2254
- */
2255
1533
  procedureFlow?: {
2256
1534
  carry?: ProcedureFlowCarry;
2257
1535
  };
2258
- /**
2259
- * 439 D-04 member-scoped carry cell, the `procedureFlow` precedent: the caller owns ONE cell per
2260
- * test member and threads the SAME object into every per-step ports literal. The loop renders its
2261
- * items into the step record's carried lines at step start, and at the step's end appends the
2262
- * step's completed downloads and replaces the clipboard with its latest write. Loop-side state
2263
- * only: never serialized, never recorded into evidence or the handoff, never crosses a test
2264
- * boundary. Absent ⇒ nothing carries (the live editor).
2265
- */
2266
1536
  carriedArtifacts?: CarriedArtifacts;
2267
- /**
2268
- * D-02/D-15/D-17 knowledge budgets are computed beside model token accounting at the
2269
- * composition root and arrive here as plain numbers. The provider-neutral loop never derives
2270
- * model ceilings or imports token-accounting policy; absent bindings use provisional floors.
2271
- */
2272
1537
  knowledgeBudgets?: {
2273
1538
  brief: number;
2274
1539
  searchResults: number;
@@ -2276,19 +1541,8 @@ interface LoopPorts {
2276
1541
  readBody: number;
2277
1542
  recordCap: number;
2278
1543
  };
2279
- /** D-21 run-fixed build ordinal copied into ServedBrief attribution when a reader is bound. */
2280
1544
  knowledgeAsOfBuild?: number;
2281
- /**
2282
- * D-17 loop-controlled turn ledger. A composition root that registers Channel-2 tools binds
2283
- * the same object into their closures; the loop owns reset timing and Channel 3 consults it
2284
- * directly. Absent is legal and creates a step-local ledger for Channel-1 accounting only.
2285
- */
2286
1545
  recordLedger?: RecordLedger;
2287
- /**
2288
- * D-11 Channel-2 turn reset owned by the memory-tool wrapper. The loop invokes it only after
2289
- * reseeding the shared distinct-record ledger from the frozen brief, so both ledgers begin the
2290
- * live planning turn from the same boundary.
2291
- */
2292
1546
  beginMemoryTurn?: (scope?: ScopeKey, exposedIds?: readonly RecordId[]) => void;
2293
1547
  /** Consume the successful direct reads served during the current live planning turn. */
2294
1548
  drainMemoryReadTraces?: () => ReadTrace[];
@@ -2309,91 +1563,34 @@ interface LoopPorts {
2309
1563
  captureMode: 'full' | 'textOnly';
2310
1564
  promptNote: string;
2311
1565
  };
2312
- /** Pitfall 8 — setVariable executes via this callback, NOT the adapter. */
1566
+ /** setVariable executes through this callback, not the adapter. */
2313
1567
  onSetVariable?: (name: string, value: string) => void;
2314
- /** Pitfall 1 — path resolution stays core-side, injected pre-resolved into the loop. */
1568
+ /** Path resolution stays core-side; paths arrive pre-resolved. */
2315
1569
  resolveUploadPath?: (rawPath: string) => string;
2316
1570
  abortSignal?: AbortSignal;
2317
1571
  secretStore?: SecretResolver;
2318
1572
  secretRedactor?: SecretRedactorPort;
2319
- /**
2320
- * WM-01 run-scoped working-memory seam (D-11/D-12). The concrete `WorkingMemoryStore` is
2321
- * created at the CLI composition root and injected here; Phase 361 rebinds this exact seam onto
2322
- * `RunSession` (the knowledgeReader idiom). Unbound ⇒ the loop runs memory-less: no capture, an
2323
- * empty served set — it never throws (D-05 degrade-when-absent).
2324
- */
2325
1573
  workingMemory?: WorkingMemoryPort;
2326
- /**
2327
- * D-14 storage-state persistence seam (Phase 360). The runner-local `FsStorageStateStore` is
2328
- * constructed run-scoped at the CLI/dashboard composition roots and injected here; the seam
2329
- * strips the raw blob from the recorded result and records only `{ name, fingerprint }`. Unbound
2330
- * ⇒ a `storageState` action degrades to a §7.1 persistence-unavailable error (never throws, D-05).
2331
- */
2332
1574
  storageState?: StorageStatePort;
2333
- /**
2334
- * D-16 injectable unique-value suffix generator (353 K=2 determinism). Absent ⇒ the seam uses
2335
- * `defaultUniqueValueGenerator` (timestamp + entropy). Tests inject a fixed generator for
2336
- * deterministic minted values; production leaves it unbound.
2337
- */
2338
1575
  uniqueValueGenerator?: UniqueValueGenerator;
2339
- /**
2340
- * D-06 optional pre-prompt blob-guard — bounds a single one-shot structured tool-output
2341
- * value before it lands in the sub-action history / next planning turn. A pure signature
2342
- * (no `ai`/model types, zero arch risk). Composition roots that depend on model may inject
2343
- * model's canonical `guardBlob`; the loop degrades to a runner-local fallback when absent.
2344
- */
2345
1576
  guardBlob?: (value: unknown) => string | undefined;
2346
- /**
2347
- * D-02 run-scoped event-emit seam. Bound by the run shell (per-step curry via
2348
- * `MemberEventSink.loopEmitFor`) so the loop emits `stepFinalized`/`subActionRecorded` live;
2349
- * absent ⇒ the loop runs telemetry-less (no emit), never throws (D-05 degrade-when-absent).
2350
- */
2351
1577
  events?: LoopEventEmitPort;
2352
- /**
2353
- * D-20 real config digests, so the loop can key the cache on what the run actually keyed on
2354
- * (consumed in Plan 08). Type-imported from the run layer; absent ⇒ the existing key material
2355
- * is used unchanged.
2356
- */
2357
1578
  configDigests?: ConfigDigests;
2358
- /**
2359
- * CASS-02 run-scoped decision-screenshot byte store. The shell hands one store instance to
2360
- * every member; the loop mints an `ArtifactRef` for captured screenshot bytes through it.
2361
- * Absent ⇒ a legal memory-only / test-harness state (no persistence), never throws (D-05).
2362
- */
2363
1579
  evidenceArtifacts?: EvidenceArtifactStorePort;
2364
1580
  }
2365
1581
 
2366
1582
  declare function executeStep(stepInstruction: string, ports: LoopPorts, context: StepContext): Promise<StepResult>;
2367
1583
 
2368
- /**
2369
- * Capture-location context stamped onto each entry (D-11): the whole run set is served every
2370
- * turn, so the planner weighs relevance itself — these mark where the entry was captured, they
2371
- * are not a filter rule.
2372
- */
2373
1584
  interface WorkingMemoryProvenanceContext {
2374
1585
  test?: number;
2375
1586
  step?: number;
2376
1587
  }
2377
- /**
2378
- * Run-scoped verbatim working memory: a plain Map keyed by entry key, latest-wins on
2379
- * re-capture (D-12 — one key ⇒ one current value, the OTP-resend reality), whole-set recall in
2380
- * capture order (D-11 — no filtering, no search). Registered secrets are redacted at capture
2381
- * (Pitfall 7 boundary 1); every other value stays verbatim.
2382
- */
2383
1588
  declare class WorkingMemoryStore {
2384
1589
  private readonly redactor?;
2385
1590
  private readonly store;
2386
1591
  constructor(redactor?: SecretRedactorPort | undefined);
2387
- /**
2388
- * Capture verbatim entries. Each item is validated against workingMemoryEntrySchema (closed
2389
- * enums reject unknown kind/provenance at the boundary, V5), its value redacted for registered
2390
- * secrets only, and stamped with the capture location. Re-capturing an existing key overwrites
2391
- * its value (D-12 latest-wins); the key's original capture position is preserved.
2392
- */
2393
1592
  capture(entries: readonly WorkingMemoryEntry[], ctx?: WorkingMemoryProvenanceContext): void;
2394
- /** The whole run-scoped set in capture order (D-11 — no filtering, no search). */
2395
1593
  entries(): WorkingMemoryEntry[];
2396
- /** Empty the store at run end (WM-02 disposal; the redacted flush is composed elsewhere). */
2397
1594
  dispose(): void;
2398
1595
  }
2399
1596
 
@@ -2405,27 +1602,15 @@ interface AgentTimeoutAbortReason {
2405
1602
  message: string;
2406
1603
  }
2407
1604
  declare function createTimeoutAbortReason(scope: AgentAbortScope, timeoutMs: number): AgentTimeoutAbortReason;
2408
- /**
2409
- * True iff `message` is the message createTimeoutAbortReason('test', ms) mints for
2410
- * some ms — the D-16 member-timeout signal. Rejects the 'step'-scope variant (a step
2411
- * timeout is an ordinary failure) and any arbitrary text.
2412
- *
2413
- * WHY match on the message string: the AgentTimeoutAbortReason object does NOT survive
2414
- * onto TestResult — the only trace that reaches verdict derivation is a failed step
2415
- * whose `error` equals this minted message (RESEARCH Q3). This matcher is the one place
2416
- * that knowledge lives, exported beside the sole mint site so the format stays
2417
- * single-sourced.
2418
- */
2419
1605
  declare function isTestTimeoutMessage(message: string): boolean;
2420
1606
  declare function getTimeoutAbortReason(signal: AbortSignal | undefined): AgentTimeoutAbortReason | undefined;
2421
1607
  declare function withAbort<T>(promise: Promise<T>, signal: AbortSignal | undefined): Promise<T>;
2422
1608
 
2423
- type ToolCategory = 'action' | 'file' | 'network';
1609
+ type ToolCategory = 'action';
2424
1610
  interface ToolDefinition<T extends z.ZodType = z.ZodType> {
2425
1611
  id: string;
2426
1612
  type: string;
2427
1613
  surface: Surface;
2428
- exposed?: boolean;
2429
1614
  description: string;
2430
1615
  category: ToolCategory;
2431
1616
  schema: T;
@@ -2447,45 +1632,14 @@ declare class ToolRegistry {
2447
1632
  }
2448
1633
  declare const defaultRegistry: ToolRegistry;
2449
1634
 
2450
- /**
2451
- * K — the per-turn non-action tool-call budget (D-06/D-10). Channel 2's designed
2452
- * search→read sequence needs two calls, and one retry pair must fit in the same turn.
2453
- * This remains an internal provisional constant, injectable via
2454
- * ExecutePlanningTurnOptions.budget for tests only. Do NOT promote it to user-facing
2455
- * config or thread it through LoopPorts / any config schema.
2456
- */
2457
1635
  declare const DEFAULT_NON_ACTION_TOOL_BUDGET = 4;
2458
- /**
2459
- * A caller-registered non-action tool. `tool` is the `ai` definition merged into the
2460
- * always-send-all slice; `execute` runs the call and returns a JSON-serializable
2461
- * result appended to the conversation as a tool message. Zero of these ship in 353;
2462
- * tests register fakes to exercise the machinery (D-07).
2463
- */
2464
1636
  interface NonActionToolHandler {
2465
1637
  tool: Tool;
2466
1638
  execute(args: Record<string, unknown>): Promise<unknown> | unknown;
2467
1639
  }
2468
1640
  type NonActionToolMap = Record<string, NonActionToolHandler>;
2469
- /**
2470
- * An ordered record of one executed non-action tool call within a planning turn
2471
- * (§B1). Exchanges persist on SubActionEvidence for successful decisions (INST-01,
2472
- * D-01) and PlanningFailureEvidence for failed turns (D-03).
2473
- */
2474
1641
  type ToolExchange = ToolExchangeEvidence;
2475
1642
  type PlanningTurnFailureReason = 'no_action_tool_called' | 'non_action_tool_budget_exhausted' | 'ungroundable_action' | 'planning_limit_reached';
2476
- /**
2477
- * The in-turn groundability verdict for a parsed action (D-09). Returned by the
2478
- * injected `groundability` callback the caller (LLMPlanner) builds from the Plan-04
2479
- * grounding gate + the in-scope screenState — the tool-loop stays gate-agnostic and
2480
- * NEVER imports `grounding/` itself.
2481
- *
2482
- * `ok: true` may optionally carry the gate's fully-grounded execution-shape `action`
2483
- * (ref, never a descriptor) and its §A8 `attempts` trail; when present the turn swaps
2484
- * them onto the returned plan so the resolved action + evidence ride to executeStep.
2485
- * When omitted (e.g. a test seam that only signals groundability) the parsed plan is
2486
- * returned unchanged. `ok: false` carries the §7.1 error text injected back into the
2487
- * SAME conversation as an error-text tool result for the model's one-shot correction.
2488
- */
2489
1643
  type GroundabilityResult = {
2490
1644
  ok: true;
2491
1645
  action?: Record<string, unknown>;
@@ -2495,7 +1649,7 @@ type GroundabilityResult = {
2495
1649
  ok: false;
2496
1650
  message: string;
2497
1651
  };
2498
- /** The injected groundability callback: parsed action → groundability verdict (D-09). */
1652
+ /** The injected groundability callback: parsed action → groundability verdict. */
2499
1653
  type GroundabilityCallback = (plan: ActionPlan) => GroundabilityResult;
2500
1654
  interface PlanningTurnSuccess {
2501
1655
  ok: true;
@@ -2517,66 +1671,30 @@ interface ExecutePlanningTurnOptions {
2517
1671
  model: LanguageModel;
2518
1672
  /** Registry backing toolCallToActionPlan (the turn's termination projection). */
2519
1673
  registry: ToolRegistry;
2520
- /** The full v45 action slice (buildTools output) — always sent (always-send-all). */
1674
+ /** The full action slice from buildTools, always sent. */
2521
1675
  actionTools: ToolSet;
2522
- /**
2523
- * System prompt — a single string, or the Phase 355 [stable, context, volatile]
2524
- * tier array the caller assembles (D-15). Passed through to generateText untouched;
2525
- * the tool-loop applies no clamp/degrade policy of its own.
2526
- */
2527
1676
  system: string | Array<SystemModelMessage>;
2528
1677
  /** The initial user message(s): text and optional image, built by the caller. */
2529
1678
  messages: ModelMessage[];
2530
- /** Caller-registered non-action tools. Empty in production (D-07). */
1679
+ /** Caller-registered non-action tools. Empty in production. */
2531
1680
  nonActionTools?: NonActionToolMap;
2532
- /** K override for tests (D-06). Defaults to DEFAULT_NON_ACTION_TOOL_BUDGET. */
1681
+ /** K override for tests. Defaults to DEFAULT_NON_ACTION_TOOL_BUDGET. */
2533
1682
  budget?: number;
2534
- /**
2535
- * D-09 in-turn grounding feedback. When present, a parsed action call is grounded by
2536
- * this injected callback after `toolCallToActionPlan` succeeds. A failure appends the
2537
- * §7.1 error text as an error-text tool result in the SAME conversation with EXACTLY
2538
- * ONE retry (a turn-local one-shot flag, never a counter — LOOP-02); a second
2539
- * consecutive grounding failure returns a structured `'ungroundable_action'` failure.
2540
- * The retry neither consumes nor bypasses the ≤K non-action budget (Pitfall 8). When
2541
- * absent the turn behaves exactly as the 353 bounded loop (back-compat within phase).
2542
- */
2543
1683
  groundability?: GroundabilityCallback;
2544
- /**
2545
- * Dynamic output cap (CTXB-04) computed by the caller's clamp helper and passed
2546
- * through to generateText. `undefined` is a valid no-op passthrough — the tool-loop
2547
- * computes no clamp of its own (D-15/Pitfall 5).
2548
- */
2549
1684
  maxOutputTokens?: number;
2550
- /**
2551
- * Optional sampling parameters applied at the model call site (D-10/D-11). Every
2552
- * field is optional and absence preserves the provider default. `maxOutputTokens`
2553
- * is deliberately excluded because the output ceiling remains clamp-owned.
2554
- */
2555
1685
  sampling?: SamplingParams;
2556
- /**
2557
- * 436 D-08: when bound, every model call of the turn is debited before it is made; a refused
2558
- * debit ends the turn with `planning_limit_reached` and no model call.
2559
- */
2560
1686
  planningCallGate?: PlanningCallGate;
2561
1687
  abortSignal?: AbortSignal;
2562
1688
  logger?: LoopScopedLogger;
2563
1689
  }
2564
1690
  declare function executePlanningTurn(options: ExecutePlanningTurnOptions): Promise<PlanningTurnResult>;
2565
1691
 
2566
- /**
2567
- * Structured planning-turn failure used to preserve failed-turn evidence across
2568
- * the planner's throw-based public contract (D-03).
2569
- */
2570
1692
  declare class PlanningTurnError extends Error {
2571
1693
  readonly reason: PlanningTurnFailureReason;
2572
1694
  readonly exchanges: ToolExchangeEvidence[];
2573
1695
  readonly callRecord?: ModelCallRecord;
2574
1696
  constructor(reason: PlanningTurnFailureReason, message: string, exchanges: ToolExchangeEvidence[], callRecord?: ModelCallRecord);
2575
1697
  }
2576
- /**
2577
- * 436 D-08/D-12: the step's planning-turn limit refused a planner model call. Never a planning
2578
- * failure; the loop ends the step with its typed limit stop.
2579
- */
2580
1698
  declare class PlanningLimitReachedError extends Error {
2581
1699
  readonly exchanges: ToolExchangeEvidence[];
2582
1700
  readonly callRecord?: ModelCallRecord;
@@ -2647,7 +1765,7 @@ declare const VerificationResultSchema: z.ZodObject<{
2647
1765
  isAppError: z.ZodBoolean;
2648
1766
  reasoning: z.ZodString;
2649
1767
  }, z.core.$strip>;
2650
- /** Closed judgment schema — a boolean verdict + rationale, never free text (D-06). */
1768
+ /** Closed judgment schema: a boolean verdict and a rationale, never free text. */
2651
1769
  declare const AiJudgmentResultSchema: z.ZodObject<{
2652
1770
  verdict: z.ZodBoolean;
2653
1771
  rationale: z.ZodString;
@@ -2660,25 +1778,29 @@ declare class LLMVerifier implements Verifier {
2660
1778
  verify(step: string, before: ScreenState, after: ScreenState, action: Action, screenshot?: Buffer, abortSignal?: AbortSignal, promptNote?: string, bulkCompletionPredicate?: string, authorContext?: VerifierAuthorContext, operationEvidence?: OperationEvidence, record?: VerifierStepRecord): Promise<VerifyResult>;
2661
1779
  private runVerification;
2662
1780
  /**
2663
- * D-05/D-06/D-09 AI judge lane. A SINGLE structured call over the current observation that
2664
- * returns the verdict + rationale. `opts` carries the requested-but-deferred M3/M4 knobs
2665
- * (consensus/video/effort) so demand is visible (D-09) — accepted, never honored, never an
2666
- * error; the loop records them into the AiJudgment evidence block. Empty/overflow model output
2667
- * degrades to a structured `verdict:false` failure (the verify() never-crash posture) — abort
2668
- * is the only rethrow.
2669
- */
2670
- judgeClaim(claim: string, screen: ScreenState, opts?: Record<string, unknown>): Promise<{
2671
- verdict: boolean;
2672
- rationale: string;
2673
- }>;
2674
- /**
2675
- * D-07 AI extraction lane. A SINGLE structured call whose output schema is derived from the
2676
- * extractAI request's declared field list (each field a string). Returns the extracted field
2677
- * map; the loop writes it into run-scoped working memory and degrades a `scope:'global'`
2678
- * request to the same run-scoped write (D-07 — no durable-memory port in M1). Empty/overflow
2679
- * output degrades to an empty extraction (never a throw) — abort is the only rethrow.
2680
- */
2681
- extractData(query: string, screen: ScreenState, opts?: Record<string, unknown>): Promise<Record<string, unknown>>;
1781
+ * One structured judgment of the claim over the current observation. Returns the verdict and
1782
+ * rationale, or unresolved when the model call failed or its answer was not a valid verdict.
1783
+ * text never attaches the screenshot; visual with no screenshot is unresolved without a call.
1784
+ * An abort rethrows.
1785
+ */
1786
+ judgeClaim(claim: string, screen: ScreenState, opts: {
1787
+ mode: AssertAiMode;
1788
+ screenshot?: Buffer;
1789
+ abortSignal?: AbortSignal;
1790
+ }): Promise<AiJudgment>;
1791
+ /**
1792
+ * One structured extraction of the declared fields over the current observation. Returns every
1793
+ * declared field with its declared type, null where the screen does not show it, and object
1794
+ * text decoded to an object. Unresolved when the model call failed, or when its answer did not
1795
+ * match the declared fields: a wrong type, a missing field, or object text that is not a JSON
1796
+ * object. A declared type outside string, number, boolean, array and object is unresolved the
1797
+ * same way, with no model call. Nothing is converted. An abort rethrows.
1798
+ */
1799
+ extractData(query: string, screen: ScreenState, opts: {
1800
+ fields: readonly ExtractField[];
1801
+ screenshot?: Buffer;
1802
+ abortSignal?: AbortSignal;
1803
+ }): Promise<AiExtraction>;
2682
1804
  private runStructured;
2683
1805
  }
2684
1806
 
@@ -2718,20 +1840,8 @@ declare class VariableStore {
2718
1840
 
2719
1841
  interface InterpolationWithProvenance {
2720
1842
  text: string;
2721
- /**
2722
- * The bindings that actually resolved, one entry per DISTINCT name in first-occurrence
2723
- * order. Unresolved patterns and the skipped `{{secret:...}}` template contribute
2724
- * nothing. Values are recorded VERBATIM — see the masking prohibition on
2725
- * `StepEvidence.interpolatedVariables` (masking here would break the emit fold's
2726
- * exact-match classification and reintroduce G-381-3).
2727
- */
2728
1843
  substitutions: InterpolatedVariable[];
2729
1844
  }
2730
- /**
2731
- * The single replacement implementation (PROC-01 · 381 D-03/D-08). Produces byte-identical
2732
- * text to the historical `interpolateVariables` while reporting WHICH binding names
2733
- * produced it, so the name survives the pre-planning interpolation seam into StepEvidence.
2734
- */
2735
1845
  declare function interpolateVariablesWithProvenance(template: string, store: VariableStore): InterpolationWithProvenance;
2736
1846
  declare function interpolateVariables(template: string, store: VariableStore): string;
2737
1847
  interface UnresolvedTemplate {
@@ -2759,65 +1869,14 @@ declare class LLMVariableExtractor implements VariableExtractor {
2759
1869
  }
2760
1870
 
2761
1871
  type PromptPlatform = 'web' | 'android' | 'ios';
2762
- /**
2763
- * v1 token estimate (chars/4). No semantic change (D-04); the TokenAccounting port
2764
- * lands in Phase 355. Exported here because the prompts module is the token estimate's
2765
- * sole runner-side consumer.
2766
- */
2767
1872
  declare function estimateTokens(text: string): number;
2768
1873
  declare function buildSystemPrompt(platform?: PromptPlatform): string;
2769
- /**
2770
- * CONTEXT tier (D-04): the app-under-test / suite / test framing. Byte-stable per run,
2771
- * so it sits inside the cached prefix and carries the single Anthropic `cache_control`
2772
- * ephemeral breakpoint (D-05) — everything at or above this message (stable + context)
2773
- * is cached once per run at zero incremental cost. A non-Anthropic provider never parses
2774
- * the `anthropic` namespace, so `providerOptions` is a transparent no-op there.
2775
- */
2776
1874
  declare function buildContextTier(context: StepContext): SystemModelMessage;
2777
- /**
2778
- * Render the knowledge brief (the volatile-tier ingredient, D-12) framed as hypotheses
2779
- * to weigh against the live observation — never as commands (spec §5, L3). Returns ''
2780
- * when the brief slot is unbound/empty so the volatile tier omits the section entirely
2781
- * (no 'Knowledge brief' header, no dangling blank line).
2782
- */
2783
1875
  declare function renderBriefAsHypotheses(brief?: string): string;
2784
- /**
2785
- * VOLATILE tier (D-04/D-07): the knowledge brief (empty until M2 binds a
2786
- * KnowledgeHintReader impl, D-12) plus a DATE-GRANULARITY timestamp. Date precision only
2787
- * — minute/second precision would bust the KV cache (D-07). Carries NO cache breakpoint;
2788
- * it sits after the breakpoint that lives on the context tier.
2789
- */
2790
1876
  declare function buildVolatileTier(context: StepContext): SystemModelMessage;
2791
- /**
2792
- * Per-turn content composer (CTXB-01/CTXB-02 — D-08/D-09/D-12). Decomposes the
2793
- * per-turn state into a small ordered set of turn messages so 354's degrade() can pin
2794
- * and proportionally truncate at message granularity rather than shredding one blob.
2795
- * Order: re-run context → previous steps → sub-action history → failure context →
2796
- * working memory → latest observation → current instruction (FINAL). Empty slots are
2797
- * omitted entirely — no blank/degenerate message is pushed (D-12).
2798
- *
2799
- * PIN CONTRACT (D-08): the last two messages are the pinned pair — the latest
2800
- * OBSERVATION (second-to-last) and the CURRENT INSTRUCTION (last, verbatim). The caller
2801
- * (Plan 05) protects exactly these two via degrade's `pin`; every earlier message is
2802
- * trim-eligible. All per-turn state lives here and NEVER in the cached system tiers.
2803
- */
2804
1877
  declare function composeTurnMessages(context: StepContext, screenState: ScreenState): ModelMessage[];
2805
1878
  declare function formatAction(action: Action): string;
2806
- /**
2807
- * VERIFIER stable tier (CTXB-01 / D-11): the byte-stable verdict-identity block, the verifier's own
2808
- * cached prefix, identical on every verification call. 439 (D-01, D-05, D-06, D-11, D-18) states
2809
- * the per-condition contract here: split the step into quoted conditions, judge each from cited
2810
- * current evidence, and leave the pass to the runner. Arg-less: no per-call inputs; the
2811
- * screenshot-analysis paragraph rides only a per-call turn that has an image (D-19).
2812
- */
2813
1879
  declare function buildVerifierStableTier(): string;
2814
- /**
2815
- * VERIFIER per-call turn content (D-11). Only the per-verification-call bytes: the step
2816
- * goal, the enriched action description, and the before/after screen states (+ the
2817
- * optional screenshot note and prompt note). The byte-stable verdict-identity/approach
2818
- * prose now lives in `buildVerifierStableTier()` (the verifier's own cached prefix), so
2819
- * it is no longer re-emitted per call.
2820
- */
2821
1880
  declare function buildVerificationPrompt(step: string, beforeState: ScreenState, afterState: ScreenState, action: Action, hasScreenshot?: boolean, promptNote?: string, bulkCompletionPredicate?: string, authorContext?: VerifierAuthorContext, operationEvidence?: OperationEvidence, record?: VerifierStepRecord): string;
2822
1881
  declare function buildAssertionPrompt(assertion: AssertionInput, screenState: ScreenState): string;
2823
1882
  declare function buildExtractionPrompt(input: ExtractorInput, screenState: ScreenState): string;
@@ -2828,10 +1887,6 @@ type OriginStampedEntry = IndexEntry & {
2828
1887
  origin?: 'app-observed' | 'user';
2829
1888
  originClass?: 'agent-observed' | 'agent-verified' | 'import' | 'user';
2830
1889
  };
2831
- /**
2832
- * Cap learned summaries using JavaScript String.length (UTF-16 code units), the
2833
- * BRIF-01 length contract. The ellipsis is part of the 140-code-unit maximum.
2834
- */
2835
1890
  declare function renderCautionSummary(summary: string): string;
2836
1891
  declare function tierForEntry(entry: OriginStampedEntry): string;
2837
1892
  /** Deterministic provisional cost of the exact text handed to the planner. */
@@ -2864,53 +1919,20 @@ interface RecordSubActionInput {
2864
1919
  /** The planner's reasoning/plan string for this sub-action. */
2865
1920
  plan: string;
2866
1921
  plannedAction: Action$1;
2867
- /**
2868
- * The FULL observed ScreenState the sub-action was planned against (D-15). Pitfall 3:
2869
- * v1 stored only the tree string — the forbidden shape. elements + refMap ride along.
2870
- */
2871
1922
  stateBefore: ScreenState;
2872
1923
  stateAfter?: ScreenState;
2873
- /**
2874
- * The execution result as the schema ActionResult (screenshot may be present here as
2875
- * bytes; it is structurally excluded by toRecordedActionResult before storage — the
2876
- * type-level screenshot-never guarantee, T-353-06). annotation is produced via
2877
- * collapseAnnotation.
2878
- */
2879
1924
  result: ActionResult$1;
2880
- /** v1 per-sub-action cache flag; folded per step by foldCacheStatus at finalize. */
1925
+ /** Per-sub-action cache flag; folded per step by foldCacheStatus at finalize. */
2881
1926
  cached?: boolean;
2882
- /**
2883
- * The §A8 grounding evidence for this sub-action (GROUND-02): the resolved descriptor
2884
- * plus the per-rung attempt trail (turn gate on the live path, replay resolution on the
2885
- * cache path, re-ground heal entries on the D-10 path). Present only when the action
2886
- * carried an element field; the loop redacts the descriptor BEFORE passing it here so a
2887
- * pre-redaction descriptor never reaches evidence (T-357-02a, the redact-before-record
2888
- * ordering). Typed via the schema DTO — no runner-local mirror (353 evidence-by-construction).
2889
- */
2890
1927
  grounding?: SubActionEvidence['grounding'];
2891
- /**
2892
- * The §A8 decision-screenshot ArtifactRef (CASS-02): the identity of the exact final image
2893
- * bytes the planner saw for this live decision, minted by the run-scoped artifact store.
2894
- * Absent on cache-served, text-only, unbound-store, or failed-store paths — never fabricated.
2895
- */
2896
1928
  decisionScreenshotRef?: SubActionEvidence['decisionScreenshotRef'];
2897
1929
  /**
2898
1930
  * Auxiliary §A8 ArtifactRefs already reserved by the schema DTO. Copied verbatim (order and
2899
1931
  * identity preserved) so the recorder never drops artifact references present on the input.
2900
1932
  */
2901
1933
  artifactRefs?: SubActionEvidence['artifactRefs'];
2902
- /**
2903
- * Ordered exchanges from this live planning decision (D-01). The loop masks every
2904
- * string leaf BEFORE passing them here (T-360-01); the recorder never sees raw values.
2905
- * Present, possibly empty, for live turns and absent for cache replay.
2906
- */
2907
1934
  exchanges?: ToolExchangeEvidence[];
2908
- /**
2909
- * Final-response enrichment for this live decision (D-05/D-08). The loop passes it
2910
- * conditionally; structural absence means no live call record was available.
2911
- */
2912
1935
  callRecord?: ModelCallRecord;
2913
- /** 436 D-22: what the action produced outside the page, already masked by the loop. */
2914
1936
  operationEvidence?: SubActionEvidence['operationEvidence'];
2915
1937
  healedDispatch?: SubActionEvidence['healedDispatch'];
2916
1938
  }
@@ -2918,17 +1940,6 @@ declare class EvidenceRecorder {
2918
1940
  private readonly subActions;
2919
1941
  private readonly cacheFlags;
2920
1942
  private servedBrief;
2921
- /**
2922
- * KREV-02 · D-13: the serve-time retrieval trace, recorded BESIDE `servedBrief` and never
2923
- * inside it. `ServedBrief` feeds `computeBriefDigest`, so a trace channel within it would have
2924
- * rewritten every cassette and acceptance digest in the tree; a sibling field leaves those
2925
- * bytes untouched, which `evidence-trace.test.ts` proves by digest equality rather than by
2926
- * asserting that nobody edited the brief.
2927
- *
2928
- * Channel 1 is REPLACED on each record (a step replans against the SAME frozen brief, so
2929
- * appending would duplicate its attributions), while Channel 3 APPENDS — exactly mirroring how
2930
- * `servedBrief.channel1` and `servedBrief.channel3` themselves behave.
2931
- */
2932
1943
  private channel1Trace?;
2933
1944
  private readonly channel3TraceLines;
2934
1945
  private readonly channel3Truncated;
@@ -2946,26 +1957,10 @@ declare class EvidenceRecorder {
2946
1957
  private verdictSource?;
2947
1958
  private planSource?;
2948
1959
  private cacheMiss?;
2949
- /** D-06 run-declared planner context, copied onto every finalized step when bound. */
2950
1960
  private readonly modelProfile?;
2951
- /** D-07 verifier identity copied beside every finalized verdict when bound. */
2952
1961
  private readonly verifierIdentity?;
2953
- /** D-16 once-per-member bound-surface digest copied onto every finalized step. */
2954
1962
  private readonly toolSchemaDigest?;
2955
- /**
2956
- * 407 D-13: the HOST's retrieval rung at serve time, handed in by the composition root and
2957
- * copied onto every finalized step. It sits BESIDE `servedBrief` for the same reason
2958
- * `retrievalTrace` does — `computeBriefDigest` keys cassettes and acceptance evidence on the
2959
- * brief's bytes, so a rung channel inside the brief would invalidate every brief ever served.
2960
- * The recorder never resolves it: a run's rung is a fact about serve time, not a live probe.
2961
- */
2962
1963
  private readonly retrievalRung?;
2963
- /**
2964
- * D-02 single sub-action chokepoint (Plan 361-08). When bound, invoked at the END of
2965
- * every {@link recordSubAction} append with the recorded evidence and its index — so all
2966
- * five loop call sites emit `subActionRecorded` through ONE seam, never per-call-site.
2967
- * Optional-chained: unbound ⇒ the recorder is byte-identical to today (never throws, D-05).
2968
- */
2969
1964
  private readonly onSubActionRecorded?;
2970
1965
  constructor(options?: {
2971
1966
  servedBrief?: ServedBrief;
@@ -2999,11 +1994,6 @@ declare class EvidenceRecorder {
2999
1994
  get subActionCount(): number;
3000
1995
  /** Append a §A8 SubActionEvidence. Returns its index (for attachStateAfter). */
3001
1996
  recordSubAction(input: RecordSubActionInput): number;
3002
- /**
3003
- * Snapshot the run-scoped working-memory set served to this step's planning turns
3004
- * (WM-01, §12.15). The loop passes the values ALREADY masked (the loop's `recordMask`, Pitfall
3005
- * 7 boundary 3) — recorded BESIDE the brief, never inside `servedBrief`.
3006
- */
3007
1997
  recordWorkingMemory(entries: WorkingMemoryEntry[]): void;
3008
1998
  /**
3009
1999
  * Record the real deterministic Channel-1 brief served to this step. The recording type is the
@@ -3015,138 +2005,43 @@ declare class EvidenceRecorder {
3015
2005
  asOfBuild: number;
3016
2006
  budget: number;
3017
2007
  block: BriefBlock;
3018
- /**
3019
- * D-16's last hop, made structural. The trace is a REQUIRED parameter, so the only way to
3020
- * persist a served brief without one is to change this signature — which is a compile error
3021
- * at every call site rather than a silently trace-less run. `makeEmptyServedBrief` stays the
3022
- * one no-reader constructor fallback and records nothing here, so an absent trace on evidence
3023
- * means "no reader was bound", never "a reader served and the trace was dropped" (D-15).
3024
- */
3025
2008
  trace: ServedRetrievalTraceV1;
3026
2009
  }): void;
3027
- /**
3028
- * Append the exact Channel-3 CautionLines injected into a live replan turn. Refused records
3029
- * never enter this method; the reserved reader overflow line does because its summary was
3030
- * actually rendered. Digest recomputation keeps ServedBrief content-addressed after mutation.
3031
- *
3032
- * WR-10 (387-13): the LEDGER accumulates on every call, including the zero-injection one. A
3033
- * turn that injected nothing is not a turn with nothing to explain — it is exactly the turn
3034
- * "why didn't it mention X" is asked about, and {@link foldRetrievalTrace} carries a dedicated
3035
- * arm for "no served lines, non-empty truncation ledger" that this method previously made
3036
- * unreachable by returning before accumulating.
3037
- *
3038
- * The surviving `cautions.length === 0` return is a COST guard, not a correctness one, and the
3039
- * distinction is measured rather than asserted: deleting it outright reddens nothing, because
3040
- * appending an empty array and recomputing a content-addressed digest reproduces the same
3041
- * bytes. It stays only to skip a whole-brief rehash on every all-cut turn. D-13's byte-stability
3042
- * on this path is protected by what is NOT written here — cut candidates are never spoofed into
3043
- * `channel3` as served lines — and the regression cases pin that outcome, not this branch.
3044
- */
3045
2010
  recordServedCautions(cautions: readonly CautionLine[], trace: ServedRetrievalTraceV1): void;
3046
2011
  /** Append successful Channel-2 direct reads and re-address the complete served brief. */
3047
2012
  recordServedReadTraces(traces: readonly ReadTrace[]): void;
3048
- /**
3049
- * Record the structurally failed planning turn (D-03). Exchanges and message arrive
3050
- * ALREADY masked by the loop; the recorder remains mask-agnostic.
3051
- */
3052
2013
  recordPlanningFailure(evidence: PlanningFailureEvidence): void;
3053
- /**
3054
- * Record the D-03 `common_reportValue` answer block. `value` arrives already masked. Surfaced
3055
- * on StepEvidence.reportedValue so the verdict layer (and Phase 361's handoff) carries the
3056
- * retrieved answer first-class. reportValue is non-terminal (D-02) — this only records.
3057
- */
3058
2014
  recordReportedValue(evidence: ReportedValueEvidence): void;
3059
- /**
3060
- * Record the D-04 infeasible termination block — present only when a turn declared the step
3061
- * infeasible via the `failureKind`/`failureReason` envelope (machine-distinguishable from a
3062
- * plain `stepFailed`). Sorted keys `["kind","reason"]` are fixed by the DTO.
3063
- */
3064
2015
  recordTermination(evidence: TerminationEvidence): void;
3065
- /**
3066
- * Record the typed limit stop (436 D-12/D-13). Its text fields arrive already masked; it is
3067
- * never a planning failure, a termination or a verdict source.
3068
- */
3069
2016
  recordLimitStop(evidence: LimitStopEvidence): void;
3070
- /**
3071
- * Record the per-condition verdicts (439 D-07). Text fields arrive masked and bounded; a later
3072
- * judgment of the same step replaces an earlier one.
3073
- */
3074
2017
  recordConditionVerdicts(evidence: ConditionVerdictsEvidence): void;
3075
- /** Record whether the step's platform could capture each operation (436 D-23). */
2018
+ /** Record whether the step's platform could capture each operation. */
3076
2019
  recordOperationCapture(availability: OperationCaptureAvailability): void;
3077
- /** Record the step's configured limits and usage (436 D-11); finish() calls it on every path. */
2020
+ /** Record the step's configured limits and usage; finish() calls it on every path. */
3078
2021
  recordLimitUsage(usage: StepLimitUsage): void;
3079
2022
  /**
3080
- * Record the D-05/D-06/D-07/D-09 AI judge block (`assertAI`/`extractAI`): verdict, rationale
3081
- * (masked), the requested-but-deferred M3/M4 knobs, and the extractAI global-scope degradation
3082
- * marker. One judgment per attempt (single-model law).
2023
+ * Record the assertAI or extractAI judge block: the verdict and masked rationale, or why the
2024
+ * model could not judge or extract. One per attempt.
3083
2025
  */
3084
2026
  recordAiJudgment(evidence: AiJudgmentEvidence): void;
3085
- /**
3086
- * Record the D-10/D-11 structured `common_assertValue` outcome block: the comparator's
3087
- * deterministic result with `expected`/`actual` already masked. A passing outcome drives the
3088
- * verifier short-circuit (Plan 10 seam), recorded via {@link recordVerdictSource}.
3089
- */
3090
2027
  recordAssertOutcome(evidence: AssertValueEvidence): void;
3091
- /**
3092
- * Record which path produced this step's final verification verdict (D-11): the deterministic
3093
- * assertValue comparator (`'assert-value'`) or the verifier's own model call
3094
- * (`'verifier-model'`), which also decides every AI-judged conclusion (assertAI or extractAI;
3095
- * quick 261004-lsa). Set with the final verdict, so a verifier rejection records nothing.
3096
- */
3097
2028
  recordVerdictSource(source: VerdictSource): void;
3098
- /**
3099
- * Record the typed step plan source (PROC-02 · 381 D-12). `procedure-replay` carries the
3100
- * guard fold (checksPassed/total + the first miss when the fold broke off); `procedure-hint`
3101
- * marks a served-without-replay exposure. Recorded BESIDE `cacheStatus` — structurally
3102
- * distinct from the cached flag so eval/cassette consumers reading cached semantics are
3103
- * never polluted (Pitfall 4). Last write wins: the loop updates the fold as guard checks
3104
- * accumulate, and the final state is what finalize emits.
3105
- */
3106
2029
  recordPlanSource(source: StepPlanSource): void;
3107
- /**
3108
- * Record why a cache key hit did not replay (438 D-11), before the loop invalidates the entry.
3109
- * The first reason in the step is kept.
3110
- */
3111
2030
  recordCacheMiss(miss: {
3112
2031
  reason: CacheMissReason;
3113
2032
  }): void;
3114
- /**
3115
- * Attach the D-15 stateAfter at the spec-locked boundaries (assert sub-actions, the
3116
- * verifier boundary, the self-heal boundary) by reuse of an observation the loop
3117
- * already takes — no extra capture.
3118
- */
3119
2033
  attachStateAfter(index: number, state: ScreenState): void;
3120
- /** Record the §A8 contrastive self-heal pair (D-12): the failed decision and the
3121
- * recovering decision at the replan-with-failure-context boundary. */
3122
2034
  recordSelfHeal(failedDecision: Decision, recoveringDecision: Decision): void;
3123
- /**
3124
- * Fold the per-channel serve-time attributions into the one persisted trace (D-13/D-14).
3125
- *
3126
- * Every value here was computed by the reader at the moment of serving and is copied through
3127
- * unchanged — no score is re-derived and no rank is recomputed at persistence time. The runner
3128
- * writes; the reader computed.
3129
- *
3130
- * Absent when nothing was served through a bound reader, which is D-15's honest no-trace arm:
3131
- * an absent trace says "no reader served this step", not "a trace was lost".
3132
- */
3133
2035
  private foldRetrievalTrace;
3134
- /** Finalize the accumulated evidence into a §A8 StepEvidence. cacheStatus is the
3135
- * per-step fold; servedBrief is always present (empty when no reader bound).
2036
+ /** Finalize the accumulated evidence into a §A8 StepEvidence; servedBrief is always present
2037
+ * (empty when no reader bound).
3136
2038
  *
3137
- * `options.nonCacheable` threads the D-08 bypass signal (Pitfall 7): when a step was
3138
- * classified NonCacheableStepInput the loop never touched the cache, so cacheStatus is
3139
- * `'bypass'` DIRECTLY — orthogonal to the boolean hit/miss fold (a cached sub-action's
3140
- * flag must not fold to `'hit'` for a bypassed step). */
2039
+ * cacheStatus is `'disabled'` when no cache was bound for the step (`options.cacheDisabled`),
2040
+ * else `'bypass'` when the loop left the cache untouched for a non-cacheable step
2041
+ * (`options.nonCacheable`), else the per-step hit/miss fold. */
3141
2042
  finalize(verdict: VerifierVerdict, stepIndex: number, stepText: string, options?: {
2043
+ cacheDisabled?: boolean;
3142
2044
  nonCacheable?: boolean;
3143
- /**
3144
- * The step's `{{env:NAME}}` provenance pairs (PROC-01 · 381 D-03/D-08), stamped only
3145
- * when non-empty so the absent-by-default shape is preserved. The recorder is
3146
- * MASK-AGNOSTIC by contract: it records exactly what its caller passes and masks
3147
- * nothing itself. These pairs in particular must NOT be masked anywhere — see the
3148
- * masking prohibition on `StepEvidence.interpolatedVariables`.
3149
- */
3150
2045
  interpolatedVariables?: readonly InterpolatedVariable[];
3151
2046
  }): StepEvidence;
3152
2047
  }
@@ -3157,15 +2052,9 @@ interface GroundingStrategy {
3157
2052
  }
3158
2053
  declare const deterministicDescriptorMatcher: GroundingStrategy;
3159
2054
 
3160
- /**
3161
- * Stable, non-secret, project-level env-digest salt (Open Question 2 resolution).
3162
- * It MUST be a fixed versioned constant — a per-run salt would silently change the
3163
- * env digest every run and disable ALL env-dependent cache hits. Never derive this
3164
- * per-run and never fold a secret into it.
3165
- */
3166
2055
  declare const CACHE_ENV_DIGEST_SALT = "agent-qa/cache/env-digest/v1";
3167
2056
  interface BuildCacheableStepInputArgs {
3168
- /** The declared-secret mask (441 D-06); the identity when unbound. */
2057
+ /** The declared-secret mask; the identity when unbound. */
3169
2058
  mask?: MaskFn;
3170
2059
  platform: Platform;
3171
2060
  suiteConfigDigest: string;
@@ -3178,15 +2067,9 @@ interface BuildCacheableStepInputArgs {
3178
2067
  /** Stable project salt; defaults to CACHE_ENV_DIGEST_SALT. Never per-run. */
3179
2068
  envSalt?: string;
3180
2069
  screenIdentityHash: string;
3181
- /** Accepted for caller ergonomics but intentionally never a key component (D-14). */
2070
+ /** Accepted for caller ergonomics but intentionally never a key component. */
3182
2071
  branch?: string;
3183
2072
  }
3184
- /**
3185
- * Assemble the schema kernel's 8-field CacheableStepInput. `mask()` is applied to
3186
- * stepText BEFORE it enters the tuple (the MASK-FUT-01 floor, D-05); the env digest
3187
- * folds only the value-free redacted shapes under the stable salt. The caller passes
3188
- * the result to computeCacheKey to obtain the 16-hex CacheKey / filename (D-06).
3189
- */
3190
2073
  declare function buildCacheableStepInput(args: BuildCacheableStepInputArgs): CacheableStepInput;
3191
2074
 
3192
2075
  interface CacheableClassification {
@@ -3201,19 +2084,8 @@ interface ClassifyStepInput {
3201
2084
  /** Config-env values this cacheable step reads (value-free shapes). */
3202
2085
  configEnv?: readonly RedactedEnvVar[];
3203
2086
  }
3204
- /**
3205
- * Classify a step by resolution provenance (D-07). Env/secret read-or-set steps
3206
- * return NonCacheableStepInput; a config-env-dependent step returns a
3207
- * CacheableClassification carrying the value-free RedactedEnvVar shapes.
3208
- */
3209
2087
  declare function classifyStep(input: ClassifyStepInput): CacheableClassification | NonCacheableStepInput;
3210
2088
 
3211
- /**
3212
- * Thrown by `subscribe(fromSeq, …)` when the requested range is neither in the in-memory
3213
- * window nor recoverable from the (possibly degraded) event log (D-07 — report incomplete,
3214
- * never silently serve a truncated stream). `earliestAvailableSeq` is the lowest seq the bus
3215
- * can still replay (the SSE `Last-Event-ID` re-subscribe floor in M5).
3216
- */
3217
2089
  declare class ReplayIncompleteError extends Error {
3218
2090
  readonly earliestAvailableSeq: number;
3219
2091
  constructor(requestedSeq: number, earliestAvailableSeq: number);
@@ -3241,14 +2113,10 @@ interface CreateRunEventBusOptions {
3241
2113
  }
3242
2114
  declare function createRunEventBus(opts: CreateRunEventBusOptions): RunEventBus;
3243
2115
 
3244
- /** How long a handle's stream keeps running after its LAST viewer detaches (403 D-07). */
2116
+ /** How long a handle's stream keeps running after its LAST viewer detaches. */
3245
2117
  declare const LIVE_STREAM_STOP_GRACE_MS = 2000;
3246
2118
  /** How long the hub waits for every subscriber to ack a frame before acking on their behalf. */
3247
2119
  declare const LIVE_STREAM_ACK_BOUND_MS = 250;
3248
- /**
3249
- * Default timer: the `bus.ts` idiom — unref'd so a pending grace never holds the process open.
3250
- * Exported so the snapshot producer shares it rather than copying it (428 D-11).
3251
- */
3252
2120
  declare function defaultLiveStreamTimer(): RunTimerPort;
3253
2121
  interface CreateLiveStreamHubOptions {
3254
2122
  timer?: RunTimerPort;
@@ -3259,13 +2127,6 @@ interface CreateLiveStreamHubOptions {
3259
2127
  * lands here is replayed to every later reader of the run.
3260
2128
  */
3261
2129
  onWarning?: (code: string, message: string) => void;
3262
- /**
3263
- * Where a SUBSCRIBER's fault is reported (403 WR-06). Deliberately a DIFFERENT sink than
3264
- * `onWarning`, and the difference is the whole fix: a viewer that throws — or whose socket died
3265
- * between a `readyState` check and the write — is a fact about THAT VIEWER, and the run's
3266
- * permanent record must not depend on who happened to be watching (LIVE-03). Absent by default,
3267
- * so a host that does not care reports nothing anywhere.
3268
- */
3269
2130
  onSubscriberFault?: (code: string, message: string) => void;
3270
2131
  }
3271
2132
  /**
@@ -3274,10 +2135,6 @@ interface CreateLiveStreamHubOptions {
3274
2135
  * the CONSUMER side the `RunSession` exposes.
3275
2136
  */
3276
2137
  interface LiveStreamHub {
3277
- /**
3278
- * `fallback` is the labelled snapshot producer this handle switches to when `capability` fails
3279
- * to start (428 D-12). The failure is still recorded; `capabilityOf` keeps the declared kind.
3280
- */
3281
2138
  register(handle: number, capability: LiveStreamCapability | undefined, fallback?: LiveStreamCapability): void;
3282
2139
  subscribe(handle: number, onFrame: (frame: LiveFrame) => void, onEnd?: (reason: LiveFrameEndReason) => void): LiveFrameSubscription | undefined;
3283
2140
  capabilityOf(handle: number): LiveStreamDeclaration;
@@ -3285,11 +2142,6 @@ interface LiveStreamHub {
3285
2142
  }
3286
2143
  declare function createLiveStreamHub(opts?: CreateLiveStreamHubOptions): LiveStreamHub;
3287
2144
 
3288
- /**
3289
- * The three live-preview cadences, side by side: a snapshot every second (this producer), a
3290
- * keepalive frame after two quiet seconds on a static page (the web adapter's screencast, 428-06),
3291
- * and the viewer's ~5s freshness window (428-14) that both of them stay inside.
3292
- */
3293
2145
  declare const LIVE_SNAPSHOT_INTERVAL_MS = 1000;
3294
2146
  declare const LIVE_KEEPALIVE_QUIET_MS = 2000;
3295
2147
  declare function createSnapshotLiveStream(input: {
@@ -3302,15 +2154,6 @@ type LiveStreamRegistration = {
3302
2154
  capability: LiveStreamCapability;
3303
2155
  fallback?: LiveStreamCapability;
3304
2156
  };
3305
- /**
3306
- * THE ONE SELECTION RULE (428 D-11/D-12), used by both run paths and the editor.
3307
- *
3308
- * The adapter's own `liveStream` always wins. `screenshot()` is wrapped in the snapshot producer
3309
- * only when the adapter's own capability is not already a snapshot: as the fallback behind a
3310
- * continuous stream that may fail to start, or as the whole preview when there is no continuous
3311
- * stream. An adapter whose own stream IS a snapshot (mobile) gets no fallback, which is what keeps
3312
- * a mobile run off its context-switching `screenshot()`.
3313
- */
3314
2157
  declare function liveStreamFor(adapter: Pick<PlatformAdapter, 'liveStream' | 'screenshot'> | undefined, options?: {
3315
2158
  timer?: RunTimerPort;
3316
2159
  }): LiveStreamRegistration | undefined;
@@ -3374,10 +2217,6 @@ declare function findSecretTemplates(text: string): SecretTemplate[];
3374
2217
  declare function interpolateSecretTemplates(template: string, store: SecretStore): string;
3375
2218
  declare function resolveSecretTemplatesInValue<T>(value: T, store?: SecretResolver): T;
3376
2219
  declare function redactSecretValue<T>(value: T, redactor?: SecretRedactorPort): T;
3377
- /**
3378
- * The cached-plan invalidation predicate (loop cache-poisoning guard): returns true
3379
- * when a value contains a redacted `[secret:*]` marker. Moved from core loop.ts.
3380
- */
3381
2220
  declare function containsRedactedSecretMarker(value: unknown): boolean;
3382
2221
  declare function literalSecretMarkerRefusal(value: unknown): string | undefined;
3383
2222
  declare class SecretRedactor implements SecretRedactorPort {
@@ -3395,20 +2234,7 @@ declare class SecretRedactor implements SecretRedactorPort {
3395
2234
  interface SecretEnvSource {
3396
2235
  forEachSecret(callback: (name: string, value: string) => void): void;
3397
2236
  }
3398
- /**
3399
- * Resolve the already-materialized secret name→value map the container is injected with
3400
- * (D-06). The runner-owned {@link SecretStore} satisfies the structural source; the port only
3401
- * ever sees the resolved map, never the store itself.
3402
- */
3403
2237
  declare function resolveSecretEnv(store?: SecretEnvSource): Record<string, string>;
3404
- /**
3405
- * The threaded hook-execution carrier (Phase 363 D-06) — successor to core's
3406
- * `SandboxRunnerOptions`. Threaded through the run/suite config as `sandboxOptions` and
3407
- * spread into {@link RunHooksOptions} at each hook site. Carries the injected
3408
- * {@link HookExecutorPort} (constructed once at the composition root) plus the secret
3409
- * store / redactor / active auth-state the hook body needs. `dockerBin`/`pullPolicy` are
3410
- * retained for source-compat with the old carrier (the executor owns those now).
3411
- */
3412
2238
  interface SandboxRunnerOptions {
3413
2239
  executor: HookExecutorPort;
3414
2240
  dockerBin?: string;
@@ -3424,13 +2250,6 @@ interface HookOrchestrationResult {
3424
2250
  allPassed: boolean;
3425
2251
  duration: number;
3426
2252
  }
3427
- /**
3428
- * The narrow lifecycle-emit seam `runHooks` fires through — the Plan 03 sink legs
3429
- * (`MemberEventSink.hookStarted`/`hookFinished`) satisfy it structurally. Both legs are
3430
- * fire-and-forget; the orchestration NEVER awaits telemetry. Output detail is emitted
3431
- * as-is (already sandbox-redacted by the impl); the sink applies the additive run-mask
3432
- * (T-363-05) — the orchestration does not mask.
3433
- */
3434
2253
  interface HookEmitSeam {
3435
2254
  hookStarted(payload: HookStartedPayload): void;
3436
2255
  hookFinished(payload: HookFinishedPayload): void;
@@ -3443,13 +2262,11 @@ interface HookRunIdentity {
3443
2262
  stepIndex?: number;
3444
2263
  }
3445
2264
  interface RunHooksOptions {
3446
- /** The injected D-06 executor (runner-local `DockerHookExecutor`). */
3447
2265
  executor: HookExecutorPort;
3448
2266
  /** User env + CLI/suite variables the first hook starts from. */
3449
2267
  env?: Record<string, string>;
3450
- /** Carrier-compat alias for {@link env} (the old `SandboxRunnerOptions.envVars` field). */
3451
2268
  envVars?: Record<string, string>;
3452
- /** Already-resolved secret name→value pairs for container injection (D-06). */
2269
+ /** Already-resolved secret name→value pairs for container injection. */
3453
2270
  secretEnv?: Record<string, string>;
3454
2271
  /** Runner-owned secret store; the orchestrator resolves {@link secretEnv} from it. */
3455
2272
  secretStore?: SecretEnvSource;
@@ -3468,22 +2285,16 @@ interface RunHooksOptions {
3468
2285
  declare function runHooks(hooks: HookDefinition[], options: RunHooksOptions): Promise<HookOrchestrationResult>;
3469
2286
 
3470
2287
  /**
3471
- * Start a run (D-01). Constructs the session SYNCHRONOUSLY — the bus, `runStarted` at seq 1, the
3472
- * run-budget arm, the run-level AbortController — then kicks the async member pool whose settled
3473
- * result feeds `done`. Returns the addressable {@link RunSession} immediately.
2288
+ * Start a run. Constructs the session SYNCHRONOUSLY — the bus, `runStarted` at seq 1, the
2289
+ * run-level AbortController — then kicks the async member pool whose settled result feeds `done`.
2290
+ * Returns the addressable {@link RunSession} immediately.
3474
2291
  *
3475
- * 402-02 (D-09): members execute through a BOUNDED CONCURRENT POOL rather than a `for` loop, but
3476
- * everything after it is unchanged — the terminal sequence is still ONE code path, run once, after
3477
- * the pool settles. Concurrency changes which member is in flight when; it does not change who
3478
- * publishes the verdict, or when `runFinished` is last.
2292
+ * Members execute through a BOUNDED CONCURRENT POOL, and the terminal sequence is ONE code path,
2293
+ * run once, after the pool settles. Concurrency changes which member is in flight when; it does not
2294
+ * change who publishes the verdict, or when `runFinished` is last.
3479
2295
  */
3480
2296
  declare function startRun(config: RunConfig): RunSession;
3481
2297
 
3482
- /**
3483
- * Build the per-member {@link MemberEventSink} the shell hands to the executor context (D-02).
3484
- * `testIndex` is bound here; `stepIndex` is curried by `loopEmitFor`. `mask` is the run's mask
3485
- * (441-12, D-06). All three payload kinds go through the schema projections + mask.
3486
- */
3487
2298
  declare function createMemberEventSink(deps: {
3488
2299
  bus: RunEventBus;
3489
2300
  mask: MaskFn;
@@ -3502,11 +2313,6 @@ interface MemberStepSpec {
3502
2313
  description?: string;
3503
2314
  };
3504
2315
  }
3505
- /**
3506
- * The one derivation of the text a step is announced with at `stepStarted` (G-428-2). Every
3507
- * producer that states a step's text before it starts (the CLI's `stepTexts` on each member
3508
- * descriptor) derives it here, so the pending text and the announced text cannot drift.
3509
- */
3510
2316
  declare function memberStepText(step: string | MemberStepSpec): string;
3511
2317
  /** The runner-owned member-test shape (a core-independent subset of TestDefinition). */
3512
2318
  interface MemberTest {
@@ -3522,18 +2328,18 @@ interface MemberTest {
3522
2328
  [key: string]: unknown;
3523
2329
  };
3524
2330
  }
3525
- /** The injected runJS execution handler (Q-2). The CLI owns page.evaluate + platform checks. */
2331
+ /** The injected runJS handler; the CLI owns page.evaluate and platform checks. */
3526
2332
  type RunJsHandler = (code: string, ctx: {
3527
2333
  abortSignal: AbortSignal;
3528
2334
  }) => Promise<{
3529
2335
  value: string;
3530
2336
  error?: string;
3531
2337
  }>;
3532
- /** The injected appium execution handler (Q-2). The CLI resolves secrets + calls the adapter. */
2338
+ /** The injected appium handler; the CLI resolves secrets and calls the adapter. */
3533
2339
  type AppiumScriptHandler = (action: Action, ctx: {
3534
2340
  abortSignal: AbortSignal;
3535
2341
  }) => Promise<ActionResult>;
3536
- /** The injected accessibility-check handler (Q-4). The CLI owns page acquisition + the web module. */
2342
+ /** The injected accessibility handler; the CLI owns page acquisition and the web module. */
3537
2343
  type AccessibilityCheckHandler = (opts: {
3538
2344
  standard?: 'wcag2a' | 'wcag2aa' | 'wcag2aaa';
3539
2345
  disableRules?: string[];
@@ -3573,11 +2379,6 @@ interface MemberRunConfig {
3573
2379
  recordCap: number;
3574
2380
  };
3575
2381
  knowledgeAsOfBuild?: number;
3576
- /**
3577
- * 407 D-13 — the host's retrieval rung, resolved once at the composition root and threaded
3578
- * verbatim onto every step's LoopPorts. Typed off LoopPorts so there is ONE spelling of the
3579
- * contract between the run shell and the loop.
3580
- */
3581
2382
  knowledgeRetrievalRung?: LoopPorts['knowledgeRetrievalRung'];
3582
2383
  recordLedger?: LoopPorts['recordLedger'];
3583
2384
  beginMemoryTurn?: LoopPorts['beginMemoryTurn'];
@@ -3621,7 +2422,7 @@ interface MemberRunConfig {
3621
2422
  accessibility?: {
3622
2423
  enabled: boolean;
3623
2424
  standard?: 'wcag2a' | 'wcag2aa' | 'wcag2aaa';
3624
- runAfter?: 'every-step' | 'navigation' | 'test-end';
2425
+ runAfter?: 'every-step' | 'test-end';
3625
2426
  failOnViolation?: boolean;
3626
2427
  disableRules?: string[];
3627
2428
  exclude?: string[];
@@ -3653,13 +2454,6 @@ interface MemberRunConfig {
3653
2454
  executeStep?: typeof executeStep;
3654
2455
  extractorFactory?: (model: LanguageModel | undefined, method: string) => VariableExtractor;
3655
2456
  }
3656
- /**
3657
- * Run a member test with the retry loop (D-13). The trigger stays `meta.retries`
3658
- * (user-config surface unchanged). Attempts run INSIDE the member; `testRetryScheduled`
3659
- * fires between attempts (a per-test accumulation reset for subscribers); only the FINAL
3660
- * attempt's TestResult leaves the member carrying `retryCount` (Pitfall 9 — the shell
3661
- * emits the single authoritative testStarted/testFinished pair per member).
3662
- */
3663
2457
  declare function runMemberTest(member: MemberTest, config: MemberRunConfig): Promise<TestResult>;
3664
2458
 
3665
2459
  declare function isCanonicalHookIdShape(value: string): boolean;
@@ -3679,20 +2473,6 @@ declare function parseAppiumInline(text: string): Action | null;
3679
2473
 
3680
2474
  declare function generateFailureSummary(steps: StepResult[]): string;
3681
2475
 
3682
- /**
3683
- * Fold one completed member {@link TestResult} + its derived {@link MemberTestOutcome} into a
3684
- * {@link PerTestOutcome}. Steps are built from `result.steps`: a step with §A8 evidence carries it
3685
- * (with `stepIndex` OVERRIDDEN to its array position); an evidence-less step gets a synthesized
3686
- * minimal StepEvidence. `testIndex` is the shell-owned array position.
3687
- *
3688
- * `rootCause` is the shell-classified §A9 verdict (373-07): attached ONLY when defined so clean
3689
- * passes/skipped/cancelled members stay rootCause-free in the persisted JSON (the D-01 presence
3690
- * rule — the key is absent, never undefined-valued).
3691
- *
3692
- * `deps.quarantined` is the 390 D-14 disposition, stamped BESIDE `outcome` under the same
3693
- * presence rule. It never alters `outcome`: a quarantined failing member reads `'failed'` here, and
3694
- * the licence to ignore that failure lives entirely in the aggregate rule and in this marker.
3695
- */
3696
2476
  declare function assemblePerTestOutcome(member: RunMemberDescriptor, result: TestResult, outcome: MemberTestOutcome, deps: {
3697
2477
  testIndex: number;
3698
2478
  scope: ScopeKey;
@@ -3707,91 +2487,23 @@ declare function assemblePerTestOutcome(member: RunMemberDescriptor, result: Tes
3707
2487
  outcome: 'failed' | 'timeout';
3708
2488
  rootCause?: Verdict;
3709
2489
  }): PerTestOutcome;
3710
- /**
3711
- * The shell-produced skip outcome (D-15): a member the shell never invoked (run aborted, or a
3712
- * poisoned same-group member). `outcome: 'skipped'`, no steps — neutral in the aggregate fold.
3713
- *
3714
- * `quarantined` is still stamped when the ledger licensed this member (390 D-14): the disposition
3715
- * describes the TEST's standing, not the outcome it happened to reach, so a reader of the handoff
3716
- * sees the same truth whether the member ran or was skipped past.
3717
- */
3718
2490
  declare function skippedPerTestOutcome(member: RunMemberDescriptor, testIndex: number, quarantined?: true): PerTestOutcome;
3719
- /**
3720
- * Assemble the one {@link CompletedRunHandoff} a run persists (D-17). Every header field is copied
3721
- * verbatim FROM the resolved {@link RunConfig} (D-04/D-20 — never re-derived); `aggregateVerdict`
3722
- * is the execution verdict; `tests` are the assembled per-member outcomes in run order.
3723
- *
3724
- * 390 D-16: `quarantineApplied` records the ledger entries this run was operating under, copied
3725
- * from the same resolved config the disposition markers were matched against — so the run's own
3726
- * receipt answers "which suppressions were licensed here, and until when" without re-reading a
3727
- * ledger that may since have changed. An empty set stays ABSENT, keeping every unquarantined run's
3728
- * handoff bytes identical to pre-390.
3729
- */
3730
2491
  declare function assembleHandoff(config: RunConfig, outcomes: PerTestOutcome[], aggregateVerdict: RunStatus, timing: {
3731
2492
  startedAt: number;
3732
2493
  endedAt: number;
3733
2494
  }): CompletedRunHandoff;
3734
2495
 
3735
- /**
3736
- * Derive the member-level outcome for one completed test (D-16). Pure total function.
3737
- *
3738
- * - status `skipped` ⇒ `'skipped'` (member-neutral; passed through)
3739
- * - status `cancelled` ⇒ `'cancelled'`
3740
- * - status `passed` ⇒ `'healed'` when ANY step carries selfHeal evidence, else `'passed'`.
3741
- * The live heal signal is StepEvidence.selfHeal *presence* — a step-status read would
3742
- * never fire (RESEARCH Pitfall 5), so we never inspect a step status string here.
3743
- * - status `failed` ⇒ `'timeout'` when ANY failed step's `error` is the test-deadline
3744
- * message (isTestTimeoutMessage), else `'failed'`.
3745
- *
3746
- * Core's TestStatus and the executor port stay untouched by this derivation (D-16).
3747
- */
3748
2496
  declare function deriveMemberOutcome(result: TestResult): MemberTestOutcome;
3749
- /**
3750
- * Fold member outcomes into the aggregate run verdict — the ratified spec §2.1 ordered
3751
- * rule with the D-15 neutral-skipped clause. EVALUATED IN ORDER:
3752
- *
3753
- * 1. `runCancelled` ⇒ `'cancelled'` (a whole-run cancel wins over everything)
3754
- * 2. `runBudgetExpired` ⇒ `'timeout'` (reserved for the whole-run wall-clock budget;
3755
- * a member 'timeout' is NOT this — it falls to the failed branch below)
3756
- * 3. any member `'failed'` or `'timeout'` ⇒ `'failed'`
3757
- * 4. any member `'cancelled'` (none failed) ⇒ `'cancelled'`
3758
- * 5. any member `'healed'` (none failed) ⇒ `'healed'`
3759
- * 6. else ⇒ `'passed'`
3760
- *
3761
- * `'skipped'` members are neutral throughout — an all-skipped (or empty) run is
3762
- * vacuously `'passed'` (D-15, the reconciled clause; matches every test runner).
3763
- *
3764
- * PHASE 390 D-14 — the quarantine skip is EXPLICIT IN THE RULE, right here in step 3 and nowhere
3765
- * else. `quarantined[i] === true` marks a member whose failure the committed ledger has licensed:
3766
- * step 3 passes over it, so a run whose only failures are quarantined aggregates `'passed'` and
3767
- * exits 0 through the untouched {@link mapVerdictToExitCode}. Three things this deliberately does
3768
- * NOT do: it does not rewrite the member outcome (`'failed'` stays `'failed'` — the projection
3769
- * window and the auto-exit keep seeing reality), it does not touch any other branch (a sibling
3770
- * `'cancelled'`/`'healed'` still governs, and the two run-level branches still win outright), and
3771
- * it does not widen either closed union. `quarantined` absent — or shorter than `outcomes` — is
3772
- * byte-identical pre-390 behavior, which is why every existing call site compiles unchanged.
3773
- *
3774
- * The skip covers `'timeout'` members as well as `'failed'` ones: a quarantined flaky test that
3775
- * times out is the same A3 phenomenon, and a rule that suppressed one but not the other would make
3776
- * relief depend on how the flake happened to manifest that build.
3777
- */
3778
2497
  declare function deriveAggregateVerdict(input: {
3779
2498
  runCancelled: boolean;
3780
- runBudgetExpired: boolean;
3781
2499
  outcomes: readonly MemberTestOutcome[];
3782
2500
  quarantined?: readonly boolean[];
3783
2501
  }): RunStatus;
3784
- /**
3785
- * Map an aggregate verdict to a process exit code (D-14). Pure and pinned:
3786
- * passed/healed ⇒ 0 (healed is ratified as a pass — the annotation lives in output and
3787
- * the handoff, never the exit code), failed/timeout ⇒ 1, cancelled ⇒ 130 (existing SIGINT
3788
- * convention). Exit 2 stays reserved for config/setup errors and is NOT produced here.
3789
- */
3790
2502
  declare function mapVerdictToExitCode(verdict: RunStatus): number;
3791
2503
 
3792
- /** The four classes the deterministic classifier can mint (RCC-02). */
2504
+ /** The four classes the deterministic classifier can mint. */
3793
2505
  type DeterministicRootCauseClass = 'timeout' | 'environment' | 'flake' | 'unknown';
3794
- /** The fixed unknown-class rationale template (D-02). */
2506
+ /** The fixed unknown-class rationale template. */
3795
2507
  declare const UNKNOWN_SIGNAL_RATIONALE = "no deterministic signal matched";
3796
2508
  interface RootCauseInput {
3797
2509
  /** The member's final-attempt TestResult (carries retryCount — the flake signal source). */
@@ -3800,29 +2512,14 @@ interface RootCauseInput {
3800
2512
  outcome: MemberTestOutcome;
3801
2513
  /** Shell-derived member index; becomes Verdict.perTest. */
3802
2514
  testIndex: number;
3803
- /** Run-start baseline probe outcome (D-04, web targets; threaded by Plan 07). */
3804
2515
  baselineProbe?: {
3805
2516
  status?: number;
3806
2517
  elapsedMs: number;
3807
2518
  error?: string;
3808
2519
  };
3809
- /**
3810
- * The run's mask (439 D-08). An unproven step's reason carries the planner's own words, which
3811
- * the step error holds unmasked, so its rationale passes through this before it is recorded.
3812
- */
3813
2520
  mask?: (text: string) => string;
3814
2521
  }
3815
- /**
3816
- * The D-02 faithful VerdictBase constructor. Pure and total: every field of the LLM-shaped
3817
- * base is filled deterministically — confidence keys on the class ('unknown' ⇒ 0, else 1),
3818
- * the unknown rationale is always the fixed template regardless of the signal argument.
3819
- */
3820
2522
  declare function deterministicVerdict(cls: DeterministicRootCauseClass, signal: string, citedSteps: number[], perTest: number): Verdict;
3821
- /**
3822
- * Classify one member's root cause from deterministic signals only (RCC-02). Returns
3823
- * undefined when the presence rule says no rootCause (skipped/cancelled/clean pass).
3824
- * See the module header for the documented, pinned branch order.
3825
- */
3826
2523
  declare function classifyRootCause(input: RootCauseInput): Verdict | undefined;
3827
2524
 
3828
2525
  declare function createMemoryTools(deps: {
@@ -3866,16 +2563,6 @@ declare function toolCallToActionPlan(toolId: string, args: Record<string, unkno
3866
2563
  doesActionAdvanceUsTowardsGoal: boolean;
3867
2564
  };
3868
2565
 
3869
- /**
3870
- * Project a resolved Action onto the schema-owned {@link RiskActionDescriptor} (D-08). An
3871
- * unrecognized verb projects `recognized: false` — the classifier's fail-safe floor maps it to
3872
- * `restricted` → deny. `command`/`declaredTier` are deliberately omitted: no shell-wrapper actions
3873
- * exist in-test and `declaredTier` stays the registry's future channel.
3874
- */
3875
- declare function projectRiskAction(action: {
3876
- type: string;
3877
- }): RiskActionDescriptor;
3878
-
3879
2566
  declare function normalizePointerActionForStep(action: Action, stepInstruction: string): Action;
3880
2567
 
3881
2568
  /**
@@ -3900,4 +2587,4 @@ declare function convertKeysForPlatform(keys: string[], options: {
3900
2587
  */
3901
2588
  declare function isMacPlatform(): boolean;
3902
2589
 
3903
- export { AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH, AUTH_STATE_HOOK_JSON_ENV, AUTH_STATE_HOOK_STORAGE_STATE_FILENAME, AUTH_STATE_HOOK_STORAGE_STATE_PATH_ENV, AUTH_STATE_HOOK_WORKSPACE_DIR, type AccessibilityCheckHandler, type AccessibilityViolation, type Action, type ActionPlan, type ActionPlanCache, type ActionResult, type ActionsFor, type AgentAbortScope, type AgentTimeoutAbortReason, type AiJudgmentMeta, AiJudgmentResultSchema, type AppRegistryEntry, type AppResolution, type AppiumScriptHandler, type AssertValueInput, type AssertValueOutcomeMeta, type AssertValueResult, type Asserter, AssertionEvaluator, type AssertionInput, type AssertionResult, type AssertionType, type BaselineProbeResult, type BrowserConfig, type BuildCacheableStepInputArgs, type BuildCachedPlanValueInput, type BuildScreenStateInput, type BuildScreenStateResult, CACHE_ENV_DIGEST_SALT, CHARS_PER_TOKEN_ESTIMATE, CLIPBOARD_TEXT_LIMIT, CLIPBOARD_TRUNCATION_MARKER, type CacheableClassification, type CacheablePlannedAction, type CachedPlanValue, type CaptureResult, type CaptureStamp, type CarriedArtifacts, type CarriedClipboard, type CarriedDownload, type CarriedLine, type ClassifyStepInput, type ClipboardWriteMeta, type CompressedScreenshot, type ConditionJudgment, type ConfigDigests, type ConformanceInput, type ConsoleLogEntry, type CreateLiveStreamHubOptions, type CreateRunEventBusOptions, DEFAULT_CANDIDATE_COUNT, DEFAULT_EDIT_DISTANCE_BOUND, DEFAULT_FUZZY_MARGIN, DEFAULT_FUZZY_THRESHOLD, DEFAULT_NON_ACTION_TOOL_BUDGET, type DesiredState, type DesiredStateAction, type DeterministicRootCauseClass, type DeviceConfig, type DialogAccount, type Direction, type DirectionScrollParams, type DocumentScrollOffsets, EXPOSURE, type EventLogPort, type EvidenceArtifactStorePort, EvidenceRecorder, type ExecuteOptions, type ExecutePlanningTurnOptions, ExplicitExtractor, type ExtractionMethod, ExtractionResultSchema, type ExtractorInput, FILE_DIFFERENCE_WINDOW, FILL_SEPARATORS, type FailureScreenshotWriter, type FillRefusalMeta, type FillRereadMeta, type FillSubmitMeta, type FillVerdictMeta, type FillVerifyInput, type FillVerifyResult, type GroundedLocator, type GroundingStrategy, type HandoffStorePort, type HookDefinition, type HookEmitSeam, type HookExecuteOptions, type HookExecutorPort, type HookOrchestrationResult, type HookResult, type HookRunIdentity, type HookRuntime, type InlineHookCall, type InterimFixture, type InterimFixtureKind, type InterimNode, type InterpolationWithProvenance, type KnowledgeHintReader, LIVE_KEEPALIVE_QUIET_MS, LIVE_SNAPSHOT_INTERVAL_MS, LIVE_STREAM_ACK_BOUND_MS, LIVE_STREAM_STOP_GRACE_MS, LLMAssertionEvaluator, LLMPlanner, LLMVariableExtractor, LLMVerifier, type LiveStreamCapability, type LiveStreamHub, type LiveStreamRegistration, type LoopEventEmitPort, type LoopLogger, type LoopPorts, type LoopScopedLogger, MAX_TO_END_SWIPES, MINT_VERBS, type MemberEventSink, type MemberEvidenceContext, type MemberRunConfig, type MemberStepSpec, type MemberTest, type MemberTestExecutor, type MemberTestRunContext, type MintVerb, MissingSecretError, type NetworkLogEntry, type NonActionToolHandler, type NonActionToolMap, OBSERVATION_LINE_PREFIX, type ObserveOptions, type OpenAppMeta, type OperationCaptureSupport, POST_VERDICT_STEP_BUDGET_MS, type PersistedRecording, type PlanResult, type Planner, type PlannerConfig, type PlanningCallGate, PlanningLimitReachedError, PlanningTurnError, type PlanningTurnFailure, type PlanningTurnFailureReason, type PlanningTurnResult, type PlanningTurnSuccess, type PlatformAdapter, type PlatformConfig, type PostVerdictOutcome, type PostVerdictPort, type PostVerdictStepInput, RECORD_ACTION_LINE_CAP, RECORD_LINE_CHAR_CAP, RECORD_LIST_CAP, ROW_CONTAINER_ROLES, RUNTIME_IMAGE_MAP, type RecordAdmission, type RecordLedger, type RecordSubActionInput, type RecordedAction, type RecordedActionOutcome, type RecordedRead, type RecordedReadKind, type RecordingCapability, type RecordingStart, type RecordingStop, type RefBinding, type RenderedCautionLine, type RenderedStepRecord, ReplayIncompleteError, type ReportValueInput, type ReportedValueMeta, type RootCauseInput, type RunArtifactStorePort, type RunConfig, type RunEventBus, type RunHooksOptions, type RunJSMatch, type RunJsHandler, type RunMemberDescriptor, type RunPorts, type RunTimerPort, type RunnerDegradeOptions, type RunnerDegradeOutcome, type RuntimeAuthStateConfig, SCROLL_OUTCOMES_READ_ONLY, SCROLL_OUTCOMES_WRITTEN, type SandboxRunnerOptions, type SavedFileComparison, type SavedFileExpectation, type ScorerOptions, type ScreenConformanceCase, type ScreenshotCompressor, type ScriptedVerdict, type ScrollEndedBy, type ScrollLoopResult, type ScrollOffsets, type ScrollPrimitives, type ScrollUntilVisibleMeta, SecretConfigError, type SecretFileMetadata, SecretRedactor, type SecretRedactorPort, type SecretResolver, SecretStore, type SecretTemplate, type ServedCautions, type ServedRunBrief, type ShellActionMeta, type StatedTarget, type StatedTargets, type StepAnnotation, type StepContext, type StepModelAttempt, type StepModelBinding, type StepModelCallEvent, type StepModelCallReport, type StepModelConsumers, type StepModelObservation, type StepModelRoleFacts, type StepModelScope, type StepModelScopeFactory, type StepModelScopeKey, type StepModelScopeOptions, type StepModelSnapshot, type StepPhaseEvent, StepRecordAccumulator, type StepResult, type StepStatus, type StepTrace, type StorageStateBlob, type StorageStatePort, type StorageStateReference, type SubActionTrace, type SwipeSignal, type TargetVisibility, type TestResult, type TestStatus, type TimeoutConfig, type TokenAccounting, type TokenUsage, type ToolCategory, type ToolDefinition, type ToolExchange, ToolRegistry, UNKNOWN_SIGNAL_RATIONALE, type UniqueValueGenerator, type UniqueValueInput, type UniqueValueMeta, type UntilVisibleParams, type VariableExtractor, type VariableSource, VariableStore, type VariableStoreOptions, type VerificationResult, VerificationResultSchema, type Verifier, type VerifierStepRecord, type VerifyResult, type WorkingMemoryPort, type WorkingMemoryProvenanceContext, WorkingMemoryStore, assembleBriefTiers, assembleHandoff, assemblePerTestOutcome, assertNever, buildAssertionPrompt, buildAuthStateHookEnv, buildCacheableStepInput, buildCachedPlanValue, buildContextTier, buildExtractionPrompt, buildScreenState, buildSystemPrompt, buildTools, buildVerificationPrompt, buildVerifierStableTier, buildVolatileTier, classifyRootCause, classifyStep, coerceRunJSResult, collapseAnnotation, compareAssertValue, compareFillReread, compareSavedFile, composeTurnMessages, containsRedactedSecretMarker, convertKeysForPlatform, createAsserter, createExtractor, createLiveStreamHub, createMemberEventSink, createMemoryTools, createRecordLedger, createRunEventBus, createSnapshotLiveStream, createStepModelScope, createTimeoutAbortReason, defaultLiveStreamTimer, defaultRegistry, defaultUniqueValueGenerator, deriveAggregateVerdict, deriveMemberOutcome, desiredStateSatisfied, deterministicDescriptorMatcher, deterministicVerdict, documentSwipeSignal, estimateRenderedServingCost, estimateTokens, executePlanningTurn, executeStep, findBareVariables, findSecretTemplates, findUnresolvedTemplates, foldCacheStatus, formatAction, generateFailureSummary, getTimeoutAbortReason, imageSizeOf, interpolateSecretTemplates, interpolateVariables, interpolateVariablesWithProvenance, isCanonicalHookIdShape, isMacPlatform, isReservedAuthStateHookEnvKey, isTestTimeoutMessage, judgeStatedTarget, literalSecretMarkerRefusal, liveStreamFor, makeEmptyServedBrief, makeInterimNodes, makeScreenState, mapVerdictToExitCode, memberStepText, metVerification, mintReportedValue, mintUniqueValue, normalizePointerActionForStep, notMetVerification, parseAppiumInline, parseEnvFile, parseHookInline, parseRunJSInline, projectLegacyTrace, projectRiskAction, readAiJudgmentMeta, readAssertValueOutcomeMeta, readClipboardMeta, readDownloadMeta, readFillRefusalMeta, readFillRereadMeta, readFillSubmitMeta, readFillVerdictMeta, readOpenAppMeta, readReportedValueMeta, readScrollUntilVisibleMeta, readShellActionMeta, readUniqueValueMeta, redactSecretValue, renderBriefAsHypotheses, renderBriefLine, renderCautionLine, renderCautionSummary, renderObservationLine, renderScreenTree, renderStepRecord, resolveAppName, resolveSecretEnv, resolveSecretTemplatesInValue, rowContains, rowTextOf, runDirectionScroll, runHooks, runMemberTest, runToEndScroll, runUntilVisibleLoop, screenConformanceCases, scriptedVerification, scrollerSetSwipeSignal, serializeEnvFile, skippedPerTestOutcome, stampCaptureMode, startRun, stripHookInline, stripReservedAuthStateHookEnv, swipeSignalFromOffsets, tierForEntry, toGroundedLocator, toVerificationResult, toolCallToActionPlan, withAbort, withStepModelCall, wordTokens };
2590
+ export { AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH, AUTH_STATE_HOOK_JSON_ENV, AUTH_STATE_HOOK_STORAGE_STATE_FILENAME, AUTH_STATE_HOOK_STORAGE_STATE_PATH_ENV, AUTH_STATE_HOOK_WORKSPACE_DIR, type AccessibilityCheckHandler, type AccessibilityViolation, type Action, type ActionPlan, type ActionPlanCache, type ActionResult, type ActionsFor, type AgentAbortScope, type AgentTimeoutAbortReason, type AiExtraction, type AiJudgment, type AiJudgmentMeta, AiJudgmentResultSchema, type AppRegistryEntry, type AppResolution, type AppiumScriptHandler, type AssertAiMode, type AssertValueInput, type AssertValueOutcomeMeta, type AssertValueResult, type Asserter, AssertionEvaluator, type AssertionInput, type AssertionResult, type AssertionType, type BaselineProbeResult, type BrowserConfig, type BuildCacheableStepInputArgs, type BuildCachedPlanValueInput, type BuildScreenStateInput, type BuildScreenStateResult, CACHE_ENV_DIGEST_SALT, CHARS_PER_TOKEN_ESTIMATE, CLIPBOARD_TEXT_LIMIT, CLIPBOARD_TRUNCATION_MARKER, type CacheableClassification, type CacheablePlannedAction, type CachedPlanValue, type CaptureResult, type CaptureStamp, type CarriedArtifacts, type CarriedClipboard, type CarriedDownload, type CarriedLine, type ClassifyStepInput, type ClipboardWriteMeta, type CompressedScreenshot, type ConditionJudgment, type ConfigDigests, type ConformanceInput, type ConsoleLogEntry, type CreateLiveStreamHubOptions, type CreateRunEventBusOptions, DEFAULT_CANDIDATE_COUNT, DEFAULT_EDIT_DISTANCE_BOUND, DEFAULT_FUZZY_MARGIN, DEFAULT_FUZZY_THRESHOLD, DEFAULT_NON_ACTION_TOOL_BUDGET, type DesiredState, type DesiredStateAction, type DeterministicRootCauseClass, type DeviceConfig, type DialogAccount, type Direction, type DirectionScrollParams, type DocumentScrollOffsets, EXPOSURE, type EventLogPort, type EvidenceArtifactStorePort, EvidenceRecorder, type ExecuteOptions, type ExecutePlanningTurnOptions, ExplicitExtractor, type ExtractField, type ExtractionMethod, ExtractionResultSchema, type ExtractorInput, FILE_DIFFERENCE_WINDOW, FILL_SEPARATORS, type FailureScreenshotWriter, type FillRefusalMeta, type FillRereadMeta, type FillSubmitMeta, type FillVerdictMeta, type FillVerifyInput, type FillVerifyResult, type GroundedLocator, type GroundingStrategy, type HandoffStorePort, type HookDefinition, type HookEmitSeam, type HookExecuteOptions, type HookExecutorPort, type HookOrchestrationResult, type HookResult, type HookRunIdentity, type HookRuntime, type InlineHookCall, type InterimFixture, type InterimFixtureKind, type InterimNode, type InterpolationWithProvenance, type KnowledgeHintReader, LIVE_KEEPALIVE_QUIET_MS, LIVE_SNAPSHOT_INTERVAL_MS, LIVE_STREAM_ACK_BOUND_MS, LIVE_STREAM_STOP_GRACE_MS, LLMAssertionEvaluator, LLMPlanner, LLMVariableExtractor, LLMVerifier, type LiveStreamCapability, type LiveStreamHub, type LiveStreamRegistration, type LoopEventEmitPort, type LoopLogger, type LoopPorts, type LoopScopedLogger, MAX_TO_END_SWIPES, MINT_VERBS, type MemberEventSink, type MemberEvidenceContext, type MemberRunConfig, type MemberStepSpec, type MemberTest, type MemberTestExecutor, type MemberTestRunContext, type MintVerb, MissingSecretError, type NetworkLogEntry, type NonActionToolHandler, type NonActionToolMap, OBSERVATION_LINE_PREFIX, type OpenAppMeta, type OperationCaptureSupport, POST_VERDICT_STEP_BUDGET_MS, type PersistedRecording, type PlanResult, type Planner, type PlannerConfig, type PlanningCallGate, PlanningLimitReachedError, PlanningTurnError, type PlanningTurnFailure, type PlanningTurnFailureReason, type PlanningTurnResult, type PlanningTurnSuccess, type PlatformAdapter, type PlatformConfig, type PostVerdictOutcome, type PostVerdictPort, type PostVerdictStepInput, RECORD_ACTION_LINE_CAP, RECORD_LINE_CHAR_CAP, RECORD_LIST_CAP, ROW_CONTAINER_ROLES, RUNTIME_IMAGE_MAP, type RecordAdmission, type RecordLedger, type RecordSubActionInput, type RecordedAction, type RecordedActionOutcome, type RecordedRead, type RecordedReadKind, type RecordingCapability, type RecordingStart, type RecordingStop, type RefBinding, type RenderedCautionLine, type RenderedStepRecord, ReplayIncompleteError, type ReportValueInput, type ReportedValueMeta, type RootCauseInput, type RunArtifactStorePort, type RunConfig, type RunEventBus, type RunHooksOptions, type RunJSMatch, type RunJsHandler, type RunMemberDescriptor, type RunPorts, type RunTimerPort, type RunnerDegradeOptions, type RunnerDegradeOutcome, type RuntimeAuthStateConfig, SCROLL_OUTCOMES_READ_ONLY, SCROLL_OUTCOMES_WRITTEN, type SandboxRunnerOptions, type SavedFileComparison, type SavedFileExpectation, type ScorerOptions, type ScreenConformanceCase, type ScreenshotCompressor, type ScriptedVerdict, type ScrollEndedBy, type ScrollLoopResult, type ScrollOffsets, type ScrollPrimitives, type ScrollUntilVisibleMeta, SecretConfigError, type SecretFileMetadata, SecretRedactor, type SecretRedactorPort, type SecretResolver, SecretStore, type SecretTemplate, type ServedCautions, type ServedRunBrief, type ShellActionMeta, type StatedTarget, type StatedTargets, type StepAnnotation, type StepContext, type StepModelAttempt, type StepModelBinding, type StepModelCallEvent, type StepModelCallReport, type StepModelConsumers, type StepModelObservation, type StepModelRoleFacts, type StepModelScope, type StepModelScopeFactory, type StepModelScopeKey, type StepModelScopeOptions, type StepModelSnapshot, type StepPhaseEvent, StepRecordAccumulator, type StepResult, type StepStatus, type StepTrace, type StorageStateBlob, type StorageStatePort, type StorageStateReference, type SubActionTrace, type SwipeSignal, type TargetVisibility, type TestResult, type TestStatus, type TimeoutConfig, type TokenAccounting, type TokenUsage, type ToolCategory, type ToolDefinition, type ToolExchange, ToolRegistry, UNKNOWN_SIGNAL_RATIONALE, type UniqueValueGenerator, type UniqueValueInput, type UniqueValueMeta, type UntilVisibleParams, type VariableExtractor, type VariableSource, VariableStore, type VariableStoreOptions, type VerificationResult, VerificationResultSchema, type Verifier, type VerifierStepRecord, type VerifyResult, type WorkingMemoryPort, type WorkingMemoryProvenanceContext, WorkingMemoryStore, assembleBriefTiers, assembleHandoff, assemblePerTestOutcome, assertNever, buildAssertionPrompt, buildAuthStateHookEnv, buildCacheableStepInput, buildCachedPlanValue, buildContextTier, buildExtractionPrompt, buildScreenState, buildSystemPrompt, buildTools, buildVerificationPrompt, buildVerifierStableTier, buildVolatileTier, classifyRootCause, classifyStep, coerceRunJSResult, collapseAnnotation, compareAssertValue, compareFillReread, compareSavedFile, composeTurnMessages, containsRedactedSecretMarker, convertKeysForPlatform, createAsserter, createExtractor, createLiveStreamHub, createMemberEventSink, createMemoryTools, createRecordLedger, createRunEventBus, createSnapshotLiveStream, createStepModelScope, createTimeoutAbortReason, defaultLiveStreamTimer, defaultRegistry, defaultUniqueValueGenerator, deriveAggregateVerdict, deriveMemberOutcome, desiredStateSatisfied, deterministicDescriptorMatcher, deterministicVerdict, documentSwipeSignal, estimateRenderedServingCost, estimateTokens, executePlanningTurn, executeStep, findBareVariables, findSecretTemplates, findUnresolvedTemplates, foldCacheStatus, formatAction, generateFailureSummary, getTimeoutAbortReason, hookRunnerImage, imageSizeOf, interpolateSecretTemplates, interpolateVariables, interpolateVariablesWithProvenance, isCanonicalHookIdShape, isMacPlatform, isReservedAuthStateHookEnvKey, isTestTimeoutMessage, judgeStatedTarget, literalSecretMarkerRefusal, liveStreamFor, makeEmptyServedBrief, makeInterimNodes, makeScreenState, mapVerdictToExitCode, memberStepText, metVerification, mintReportedValue, mintUniqueValue, normalizePointerActionForStep, notMetVerification, parseAppiumInline, parseEnvFile, parseHookInline, parseRunJSInline, projectLegacyTrace, readAiJudgmentMeta, readAssertValueOutcomeMeta, readClipboardMeta, readDownloadMeta, readFillRefusalMeta, readFillRereadMeta, readFillSubmitMeta, readFillVerdictMeta, readOpenAppMeta, readReportedValueMeta, readScrollUntilVisibleMeta, readShellActionMeta, readUniqueValueMeta, redactSecretValue, renderBriefAsHypotheses, renderBriefLine, renderCautionLine, renderCautionSummary, renderObservationLine, renderScreenTree, renderStepRecord, resolveAppName, resolveSecretEnv, resolveSecretTemplatesInValue, rowContains, rowTextOf, runDirectionScroll, runHooks, runMemberTest, runToEndScroll, runUntilVisibleLoop, screenConformanceCases, scriptedVerification, scrollerSetSwipeSignal, serializeEnvFile, skippedPerTestOutcome, stampCaptureMode, startRun, stripHookInline, stripReservedAuthStateHookEnv, swipeSignalFromOffsets, tierForEntry, toGroundedLocator, toVerificationResult, toolCallToActionPlan, withAbort, withStepModelCall, wordTokens };