@vostride/agent-qa-dashboard 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.
@@ -1,6 +1,6 @@
1
1
  import { IncomingMessage, ServerResponse, Server } from 'node:http';
2
2
  import { RunAttributes, ResolvedWorkspacePaths, ResolvedAppiumExecutable, HookDefinition, AuthStateMetadata } from '@vostride/agent-qa-core';
3
- import { RunDetailMember, RunDetailStep, RunDetailSubAction, RunDetailRows, RunStatus, RunArtifactKind, RunArtifactStageInput, RunArtifactPayload, RunArtifactFinalizeInput, LiveStreamDeclaration, LiveFrame, LiveFrameEndReason, LiveFrameSubscription, FunctionCaller, RunEventEnvelope, RunStartAcknowledgement, RunSession, RunServiceReadiness, RunsLiveUrlResult, RunServiceDenialBody, MaskFn, LiveViewSubjectRef, LiveUrlVerdict, EditorLiveUrlResult, ConfigWriteIssue, ConfigChange, ConfigPathSegment, ConfigWriteRefusal, PlannerLimits } from '@vostride/agent-qa-schema';
3
+ import { RunDetailMember, RunDetailStep, RunDetailSubAction, RunDetailRows, RunStatus, RunArtifactKind, RunArtifactStageInput, RunArtifactPayload, RunArtifactFinalizeInput, LiveStreamDeclaration, LiveFrame, LiveFrameEndReason, LiveFrameSubscription, FunctionCaller, RunEventEnvelope, RunStartAcknowledgement, RunSession, RunServiceReadiness, RunsLiveUrlResult, MaskFn, LiveViewSubjectRef, LiveUrlVerdict, EditorLiveUrlResult, ConfigWriteIssue, ConfigChange, ConfigPathSegment, ConfigWriteRefusal, PlannerLimits } from '@vostride/agent-qa-schema';
4
4
  import { EventEmitter } from 'node:events';
5
5
  import { SecretStore, SecretRedactor, ConsoleLogEntry, NetworkLogEntry, StepAnnotation, StepPhaseEvent, StepResult } from '@vostride/agent-qa-runner';
6
6
  import { Node } from 'yaml';
@@ -45,7 +45,6 @@ interface RunRow {
45
45
  endedAt: string | null;
46
46
  failureSummary: string | null;
47
47
  errorLog: string | null;
48
- memoryLog: string | null;
49
48
  testId: string | null;
50
49
  suiteId: string | null;
51
50
  platform: string;
@@ -78,15 +77,6 @@ interface RunArtifactRow {
78
77
  createdAt: string;
79
78
  updatedAt: string;
80
79
  }
81
- /**
82
- * ONE RUN'S ARTIFACT, AND NOTHING ELSE (405-07, D-02).
83
- *
84
- * `children` stood here and is gone. It walked the run row's now-deleted parent link for the child
85
- * rows of a suite parent — a shape nothing has written since 402-09 put ONE `runs` row per run and moved member
86
- * identity onto `run_members`. A structurally-always-empty array on a response is worse than an
87
- * absent one: a reader cannot tell "this run has no children" from "children stopped being a fact
88
- * this product records", so the page renders an empty section forever and nobody notices.
89
- */
90
80
  interface RunArtifactBundle {
91
81
  artifact: RunArtifactRow | null;
92
82
  }
@@ -94,10 +84,6 @@ interface ExecutionLogRow {
94
84
  id: string;
95
85
  runId: string;
96
86
  stepId: string | null;
97
- /**
98
- * 405 D-01: where in the run tree this hook ran, from `HookFinishedPayload`'s own optional
99
- * fields. `null` means a RUN-SCOPED hook — a real state, not a missing value.
100
- */
101
87
  testIndex: number | null;
102
88
  stepIndex: number | null;
103
89
  type: 'hook' | 'appium-script' | 'runjs';
@@ -116,7 +102,6 @@ interface InsertExecutionLogInput {
116
102
  id: string;
117
103
  runId: string;
118
104
  stepId?: string | null;
119
- /** 405 D-01: the handle and step this hook belongs to; absent means run-scoped. */
120
105
  testIndex?: number | null;
121
106
  stepIndex?: number | null;
122
107
  type: 'hook' | 'appium-script' | 'runjs';
@@ -158,15 +143,6 @@ interface InsightsBreakdownRow {
158
143
  filePath?: string;
159
144
  suiteId?: string;
160
145
  }
161
- /**
162
- * What a run deletion removed (405-07, D-14 · T-405-27).
163
- *
164
- * ROWS ONLY. The two path arrays that stood here fed the router's filesystem cleanup, and both the
165
- * cleanup and the columns it read are gone: refs are the only artifact addressing now, and the run
166
- * directory under `.agent-qa/runs/` is the run's own record — the event log and the blobs — which
167
- * the dashboard never owned and must not delete. `deletedRunIds` survives as a one-element list
168
- * rather than collapsing to a boolean, because it is the shape the response already publishes.
169
- */
170
146
  interface DeleteRunResult {
171
147
  deleted: boolean;
172
148
  deletedRunIds: string[];
@@ -240,7 +216,6 @@ declare class DashboardDatabase {
240
216
  endedAt?: string;
241
217
  failureSummary?: string;
242
218
  errorLog?: string;
243
- memoryLog?: string;
244
219
  attributes?: RunAttributes;
245
220
  platform?: string;
246
221
  testId?: string;
@@ -270,20 +245,6 @@ declare class DashboardDatabase {
270
245
  getNextPendingRun(): RunRow | undefined;
271
246
  getPendingRuns(): RunRow[];
272
247
  updateRunStatus(id: string, status: string): boolean;
273
- /**
274
- * Write or refresh ONE member row, keyed by the handle `(run_id, test_index)`.
275
- *
276
- * AN UPSERT AND NOT TWO WRITES, because the member row is fed by two events at two times:
277
- * `testStarted` knows the identity fields and `testFinished` knows the outcome — and D-18
278
- * requires a member whose stream begins with a terminal event to render anyway, so the second
279
- * one alone has to be able to create the row.
280
- *
281
- * ONLY SUPPLIED FIELDS MOVE. `COALESCE(excluded.x, run_members.x)` on every optional column, so
282
- * a `testFinished` that carries no name cannot blank the name `testStarted` wrote. `attempts` is
283
- * excluded from the update entirely: it is the D-17 retry ordinal, owned by
284
- * `incrementRunMemberAttempts`, and an upsert that reset it would erase the fact the header
285
- * renders.
286
- */
287
248
  upsertRunMember(member: {
288
249
  runId: string;
289
250
  testIndex: number;
@@ -300,29 +261,8 @@ declare class DashboardDatabase {
300
261
  retryCount?: number;
301
262
  recording?: RunDetailMember['recording'];
302
263
  }): void;
303
- /**
304
- * Raise ONE member's attempt ordinal (D-17). A no-op when the member row does not exist yet —
305
- * a retry scheduled before any identity event is a real ordering, and inventing a row here
306
- * would put a member on the page that nothing has said anything about.
307
- */
308
264
  incrementRunMemberAttempts(runId: string, testIndex: number): void;
309
- /**
310
- * Drop ONE HANDLE's projected step and sub-action rows (D-17).
311
- *
312
- * SCOPED TO THE HANDLE, which was the whole change from the v1 run-wide step delete this
313
- * replaced (deleted outright by 405-07's census): that member wiped every step of the RUN on any
314
- * member's retry, so in a suite the abandoned attempt of test 3 deleted the completed history of
315
- * tests 0-2. The member row itself survives — its outcome and its attempt count are facts about
316
- * the member, not about the attempt. So do its setup and teardown hook rows, which run once per
317
- * member outside the retry loop; only the attempt's `inline` hook rows go (433-41, CR-01).
318
- */
319
265
  deleteMemberProjection(runId: string, testIndex: number): void;
320
- /**
321
- * Write ONE finalized step row. `INSERT OR REPLACE` because a re-run of the same handle re-emits
322
- * the same `(test_index, step_index)` and the LAST attempt is the one the page renders (D-17).
323
- *
324
- * The three token columns stay NULL when `tokenUsage` is absent — never 0 (D-05).
325
- */
326
266
  insertRunStep(step: {
327
267
  runId: string;
328
268
  testIndex: number;
@@ -359,14 +299,6 @@ declare class DashboardDatabase {
359
299
  ariaEvidence?: RunDetailSubAction['ariaEvidence'];
360
300
  recordingOffsetMs?: RunDetailSubAction['recordingOffsetMs'];
361
301
  }): void;
362
- /**
363
- * THE run-detail read (D-03). `undefined` when no `runs` row exists — absence is a RESULT here,
364
- * and turning it into a typed refusal is the `runs.detail` op's job, so the "not found"
365
- * vocabulary lives in the function layer rather than in this store.
366
- *
367
- * A run that exists and projected nothing answers three empty arrays, which is a DIFFERENT fact
368
- * and stays a different answer.
369
- */
370
302
  readRunDetailRows(runId: string): RunDetailRows | undefined;
371
303
  private appendAttributePredicateConditions;
372
304
  private applyRegexAttributePredicates;
@@ -408,20 +340,6 @@ declare class DashboardDatabase {
408
340
  limit?: number;
409
341
  q?: string;
410
342
  }): AttributeValueSuggestion[];
411
- /**
412
- * Delete ONE run and everything the schema hangs off it (405-07, D-02/D-14 · T-405-27).
413
- *
414
- * ONE ID, AND THE CASCADE DOES THE REST. This used to open with a recursive `run_tree` CTE that
415
- * walked the child rows of a suite parent, then hand-delete their step and trace rows in a
416
- * transaction. Nothing has written a child row since 402-09 — one `runs` row per run, member
417
- * identity on `run_members` — so the walk could only ever return the one row it was seeded with,
418
- * and the hand-deletes named tables this schema no longer has. Every table that references a run
419
- * declares `ON DELETE CASCADE`, so the single statement below is the whole deletion.
420
- *
421
- * AND IT TOUCHES NO FILE. The two path arrays it used to collect fed the router's artifact
422
- * cleanup; both are gone. The run's directory under `.agent-qa/runs/` — its event log and its
423
- * content-addressed blobs — is the run's own record and is not the dashboard's to remove.
424
- */
425
343
  deleteRun(id: string): DeleteRunResult;
426
344
  insertRunArtifact(input: {
427
345
  runId: string;
@@ -432,15 +350,6 @@ declare class DashboardDatabase {
432
350
  finalizeRunArtifact(runId: string, updates?: RunArtifactFinalizeInput): RunArtifactRow;
433
351
  getRunArtifact(runId: string): RunArtifactRow | null;
434
352
  getRunArtifactBundle(runId: string): RunArtifactBundle;
435
- /**
436
- * The runs a self-heal happened on (405-07, D-02).
437
- *
438
- * READ OFF `run_steps.self_heal_occurred`, WHICH IS THE SURVIVING HEALING FACT. This scanned the
439
- * v1 wide step table for `status = 'healed'`; that table had no producer left and its readers
440
- * went with it. `selfHealOccurred` is the bus payload's own boolean, projected verbatim by the
441
- * subscriber — so the flake rate below is now computed from what the runner actually reported
442
- * rather than from a status word a retired projection wrote.
443
- */
444
353
  private getHealedRunIds;
445
354
  private summarizeAnalyticsRuns;
446
355
  private listRunsForInsights;
@@ -459,14 +368,6 @@ declare class DashboardDatabase {
459
368
  healed: number;
460
369
  duration: number;
461
370
  }[];
462
- memory: {
463
- runs: number;
464
- added: number;
465
- confirmed: number;
466
- deprecated: number;
467
- deleted: number;
468
- curatorTokens: number;
469
- };
470
371
  };
471
372
  getCostStats(opts?: StatsOptions): {
472
373
  runs: {
@@ -509,12 +410,6 @@ declare class DashboardDatabase {
509
410
  };
510
411
  testRunUnmeasuredSteps: number;
511
412
  };
512
- /**
513
- * The window's settled run ids, newest first, capped at `limit`, with their full count, and the
514
- * count of the window's runs still in flight (433-30, 433-42). A settled run has started and is
515
- * neither `pending` nor `running`; every other row in the window is in flight. Ids only: the
516
- * Insights knowledge-change read dispatches each through the agent host.
517
- */
518
413
  listInsightsWindowRunIds(opts: {
519
414
  from?: string;
520
415
  to?: string;
@@ -602,99 +497,19 @@ interface ExecuteOptions {
602
497
  source: string;
603
498
  attributes?: RunAttributes;
604
499
  timeout?: number;
605
- /**
606
- * The Appium lease URL for a mobile run, AS DATA (401-07, D-01/D-12).
607
- *
608
- * The bundled Appium spawn is design-of-record and stays exactly where it is; what changed is the
609
- * DELIVERY. It used to ride `AGENT_QA_APPIUM_URL` in a child's environment, and a child env is
610
- * something only a child has. The run happens in this process now, so the lease travels as an
611
- * argument and is handed to the run through an injected resolver.
612
- */
613
500
  appiumUrl?: string;
614
501
  }
615
- /**
616
- * A run has reached a terminal state (401-07, D-04/D-12).
617
- *
618
- * THE TYPED SUCCESSOR TO THE CHILD'S `close` EVENT. The host reconciles a db row still reading
619
- * `running`, releases the run's Appium lease and frees the queue slot off this — exactly what it did
620
- * off the process exit — but the status is now the bus's own ground truth and the `details` carry
621
- * the failure's REASON rather than a scraped tail of stderr.
622
- *
623
- * `'run-settled'` is now the WHOLE of this emitter's contract. A second event carried the retired
624
- * live feed's frames and went with it (405-07, D-19).
625
- */
626
502
  interface RunSettledDetails {
627
- /**
628
- * A human-readable reason when the run did not simply finish. 2026-09-30, 432-09 (D-15): a
629
- * refusal is this plain reason. No remedy list rides the settle; nothing asks the reader to act.
630
- */
631
503
  readonly reason?: string;
632
- /**
633
- * The run NEVER BEGAN — the gate or the host refused it (401-18, G-401-16).
634
- *
635
- * A FACT, NOT AN INFERENCE. `settle` has always known this — a rejection with no started session
636
- * is a denial, a refused request field or an input error — and threw the knowledge away, leaving
637
- * the host's reconciliation to guess from a regex over the diagnostic lines. It guessed
638
- * `Process exited before test completed`, which is a sentence about a process, for a run where
639
- * nothing was ever started to exit.
640
- *
641
- * DELIBERATELY A BOOLEAN AND NOT A CLASS. Which refusal it was — `fail-closed-denied`, `blocked`,
642
- * `session-pin-denied`, an unrecognised request field, a plain input error — is not something the
643
- * reconciliation branches on, and a prose name for it here would be the same defect one layer
644
- * down. If a class is ever needed it arrives as a closed-set value owned by `schema`.
645
- *
646
- * ABSENT ON A RUN THAT STARTED, including one that started and then failed. That asymmetry is the
647
- * scope guarantee: every other arm of the reconciliation reads exactly what it read before.
648
- */
649
504
  readonly refusedBeforeStart?: true;
650
- /**
651
- * The refusal said without naming any surface's affordance (401-18, G-401-16).
652
- *
653
- * The gate composed two sentences per decision: the canonical one, which named the session trust
654
- * flag and landed in the execution-audit row, and the neutral one, which stops at the classification and the outcome.
655
- * A browser reader was being handed the first, so the record's only account of why a run never
656
- * happened told them to pass a flag to a command they were not running.
657
- *
658
- * READ STRUCTURALLY OFF THE REJECTION, and ABSENT where the
659
- * rejection carries no neutral form — an input error is not a gate decision and has no second
660
- * phrasing. The consumer then falls back to the rejection's own message, which for those refusals
661
- * names no surface's affordance either.
662
- */
663
- readonly neutralReason?: string;
664
505
  /** Diagnostic lines — a rejection's own message. The typed successor to scraped stderr. */
665
506
  readonly output: readonly string[];
666
507
  }
667
508
  type RunSettledStatus = 'completed' | 'failed' | 'cancelled' | 'timeout';
668
- /** A trigger's request as the queue would carry it, before anything is recorded (433-34). */
669
- interface PreflightOptions {
670
- readonly args: string[];
671
- readonly source: 'dashboard' | 'suite';
672
- }
673
509
  interface ExecutionBackend extends EventEmitter {
674
510
  execute(opts: ExecuteOptions): void;
675
- /**
676
- * Ask the run core whether this request may start, before a row is minted or anything enqueued
677
- * (433-34, G-433-10).
678
- *
679
- * The composing host answers with the core's own production rule over the members' declared
680
- * targets; this package decides nothing about production. A refusal rejects with the core's
681
- * denial, which carries `neutralReason`. Absent on a backend whose host composes no preflight.
682
- */
683
- preflight?(opts: PreflightOptions): Promise<void>;
684
511
  kill(runId: string): boolean;
685
512
  killAll(): void;
686
- /**
687
- * The runs this backend currently has in flight, as `GET /api/execution/active` serves them.
688
- *
689
- * `testName` IS ON THE INTERFACE (405-07, D-19). It used to be produced by scanning a per-run
690
- * event buffer for a `testStarted` frame — a read that only the concrete class could perform,
691
- * through a member the interface did not declare. It is now recorded on the run handle by the
692
- * backend's own bus subscription, so the field is part of the contract every implementation
693
- * answers rather than a property of one implementation's internal storage.
694
- *
695
- * ABSENT MEANS NO MEMBER HAS STARTED YET, which is a real state on a run between its start and
696
- * its first `testStarted`; it is never filled with the run id or a placeholder.
697
- */
698
513
  getActiveExecutions(): {
699
514
  runId: string;
700
515
  status: string;
@@ -751,110 +566,18 @@ type AgentRegistryHandle = object;
751
566
  interface AgentHost {
752
567
  /** The composed registry every call goes through. Opaque here. */
753
568
  readonly registry: AgentRegistryHandle;
754
- /**
755
- * The caller this door dispatches as, MINTED by the composition root and never by this package.
756
- *
757
- * Attribution and grants both. The composer derives it from the CLI chat door's own mint with
758
- * only the surface name changed (D-08/Pitfall 9) — a hand-typed scope list here would be the
759
- * drift vector the parity legs exist to catch, and this package could not type-check one anyway.
760
- */
761
569
  readonly caller: FunctionCaller;
762
- /**
763
- * The agent package's `runs.postprocessing` id (404 D-16/D-18).
764
- *
765
- * SUPPLIED BY THE COMPOSITION, NEVER SPELLED HERE. The post-processing read route dispatches
766
- * chip truth through this door, and the op id is the agent package's constant: a string literal
767
- * in this package would be a second declaration of a capability's name, free to drift from the
768
- * spec that answers to it. This package also may not import `@vostride/agent-qa-agent`
769
- * (validate:arch), so there is nowhere here the real constant could come from.
770
- */
771
570
  readonly runsPostProcessingFunctionId: string;
772
- /**
773
- * The agent package's `runs.events` id, on the line above's footing (404 D-22).
774
- *
775
- * A SECOND ID BECAUSE THE READ ROUTE JOINS TWO FACTS from two different records: the chain's
776
- * chips live in the durable job store, and the run's POSTURE — who was going to drain it — lives
777
- * on the `runFinished` line of the run's own event log, beside the last per-stage failure text.
778
- * Reading the log any other way would mean this package opening a file the function layer owns.
779
- */
780
571
  readonly runsEventsFunctionId: string;
781
- /**
782
- * The agent package's `runs.detail` id, on `runsPostProcessingFunctionId`'s exact footing (405
783
- * D-03).
784
- *
785
- * SUPPLIED BY THE COMPOSITION, NEVER SPELLED HERE, for the reason its two neighbours are: the
786
- * op id is the agent package's constant, a string literal in this package would be a second
787
- * declaration of a capability's name free to drift from the spec that answers to it, and this
788
- * package may not import `@vostride/agent-qa-agent` at all (validate:arch) — so there is nowhere
789
- * here the real constant could come from.
790
- *
791
- * WHAT IT REPLACES is worth naming: run detail used to be assembled by reading SQLite from
792
- * inside the router. Routing it through this id is what makes the same durable read available
793
- * to the CLI, MCP and chat instead of to the browser alone.
794
- */
795
572
  readonly runsDetailFunctionId: string;
796
573
  /** The evidence op identity supplied by the same composition as the detail reader. */
797
574
  readonly runsEvidenceFunctionId: string;
798
- /**
799
- * The agent package's `runs.artifact` id, on `runsDetailFunctionId`'s exact footing (405 D-13).
800
- *
801
- * SUPPLIED BY THE COMPOSITION, NEVER SPELLED HERE, for the reason its four neighbours are — and
802
- * for one more that is specific to this route: the artifact arm serves BYTES, and the alternative
803
- * to dispatching them through the function layer is this package constructing the evidence store
804
- * and reading a file. That would be a private store read no roster row covers and no audit sink
805
- * sees, on a path whose two inputs both arrive from a URL. Routing it through an id is what makes
806
- * the containment rule the store's own and the capability one the CLI, MCP and 408's embed reach
807
- * the same way.
808
- */
809
575
  readonly runsArtifactFunctionId: string;
810
- /**
811
- * The agent package's `analysis.get` id, on `runsArtifactFunctionId`'s exact footing (406 D-04).
812
- *
813
- * SUPPLIED BY THE COMPOSITION, NEVER SPELLED HERE, for the reason its five neighbours are: the
814
- * op id is the agent package's constant, a string literal in this package would be a second
815
- * declaration of a capability's name free to drift from the spec that answers to it, and this
816
- * package may not import `@vostride/agent-qa-agent` at all (validate:arch) — so there is nowhere
817
- * here the real constant could come from.
818
- *
819
- * WHAT IT SERVES is the failure view: the resolved verdicts and rendered sentences a person
820
- * reads inside each failed member's group, on BOTH doors through one adapter. `analysis.get` is
821
- * the single producer of those sentences (389 D-11), so routing the page's read through this id
822
- * is what keeps the browser, the CLI, chat and 408's embed reading one answer.
823
- */
824
576
  readonly analysisGetFunctionId: string;
825
- /**
826
- * The agent package's `runs.knowledge` id, on `analysisGetFunctionId`'s exact footing
827
- * (2026-08-29, 407-01 D-05).
828
- *
829
- * THE SIXTH ID THE RUN-SERVICE ROUTES DISPATCH, supplied by the composition and never spelled
830
- * here, for the reason its five neighbours are: the op id is the agent package's constant, a
831
- * string literal in this package would be a second declaration of a capability's name free to
832
- * drift from the spec that answers to it, and this package may not import
833
- * `@vostride/agent-qa-agent` at all (validate:arch) — so there is nowhere here the real constant
834
- * could come from.
835
- *
836
- * WHAT IT SERVES is the Knowledge panel: what a run USED (the brief channels served per step,
837
- * the serve-time trace behind each, procedure replay and hint use, the recorded retrieval rung)
838
- * and what it LEARNED (curation counts, the record changes attributable to it, canary outcomes).
839
- * `runs.knowledge` is the single producer of that whole view (407 D-05), so routing the page's
840
- * read through this id is what keeps the browser, the CLI, MCP and chat reading one answer
841
- * instead of a page composing it from N per-step calls that can disagree.
842
- */
843
577
  readonly runsKnowledgeFunctionId: string;
844
- /** 2026-09-08, 419 D-13: the eighth op id arrives as data, on the knowledge id's footing. */
845
578
  readonly runsMarkFunctionId: string;
846
- /** 2026-09-15, 423-21 D-18: the marks-history read id, supplied as data like its neighbours. */
847
579
  readonly runsMarksHistoryFunctionId: string;
848
- /** 2026-09-15, 423-21 D-18: the read-tier mark consequence preview id. */
849
580
  readonly runsMarkPreviewFunctionId: string;
850
- /**
851
- * `invokeFunction`, bound by the composer. THE one door call.
852
- *
853
- * `input` IS `unknown` (404-05). Every op this seam carries has its own strict input schema.
854
- * Narrowing here would mean this package describing other packages' input contracts — and the
855
- * real `invokeFunction` has always taken `unknown`, because the op's own schema is what validates
856
- * it, once, inside the invocation.
857
- */
858
581
  invokeFunction(registry: AgentRegistryHandle, functionId: string, input: unknown, caller: FunctionCaller): Promise<unknown>;
859
582
  }
860
583
 
@@ -878,24 +601,10 @@ interface PostProcessingRelay {
878
601
  }
879
602
  declare function createPostProcessingRelay(): PostProcessingRelay;
880
603
 
881
- /**
882
- * What starting a run needs from the composition, as data rather than as a live handle.
883
- *
884
- * 2026-10-01 (432-21, D-12): the matched token's `trustScope` and `clientId` are deleted with the
885
- * token. A start carries the caller's pattern set and nothing about who the caller is.
886
- */
887
604
  interface RunServiceStartInput {
888
605
  /** The pattern set the caller asked for; absent means the configured default set. */
889
606
  readonly patterns?: readonly string[];
890
607
  }
891
- /**
892
- * Everything this door reaches the world through (D-02).
893
- *
894
- * ALL ARE INJECTED, and the injection is what makes the module mountable: the implementations name
895
- * `invokeFunction`, `runs.start` and a composed local host, all of it vocabulary this package may
896
- * not import. `InProcessRunStarter` is the shape precedent one directory over. 2026-10-01 (432-21,
897
- * D-12): `verifyBearer` is deleted; the same-site guard needs no port.
898
- */
899
608
  interface RunServicePorts {
900
609
  /**
901
610
  * Start a run and return the acknowledgment.
@@ -906,36 +615,9 @@ interface RunServicePorts {
906
615
  invokeRunStart(input: RunServiceStartInput): Promise<RunStartAcknowledgement>;
907
616
  /** The started run's session, or nothing if this process never started that run. */
908
617
  attach(runId: string): RunSession | undefined;
909
- /** The measured readiness facts `/ok` reports (D-15). */
618
+ /** The measured readiness facts `/ok` reports. */
910
619
  readiness(): RunServiceReadiness;
911
- /**
912
- * Mint a live-view URL for one handle of a run (403 D-03).
913
- *
914
- * REQUIRED, NOT OPTIONAL, and that is a decision rather than an oversight. An optional member is
915
- * a member a composition can forget, and the failure mode of forgetting it here is a 404 that
916
- * reads exactly like "no such route" — which is what a door with no live view is indistinguishable
917
- * from. A composition that cannot mint supplies a function that REJECTS with a
918
- * `LiveViewUnavailableError`-named error, which the arm maps to 503 `live_view_unavailable`: an
919
- * honest host fact, said out loud, once, in the vocabulary the local door already uses.
920
- *
921
- * The minted token's own subject (run, handle) and expiry are checked by the live-view validator
922
- * independently of who asked (D-13). 2026-10-01 (432-21, D-12): the bearer's trust scope this mint
923
- * used to run under is deleted; the composition supplies the one caller it runs under.
924
- */
925
620
  mintLiveUrl(input: MintLiveUrlInput): Promise<RunsLiveUrlResult>;
926
- /**
927
- * The injected agent host the two READ rows dispatch through (405-05, D-12/D-13).
928
- *
929
- * OPTIONAL, unlike `mintLiveUrl` above, and the asymmetry is deliberate rather than an
930
- * oversight. `mintLiveUrl` is required because a composition that forgot it would answer a 404
931
- * indistinguishable from an unserved path — but the argument runs the other way here: a host
932
- * genuinely composed without a function registry (a bare mount, this file's own fixtures) has no
933
- * capability to reach, and the honest answer is the SAME 503 `agent_host_unavailable` the local
934
- * door already gives for exactly this state. One word, one meaning, both doors.
935
- *
936
- * It is a HANDLE and nothing else — this package may not name the agent packages, so what
937
- * crosses is the seam `chat/host.ts` declares and the op ids the composition supplies as data.
938
- */
939
621
  readonly agentHost?: AgentHost;
940
622
  }
941
623
  /** What minting one `liveUrl` needs from a request, as data: the subject, and nothing else. */
@@ -955,67 +637,30 @@ interface RunServiceRouteRow {
955
637
  }
956
638
  declare const RUN_SERVICE_START_ROUTE = "/run";
957
639
  declare const RUN_SERVICE_EVENTS_TEMPLATE = "/run/:runId/events";
958
- /**
959
- * The MINT (403 D-03, Q3) — the remote half of the pair whose local half is
960
- * `GET /api/runs/:runId/live-url`.
961
- *
962
- * SAME SHAPE AS THE EVENTS ROUTE ONE LINE UP, deliberately: a caller addresses a run it started by
963
- * id and asks this door for one thing about it per route. Since 432-21 the two doors differ in
964
- * nothing but the path — the same op, the same caller shape, the same result and fragment carriage.
965
- */
966
640
  declare const RUN_SERVICE_LIVE_URL_TEMPLATE = "/run/:runId/live-url";
967
641
  /**
968
- * Readiness (D-15) — behind the same-site guard, like every other route on this door.
969
- *
970
- * An `/ok` that answered before the guard would tell a page on another origin that this process is
971
- * an agent-qa run service and that it is up. (Until 432-21 the guard here was the bearer verdict,
972
- * and the preflight was liveness and early token validation in one round-trip.)
973
- */
974
- /**
975
- * The durable run-detail READ (405-05, D-12 / 402 D-16) — the remote twin of the local door's
976
- * `GET /api/runs/:id/detail`.
642
+ * The durable run-detail READ — the remote twin of the local door's `GET /api/runs/:id/detail`.
977
643
  *
978
644
  * IT DISPATCHES THROUGH THE SAME ADAPTER THE LOCAL DOOR CALLS. `serveRunDetailRead` is one
979
645
  * function, so the two doors cannot come to disagree about what a run's projection is; a second
980
646
  * spelling here would agree on the day it was written and be a wire-contract fork thereafter.
981
647
  *
982
- * THIS ROW IS MASKED, and deliberately. It is a machine wire like `/run/:runId/events` one line up
983
- * — its consumer (the CLI's own `emitHuman`, 408's embed) is where a person meets the text, and
984
- * that consumer is the display boundary. The alternative would restore declared secrets onto a
985
- * machine wire, extending the disclosure surface to every client and every intermediary, which is
986
- * not what "the browser is never the boundary" (400-06) asks for. 405-10
987
- * applies the unmask seam to the LOCAL door only and enrols this row on the masked side.
648
+ * This row serves the same stored body the local door serves, masked at write.
988
649
  */
989
650
  declare const RUN_SERVICE_DETAIL_TEMPLATE = "/run/:runId/detail";
990
651
  declare const RUN_SERVICE_EVIDENCE_TEMPLATE = "/run/:runId/evidence";
991
- /**
992
- * The ref-resolving artifact READ (405-05, D-12 / 402 D-16) — the remote twin of the local door's
993
- * `GET /api/runs/:runId/artifacts/:sha`, and the row 402 D-16 named by anticipation.
994
- *
995
- * TWO CAPTURES, `[^/]+` ON BOTH. The runId is decoded and the sha is not: a content address is 64
996
- * characters from `[0-9a-f]`, none of which percent-encoding can represent differently, so a sha
997
- * segment that needed decoding is already not one.
998
- *
999
- * MASKED, LIKE ITS SIBLING AND MORE SO: these are BYTES. The unmask seam never touches an artifact
1000
- * body on any door (D-09) — a screenshot is not text and there is nothing in it to restore.
1001
- */
1002
652
  declare const RUN_SERVICE_ARTIFACT_TEMPLATE = "/run/:runId/artifacts/:sha";
1003
653
  /**
1004
- * The run-ANALYSIS read (406-01, D-04) — the remote twin of the local door's
1005
- * `GET /api/runs/:id/analysis`.
654
+ * The run-ANALYSIS read — the remote twin of the local door's `GET /api/runs/:id/analysis`.
1006
655
  *
1007
656
  * IT DISPATCHES THROUGH THE SAME ADAPTER THE LOCAL DOOR CALLS, for the reason its detail sibling
1008
657
  * does: `serveRunAnalysisRead` is one function, so the two doors cannot come to disagree about
1009
658
  * what a run's analysis is.
1010
659
  *
1011
- * THIS ROW IS MASKED, AND FOR THE REASON ITS SIBLING IS. The verdict sentence quotes the failing
1012
- * step's recorded error, which carries declared placeholders at rest; restoring them onto a
1013
- * machine wire would hand them to every client and every intermediary, and this row's
1014
- * consumer — the CLI's own emit, 408's embed — is where a person meets the text. The dispatch
1015
- * below passes no `boundary`, and the option's `'machine'` default is what keeps it masked.
660
+ * This row serves the same stored body the local door serves, masked at write.
1016
661
  */
1017
662
  declare const RUN_SERVICE_ANALYSIS_TEMPLATE = "/run/:runId/analysis";
1018
- /** 2026-09-15, 423-21 D-18: runs.marks.history and runs.mark.preview behind the same guard. */
663
+ /** runs.marks.history and runs.mark.preview behind the same guard. */
1019
664
  declare const RUN_SERVICE_MARKS_TEMPLATE = "/run/:runId/marks";
1020
665
  declare const RUN_SERVICE_MARK_PREVIEW_TEMPLATE = "/run/:runId/mark-preview";
1021
666
  declare const RUN_SERVICE_OK_ROUTE = "/ok";
@@ -1040,10 +685,9 @@ declare function matchRunServiceRoute(method: string | undefined, path: string):
1040
685
  /**
1041
686
  * Whether a path belongs to this door — the MOUNT's whole question, and method-blind on purpose.
1042
687
  *
1043
- * A host consults this before its own routing so that every request to a service path, including
1044
- * an `OPTIONS` preflight and a method this table has no row for, is answered by this door rather
1045
- * than by the host's generic handling. That is what keeps the host's wildcard CORS preflight and
1046
- * its SPA fallback away from this surface.
688
+ * A host consults this before its own routing, so every request to a service path, `OPTIONS` and
689
+ * methods this table has no row for included, gets this router's same-site and media-type checks
690
+ * rather than the host's page arms.
1047
691
  *
1048
692
  * DERIVED FROM THE TABLE, never a second list: the prefixes are read off the rows, so a route
1049
693
  * added above is mounted the same commit.
@@ -1054,15 +698,6 @@ interface RunServiceRouter {
1054
698
  /** Live SSE connections — so a host can assert this door leaks none on teardown. */
1055
699
  openStreamCount(): number;
1056
700
  }
1057
- /**
1058
- * Where a stream request asked to resume from. Three arms, and the count is the contract.
1059
- *
1060
- * `start` is "the caller has observed nothing", `after` carries the last seq it DID observe, and
1061
- * `invalid` is a fact about the caller's own input. There is deliberately no fourth arm meaning
1062
- * "unparseable, serve them from the beginning": silently restarting a resume at seq 1 would
1063
- * re-deliver every envelope the caller already has, and silently serving from the floor would hide
1064
- * a gap — the two answers D-13 refuses by name.
1065
- */
1066
701
  type ResumePoint = {
1067
702
  readonly kind: 'start';
1068
703
  } | {
@@ -1071,49 +706,14 @@ type ResumePoint = {
1071
706
  } | {
1072
707
  readonly kind: 'invalid';
1073
708
  };
1074
- /**
1075
- * The DENIAL this rejection is, if it is one — read structurally, never by class (402-06, T-402-22).
1076
- *
1077
- * ON `dashboardNeutralReasonOf`'S EXACT PRECEDENT (`execution/in-process-backend.ts`), and for the
1078
- * same architectural reason: the rejection is a `RunDeniedError` minted in `agent-local`, and this
1079
- * package may not import `agent`, `agent-local` or `safety` — `pnpm validate:arch` is the
1080
- * mechanical proof.
1081
- *
1082
- * THE DISCRIMINATOR IS `neutralReason`, DELIBERATELY. Only a run denial carries it: an
1083
- * unrecognised request field, an input error and "the host was asked to start a run before it was
1084
- * composed" carry none, and those are exactly the rejections that must stay a 500 with no words on
1085
- * them. Keying on the class NAME would be a string compare against another package's private
1086
- * vocabulary.
1087
- *
1088
- * 2026-10-01 (432-19, D-15): there is no remedy list to validate or project. The production refusal
1089
- * never carried one, and the remedy vocabulary left with the execution gate.
1090
- */
1091
- declare function runDenialOf(error: unknown): RunServiceDenialBody | undefined;
1092
709
  declare function createRunServiceRoutes(ports: RunServicePorts): RunServiceRouter;
1093
710
 
1094
711
  interface StartServerOptions {
1095
712
  db: DashboardDatabase;
1096
713
  port?: number;
1097
- /**
1098
- * The interface this server binds (402-05, D-07 — INVK-03).
1099
- *
1100
- * DEFAULTS TO LOOPBACK, and a non-loopback value is REFUSED before anything listens — with no
1101
- * exemption. This is BREAKING for anyone who relied on the previous `server.listen(port)`, which
1102
- * bound every interface, and there is no migration flag: the v2 ethos ships no back-compat shim
1103
- * for a hole. Remote access goes through an authenticating proxy (432 D-13's forward note).
1104
- */
714
+ /** Defaults to loopback; any other value is refused before anything listens. */
1105
715
  host?: string;
1106
716
  uiDir?: string;
1107
- /**
1108
- * Where this workspace writes run artifacts (`services.dashboard.artifactsDir`).
1109
- *
1110
- * ACCEPTED AND NOT READ BY THIS SERVER SINCE 405-07 (D-14). It used to be resolved into a
1111
- * screenshots and a videos root that two path-serving routes and the run-deletion sweep read.
1112
- * Refs are the only artifact addressing now, and the bytes are reached through the
1113
- * `runs.artifact` op over the evidence store's own layout. The option stays declared because it
1114
- * is a user-facing config key the RECORDING path still writes under; the dashboard simply no
1115
- * longer serves or deletes anything by path.
1116
- */
1117
717
  artifactsDir?: string;
1118
718
  workspacePaths?: ResolvedWorkspacePaths;
1119
719
  configPath?: string;
@@ -1125,112 +725,20 @@ interface StartServerOptions {
1125
725
  };
1126
726
  };
1127
727
  authFetch?: typeof globalThis.fetch;
1128
- /**
1129
- * The composed agent host the chat door dispatches through (400-01, D-01).
1130
- *
1131
- * INJECTED by whoever starts this server — in production `agent-qa dashboard`, which composes the
1132
- * SAME port set `agent-qa chat` does and hands it over, so the two interactive doors have one
1133
- * answer to "what can a conversation do" (D-08). Absent leaves the chat routes answering 501 by
1134
- * name: the door exists, this process was started without a host. See `chat/host.ts`.
1135
- */
1136
728
  agentHost?: AgentHost;
1137
- /**
1138
- * The backend every dashboard run executes through (401-07, D-01/D-09/D-10 — INVK-01).
1139
- *
1140
- * INJECTED, ON `agentHost`'s OWN IDIOM AND FOR ITS OWN REASON. The implementation that starts a
1141
- * run names `runs.start`, `invokeFunction` and the composed local host — all of it
1142
- * `@vostride/agent-qa-agent*` vocabulary this package may not import (validate:arch). So
1143
- * `agent-qa dashboard` composes it in the process that runs this server and hands it over, which
1144
- * is what makes the run button one more caller of the op chat already uses rather than a
1145
- * dashboard carve-out around the gates.
1146
- *
1147
- * ABSENT DEGRADES BY NAME, exactly as it did when the CLI binary could not be resolved: the
1148
- * execution routes answer 503 and the queue's execute handler does nothing. A dashboard started
1149
- * without a run door is a dashboard that cannot run tests, and it says so.
1150
- */
1151
729
  executionBackend?: ExecutionBackend;
1152
- /**
1153
- * The run service's ports (402-01, D-02/D-06 — INVK-03).
1154
- *
1155
- * INJECTED, ON `agentHost`'s AND `executionBackend`'s OWN IDIOM AND FOR THEIR OWN REASON. The
1156
- * implementations name `runs.start`, `invokeFunction` and the composed local host — all of it
1157
- * vocabulary this package may not import (validate:arch). So `agent-qa dashboard` composes them
1158
- * in the process that runs this server and hands them over, which is what makes the run service
1159
- * a mountable module rather than a fourth process.
1160
- *
1161
- * ABSENT MEANS THE SERVICE IS NOT MOUNTED, and `/run` and its neighbours reach whatever the
1162
- * static/SPA handling below does with an unknown path. 2026-10-01 (432-21, D-12): `agent-qa
1163
- * dashboard` supplies it unconditionally now. It used to mount only when a run-service credential
1164
- * was declared, and those credentials are deleted; the door is guarded by the same-site check
1165
- * and the loopback bind like every other door here. Absent is a bare in-process mount's posture.
1166
- */
1167
730
  runService?: RunServicePorts;
1168
- /**
1169
- * The run service's readiness predicate, served WITHOUT a token on the local dashboard API
1170
- * (402-05, D-15 — `GET /api/run-readiness`).
1171
- *
1172
- * SEPARATE FROM `runService` ABOVE AND NOT DERIVED FROM IT, because a mount without the service
1173
- * still has a browser that needs an honest readiness answer rather than a 404. `agent-qa
1174
- * dashboard` supplies the very same function object it put on `runService.readiness`: one
1175
- * predicate, two doors. (Until 432-21 the service was absent whenever no credential was declared.)
1176
- */
1177
731
  runServiceReadiness?: () => RunServiceReadiness;
1178
- /**
1179
- * The run id → live `RunSession` lookup, as a FIRST-CLASS option (403 D-14 — WINDOWS #264).
1180
- *
1181
- * SEPARATE FROM `runService` AND NOT DERIVED FROM IT, on `runServiceReadiness`'s exact argument
1182
- * one field up. The derivation `runService?.attach` is what made the local run-stream door
1183
- * answer 503 about runs this very process was executing: until 432-21 `composeRunServicePorts`
1184
- * ran only when `runServiceTokens` were declared, so the DEFAULT zero-token dashboard composed no
1185
- * registry at all and the local door had nothing to attach to. `agent-qa dashboard` supplies this
1186
- * from a registry hoisted above the door.
1187
- *
1188
- * The legacy derivation still applies when this is absent, so an in-process caller that only
1189
- * passes `runService` keeps working byte-for-byte.
1190
- */
1191
732
  runServiceAttach?: (runId: string) => RunSession | undefined;
1192
- /**
1193
- * The live-view seam (403 D-03/D-06): the function layer's validator, by reference, and the
1194
- * mint dispatched through the registry.
1195
- *
1196
- * ABSENT MEANS NO LIVE VIEW IS SERVED — the embed route is not registered, the frame socket
1197
- * refuses the upgrade, and `GET /api/runs/:runId/live-url` answers 503 by name. This server
1198
- * holds NO signing key and NO token parse of its own; both are the function layer's, handed in.
1199
- */
1200
733
  liveView?: {
1201
734
  validate(token: string, expect: {
1202
735
  subject: LiveViewSubjectRef;
1203
736
  now: number;
1204
737
  }): LiveUrlVerdict;
1205
738
  mintLiveUrl(runId: string, handle: number): Promise<RunsLiveUrlResult>;
1206
- /**
1207
- * The `editor.liveurl` mint, dispatched through the registry (428 D-07). ABSENT MEANS NO
1208
- * EDITOR VIEW IS MINTED, and `GET /api/live-editor/sessions/:id/live-url` answers 503 by name.
1209
- */
1210
739
  mintEditorLiveUrl?(sessionId: string): Promise<EditorLiveUrlResult>;
1211
740
  };
1212
- /**
1213
- * The editor-subject registry (428 D-07): the session manager registers each live editor session
1214
- * here and the frame socket attaches editor subjects through it.
1215
- *
1216
- * ABSENT MEANS NO EDITOR SUBJECT IS SERVED ON THE FRAME SOCKET. `agent-qa dashboard` creates one
1217
- * registry and hands the same object to the live-view composition and to this server.
1218
- */
1219
741
  liveEditorSubjects?: LiveEditorSubjects;
1220
- /**
1221
- * The in-process post-processing chip relay (404-05, D-16).
1222
- *
1223
- * INJECTED, ON `agentHost`'s OWN IDIOM AND FOR ITS OWN REASON. The PUBLISHER is the CLI's
1224
- * post-run chip emitter, in this same process, and this package may not import it — so
1225
- * `agent-qa dashboard` creates one relay, hands `relay.publish` to the run door's bridge as the
1226
- * emitter's second sink and hands the relay itself here. It has to be the SAME object: a relay
1227
- * built inside this function would be a registry nothing publishes to, and the stream door would
1228
- * heartbeat forever at a page whose chips are demonstrably moving.
1229
- *
1230
- * ABSENT MEANS NO PUSH CHANNEL, and `GET /api/runs/:id/post-processing/stream` answers 503 by
1231
- * name. The READ route needs none of this and keeps working: polling is the floor the whole
1232
- * design rests on, and the stream is the optimisation over it.
1233
- */
1234
742
  postProcessingRelay?: PostProcessingRelay;
1235
743
  }
1236
744
  declare function startServer(opts: StartServerOptions): Promise<{
@@ -1303,10 +811,6 @@ type FieldState = {
1303
811
  present: true;
1304
812
  value: unknown;
1305
813
  };
1306
- /**
1307
- * What one change found and left at the field it touched (429-11 D-24). The nodes are the file's
1308
- * own, so a restore brings back real secrets and comments rather than anything the page holds.
1309
- */
1310
814
  type ConfigPrior = {
1311
815
  kind: 'entry';
1312
816
  array: ConfigPathSegment[];
@@ -1320,7 +824,7 @@ type ConfigPrior = {
1320
824
  after: FieldState;
1321
825
  };
1322
826
  type ConfigPriors = readonly ConfigPrior[];
1323
- /** A whole-document replacement, checked against the bytes the caller read (432-07 D-05). */
827
+ /** A whole-document replacement, checked against the bytes the caller read. */
1324
828
  type ReplaceDocumentOutcome = {
1325
829
  kind: 'ok';
1326
830
  revision: string;
@@ -1374,10 +878,6 @@ declare function serializeConfigWrite<T>(configPath: string, work: () => Promise
1374
878
  declare class ConfigFileInvalidError extends Error {
1375
879
  constructor(message: string);
1376
880
  }
1377
- /**
1378
- * The config's values for a reader that only needs them (429-32, Pitfall 3): a missing file reads
1379
- * as empty, and a file that does not parse is an error rather than the part of it yaml recovers.
1380
- */
1381
881
  declare function readConfigValues(manager: ConfigManager): Promise<Record<string, unknown>>;
1382
882
  declare class ConfigManager {
1383
883
  private configPath;
@@ -1405,7 +905,7 @@ type LiveSessionLLMConfig = DashboardLLMConfig & {
1405
905
  screenshotSize?: number;
1406
906
  effectiveResolution?: number;
1407
907
  };
1408
- /** The model entry's own `vision` flag, when the config sets it (439 D-19). */
908
+ /** The model entry's own `vision` flag, when the config sets it. */
1409
909
  modelVision?: boolean;
1410
910
  };
1411
911
  interface LiveDraftMetadata {
@@ -1609,22 +1109,10 @@ interface SessionState {
1609
1109
  interactive: boolean;
1610
1110
  terminalError: string | null;
1611
1111
  }
1612
- /**
1613
- * What the create door found the current config declares about the session's target (432 D-18).
1614
- *
1615
- * It can only add a refusal: `initialize` refuses any name here unless the config it reads itself
1616
- * opts in. There is deliberately no opt-in field, so nothing a caller passes can allow production.
1617
- */
1618
- interface LiveProductionFinding {
1619
- readonly productionTargetNames: readonly string[];
1620
- }
1621
1112
  interface LiveSessionConfig {
1622
1113
  platform: 'web' | 'android' | 'ios';
1623
1114
  targetName?: string;
1624
- production?: LiveProductionFinding;
1625
- /** 436 D-03: resolved at the create door from the project config and the edited entity. */
1626
1115
  plannerLimits?: PlannerLimits;
1627
- /** 436 D-03: per executed test, project then suite then the test's own `use`. */
1628
1116
  plannerLimitsForTest?: (testId: string) => Promise<PlannerLimits>;
1629
1117
  llmConfig: LiveSessionLLMConfig;
1630
1118
  authFetch?: typeof globalThis.fetch;
@@ -1637,6 +1125,8 @@ interface LiveSessionConfig {
1637
1125
  hookRegistryError?: string;
1638
1126
  url?: string;
1639
1127
  headless?: boolean;
1128
+ /** The resolved `use.timeout.navigation`; unset leaves the web adapter's default. */
1129
+ navigationTimeoutMs?: number;
1640
1130
  useDeviceName?: string;
1641
1131
  appState?: 'preserve' | 'reset';
1642
1132
  bundleId?: string;
@@ -1655,17 +1145,7 @@ interface LiveSessionConfig {
1655
1145
  appiumUrl?: string;
1656
1146
  };
1657
1147
  }
1658
- /**
1659
- * The close code the control socket uses for a session this process does not hold (428 P5), so the
1660
- * page can say the session ended instead of "Disconnected". The dashboard UI spells the same number;
1661
- * Plan 23 pins the two equal.
1662
- */
1663
1148
  declare const LIVE_EDITOR_UNKNOWN_SESSION_CLOSE_CODE = 4404;
1664
- /**
1665
- * The close code for a control socket a newer one has replaced (428 WR-01). The session is still
1666
- * held; this socket no longer drives it, so the page must not reconnect and take it back. The
1667
- * dashboard UI spells the same number.
1668
- */
1669
1149
  declare const LIVE_EDITOR_SUPERSEDED_CLOSE_CODE = 4409;
1670
1150
 
1671
1151
  /** Why the session let go of a control socket: a newer one replaced it, or the session ended. */
@@ -1729,19 +1209,9 @@ declare class LiveSession {
1729
1209
  /** What the editor-subject registry holds for this session: its hub, read at call time. */
1730
1210
  liveAttachment(): LiveEditorAttachment;
1731
1211
  private openLiveHub;
1732
- /**
1733
- * Make a control socket the current one. `release` is how the session lets go of it later: the
1734
- * previous attachment's is called with `superseded` here (428 WR-01), so one socket drives the
1735
- * session at a time.
1736
- */
1737
1212
  beginAttachment(release?: (reason: LiveAttachmentRelease) => void): number;
1738
1213
  isCurrentAttachment(generation: number): boolean;
1739
1214
  attachMessageSink(sink: ((message: ServerMessage) => void) | null): void;
1740
- /**
1741
- * A command's reply, for whichever control socket is attached now (428 CR-01). A command can
1742
- * outlive the socket that issued it, and its outcome belongs to the page, not to that socket:
1743
- * with none attached it is held and flushed to the next one.
1744
- */
1745
1215
  deliver(message: ServerMessage): void;
1746
1216
  private dispatch;
1747
1217
  private redact;
@@ -1968,14 +1438,6 @@ type DashboardVisionConfig = {
1968
1438
  interface RouterDeps {
1969
1439
  db: DashboardDatabase;
1970
1440
  workspacePaths?: ResolvedWorkspacePaths;
1971
- /**
1972
- * The injected run backend (401-07, D-09).
1973
- *
1974
- * TYPED AGAINST THE INTERFACE, AND NOW ACTUALLY SEPARABLE. It always meant to be, and was not:
1975
- * the retired live-event route reached past the interface for a per-run replay buffer only the
1976
- * concrete class declared, so the seam had exactly one possible implementation. That route and
1977
- * that buffer are gone (405-07, D-19); what this router asks of a backend is the interface.
1978
- */
1979
1441
  executionBackend?: ExecutionBackend;
1980
1442
  jobQueue?: JobQueue;
1981
1443
  testFileManager?: TestFileManager;
@@ -1986,75 +1448,11 @@ interface RouterDeps {
1986
1448
  llmConfig?: DashboardRuntimeLLMConfig;
1987
1449
  authFetch?: typeof globalThis.fetch;
1988
1450
  sessionManager?: SessionManager;
1989
- /**
1990
- * The composed agent host (400-01, D-01). It serves run detail, marks, analysis, knowledge and
1991
- * post-processing. (The run-confirm pair it also served is deleted, 432-14.)
1992
- *
1993
- * INJECTED, and optional because a router built the legacy two-argument way
1994
- * (`createRouter(db)`) has none. Each arm that needs it then answers by name rather than 404 —
1995
- * the route exists, this server was started without a host. See `chat/host.ts` for why the
1996
- * composition happens in the CLI command that starts this server rather than here.
1997
- */
1998
1451
  agentHost?: AgentHost;
1999
- /**
2000
- * The run service's readiness predicate, served on the LOCAL door (402-05, D-15).
2001
- *
2002
- * THE SAME FUNCTION THE RUN SERVICE'S `/ok` SERVES — one readiness spelling behind two doors,
2003
- * which is the whole of D-15. It is passed in rather than computed here for the reason `agentHost`
2004
- * is: every fact in it (is a host composed) is known only to the process that composed it, and a
2005
- * copy made here is how the run service and the dashboard start disagreeing about whether this
2006
- * process can run anything.
2007
- *
2008
- * ABSENT IS THE LEGACY MOUNT, NOT AN UNCONFIGURED SERVICE. `agent-qa dashboard` ALWAYS supplies
2009
- * this, because the browser preflight needs an honest answer and a 404 is not one. A router built the legacy
2010
- * two-argument way has none, and that arm answers 503 by name on `agentHost`'s idiom.
2011
- */
2012
1452
  runServiceReadiness?: () => RunServiceReadiness;
2013
- /**
2014
- * The started run's session, or nothing — the LOCAL door's attach port (402-08, D-01).
2015
- *
2016
- * THE SAME PORT THE AUTHED DOOR USES, and `server.ts` supplies it by reading
2017
- * `runService.attach` rather than by composing a second lookup: one session registry serves both
2018
- * doors, so a run the remote door can attach to is a run this door can attach to, and there is
2019
- * no second retention window to disagree about.
2020
- *
2021
- * ABSENT MEANS NO RUN SERVICE WAS MOUNTED, which is the same fact as "this process composed no
2022
- * session registry" — unlike `runServiceReadiness` above, whose absence is a legacy mount rather
2023
- * than an unconfigured service. The route then answers 503 BY NAME on the execution routes' own
2024
- * degradation idiom, never a 404 (the route exists) and never an empty stream (which would look
2025
- * like a run that emitted nothing).
2026
- */
2027
1453
  runServiceAttach?: (runId: string) => RunSession | undefined;
2028
- /**
2029
- * The `runs.liveurl` mint, DISPATCHED THROUGH THE REGISTRY by the composition root (403 D-03).
2030
- *
2031
- * A FUNCTION, not a signer: this router holds no key and mints nothing. What it does is turn one
2032
- * HTTP shape into one op call and the op's refusals into status codes — which is the whole of a
2033
- * thin client over the function layer.
2034
- *
2035
- * ABSENT MEANS THIS HOST SERVES NO LIVE VIEW, and the route answers 503 BY NAME on
2036
- * `runServiceReadiness`'s idiom — never a 404 (the route exists) and never a URL to nowhere.
2037
- */
2038
1454
  mintLiveUrl?: (runId: string, handle: number) => Promise<RunsLiveUrlResult>;
2039
- /**
2040
- * The `editor.liveurl` mint, dispatched through the registry by the composition root (428 D-07).
2041
- * The editor counterpart of `mintLiveUrl`: a function, never a signer. ABSENT MEANS THIS HOST
2042
- * MINTS NO EDITOR VIEW, and the route answers 503 by name.
2043
- */
2044
1455
  mintEditorLiveUrl?: (sessionId: string) => Promise<EditorLiveUrlResult>;
2045
- /**
2046
- * The in-process chip sink the post-processing stream relays from (404-05, D-16).
2047
- *
2048
- * INJECTED ON `agentHost`'s OWN IDIOM. The publisher is the CLI's post-run chip emitter — a
2049
- * package this one may not import — so `agent-qa dashboard` creates the relay, hands
2050
- * `relay.publish` to the run door's bridge and hands the relay itself here. One object, two
2051
- * halves of the same process; a relay composed here instead would be a registry the emitter
2052
- * never reaches, and the stream would heartbeat forever at a page whose chips do move.
2053
- *
2054
- * ABSENT MEANS THIS SERVER HAS NO PUSH CHANNEL and the stream arm answers 503 BY NAME — never a
2055
- * 404 (the route exists) and never an empty stream, which would look like a chain that never
2056
- * ticked. The READ route is unaffected: polling works with no relay at all.
2057
- */
2058
1456
  postProcessingRelay?: PostProcessingRelay;
2059
1457
  }
2060
1458
  declare function createRouter(deps: RouterDeps): (req: IncomingMessage, res: ServerResponse) => void;
@@ -2080,15 +1478,6 @@ declare function tryParseRequestUrl(req: Pick<IncomingMessage, 'url'>): URL | un
2080
1478
  * through the door's own responder can re-enter the fault it was catching.
2081
1479
  */
2082
1480
  declare function refuseUnparseableRequest(res: ServerResponse): void;
2083
- /**
2084
- * The process-level backstop's answer: a 500 in fixed bytes, or a destroyed socket if it is late.
2085
- *
2086
- * THE ERROR IS NOT PRINTED AND NOT SERIALIZED. Phase 395 measured a planted credential leaving this
2087
- * product through an error's serialization rather than its `message`, so what goes to stderr here
2088
- * is the error's CONSTRUCTOR NAME and the request METHOD — two values with no attacker- or
2089
- * secret-derived content — and never the URL, which is attacker-chosen, or the error itself, whose
2090
- * `cause` chain is exactly the surface that leaked.
2091
- */
2092
1481
  declare function backstopServerError(res: ServerResponse, req: Pick<IncomingMessage, 'method'>, error: unknown): void;
2093
1482
 
2094
- export { createRouter as $, type AgentHost as A, type RunRow as B, ConfigFileInvalidError as C, DashboardDatabase as D, type ExecutionBackend as E, type RunServicePorts as F, type RunServiceRouteHandlerName as G, type RunServiceRouteMatch as H, type RunServiceRouteRow as I, type RunServiceRouter as J, type RunServiceStartInput as K, type LiveEditorAttachment as L, type MintLiveUrlInput as M, type RunSettledDetails as N, type RunSettledStatus as O, type PreflightOptions as P, RunsDatabaseVersionRefusedError as Q, RUN_SERVICE_ANALYSIS_TEMPLATE as R, TestFileManager as S, type TestFileInfo as T, type TestValidationError as U, type TestValidationResult as V, backstopServerError as W, classifyRunOwner as X, completeRunOwnership as Y, createLiveEditorSubjects as Z, createPostProcessingRelay as _, type ExecuteOptions as a, createRunServiceRoutes as a0, defaultRunOwnership as a1, matchRunServiceRoute as a2, orphanSummary as a3, ownedElsewhere as a4, ownsRunServicePath as a5, readConfigValues as a6, readJsonBody as a7, refuseUnparseableRequest as a8, runDenialOf as a9, serializeConfigWrite as aa, startServer as ab, tryParseRequestUrl as ac, type PostProcessingRelay as b, type AgentRegistryHandle as c, AppiumManager as d, ConfigManager as e, LIVE_EDITOR_SUPERSEDED_CLOSE_CODE as f, LIVE_EDITOR_UNKNOWN_SESSION_CLOSE_CODE as g, type LiveEditorSubjects as h, type PostProcessingListener as i, RUN_SERVICE_ARTIFACT_TEMPLATE as j, RUN_SERVICE_DETAIL_TEMPLATE as k, RUN_SERVICE_EVENTS_TEMPLATE as l, RUN_SERVICE_EVIDENCE_TEMPLATE as m, RUN_SERVICE_LIVE_URL_TEMPLATE as n, RUN_SERVICE_MARKS_TEMPLATE as o, RUN_SERVICE_MARK_PREVIEW_TEMPLATE as p, RUN_SERVICE_OK_ROUTE as q, RUN_SERVICE_ROUTE_TABLE as r, RUN_SERVICE_START_ROUTE as s, type ReplaceDocumentOutcome as t, type ResumePoint as u, type RunOwner as v, type RunOwnerProbe as w, type RunOwnerState as x, type RunOwnership as y, type RunOwnershipInput as z };
1483
+ export { createRunServiceRoutes as $, type AgentHost as A, type RunServicePorts as B, ConfigFileInvalidError as C, DashboardDatabase as D, type ExecutionBackend as E, type RunServiceRouteHandlerName as F, type RunServiceRouteMatch as G, type RunServiceRouteRow as H, type RunServiceRouter as I, type RunServiceStartInput as J, type RunSettledDetails as K, type LiveEditorAttachment as L, type MintLiveUrlInput as M, type RunSettledStatus as N, RunsDatabaseVersionRefusedError as O, type PostProcessingRelay as P, TestFileManager as Q, RUN_SERVICE_ANALYSIS_TEMPLATE as R, type TestValidationError as S, type TestFileInfo as T, type TestValidationResult as U, backstopServerError as V, classifyRunOwner as W, completeRunOwnership as X, createLiveEditorSubjects as Y, createPostProcessingRelay as Z, createRouter as _, type ExecuteOptions as a, defaultRunOwnership as a0, matchRunServiceRoute as a1, orphanSummary as a2, ownedElsewhere as a3, ownsRunServicePath as a4, readConfigValues as a5, readJsonBody as a6, refuseUnparseableRequest as a7, serializeConfigWrite as a8, startServer as a9, tryParseRequestUrl as aa, type AgentRegistryHandle as b, AppiumManager as c, ConfigManager as d, LIVE_EDITOR_SUPERSEDED_CLOSE_CODE as e, LIVE_EDITOR_UNKNOWN_SESSION_CLOSE_CODE as f, type LiveEditorSubjects as g, type PostProcessingListener as h, RUN_SERVICE_ARTIFACT_TEMPLATE as i, RUN_SERVICE_DETAIL_TEMPLATE as j, RUN_SERVICE_EVENTS_TEMPLATE as k, RUN_SERVICE_EVIDENCE_TEMPLATE as l, RUN_SERVICE_LIVE_URL_TEMPLATE as m, RUN_SERVICE_MARKS_TEMPLATE as n, RUN_SERVICE_MARK_PREVIEW_TEMPLATE as o, RUN_SERVICE_OK_ROUTE as p, RUN_SERVICE_ROUTE_TABLE as q, RUN_SERVICE_START_ROUTE as r, type ReplaceDocumentOutcome as s, type ResumePoint as t, type RunOwner as u, type RunOwnerProbe as v, type RunOwnerState as w, type RunOwnership as x, type RunOwnershipInput as y, type RunRow as z };