import type { WorkOrder } from "./prompts.js"; import type { RemoteJobName } from "./remote-executor.js"; import type { ChecklistItem, ClientPlatform, ContractAmendment, CoverageChecklist, OpenApiChange, ScenarioSlice, TestRun } from "./types.js"; /** * The shape shared by every UI client (web frontend, mobile app, * flags-admin console). Authoring is always local; EXECUTION of the * UI-driving tests follows the `uiTestExecution` discriminant (local * machine vs. directly on the remote runner hardware). Each * model-performing method receives its instructions as order.prompt; * methods without an order are executors. During the fan-out, any method * may throw ContractGapDiscovered to request a contract amendment. */ interface ClientAgentBase { readonly platform: ClientPlatform; /** * Open a FRESH lane conversation for a new slice. This client's * constructive steps within a slice share one persistent session (the lane * agent's memory of its own arc); resetLane clears it at each slice * boundary so a new slice never inherits the previous one's context. Called * by the orchestrator at the start of every slice's client work. */ resetLane(): void; receiveRunInstructions(instructions: readonly string[]): Promise; /** * C1-contract, step 1 — BEFORE any client code. One item per client * operation the contract adds: the equivalence behaviors that must hold * for the operation. Built up front, because the contract test DEFINES * the API the client is then built against. */ buildContractChecklist(order: WorkOrder, contract: OpenApiChange): Promise; /** * C1-contract, step 1 — write (or refine) the item's contract test * running ONLY against the fake (the real backend does not exist yet), * shaped so a second implementation can later be added to the SAME * assertions. TDD authors it before the fake, so the suite is observed * RED first; the fake (implementFakeApi) then turns it green. Returns * the exact test title so a never-added test reads as "no tests", not * as a pass. */ writeContractTestAgainstFake(order: WorkOrder, item: ChecklistItem): Promise; /** * C1-contract, step 2 — the fake API with its three per-operation * doubles (slow, backend error, network failure). In TDD this turns the * step-1 contract tests green; in basic mode step 1 and step 2 are one * step (the fake and its passing contract tests together). */ implementFakeApi(order: WorkOrder, contract: OpenApiChange): Promise; /** * The concrete C1 exit condition: scenario behaviors plus the four * mandated per-operation cases. On re-entry after an amendment, items * keep the covered status applyContractChange left them with. */ buildE2eChecklist(order: WorkOrder, slice: ScenarioSlice): Promise; /** * TDD mode: write JUST the item's e2e test (revised if it passes * prematurely). Resolves to the EXACT title of the test written — the * loop records it on the item so execution filters by title, and a * test never actually added reads as "no tests found", not as a pass. */ writeE2eTest(order: WorkOrder, item: ChecklistItem): Promise; /** * TDD mode: the fresh test passed BEFORE any implementation step. * Judge which explanation holds — the behavior is already implemented * (returns true: the pass is legitimate, the item is covered) or the * test is vacuous (returns false: rewrite it). */ judgeItemAlreadyImplemented(order: WorkOrder, item: ChecklistItem): Promise; /** TDD mode: the minimum client code that turns the observed-red test green. */ writeUiCodeToPassE2eTest(order: WorkOrder, item: ChecklistItem): Promise; /** * Basic mode: the item's test and minimum code in one step. Resolves * to the written test's exact title (see writeE2eTest). */ writeE2eTestAndUiCodeTogether(order: WorkOrder, item: ChecklistItem): Promise; /** * Absorb an amendment: adjust fake and types, and UN-COVER every * checklist item the amendment invalidates. */ applyContractChange(order: WorkOrder, contract: OpenApiChange, amendments: readonly ContractAmendment[]): Promise; implementRealApi(order: WorkOrder, contract: OpenApiChange): Promise; /** * C2, step 5 — the real backend now exists and is wired to the use case. * Extend the contract tests written against the fake so the SAME * assertions also run against the REAL backend: the fake-vs-real * equivalence guard closes here. Never authored from scratch — it * extends the step-1 tests, and never weakens an assertion. */ extendContractTestsToReal(order: WorkOrder, contract: OpenApiChange): Promise; runContractSuite(): Promise; /** Localize and fix the actual cause of a red suite — never weaken a test. */ fixActualCauseOfBreakage(order: WorkOrder, run: TestRun): Promise; /** * The client's e2e suite, executed where the test process runs — for * every client: browsers via their local runners, mobile via the * in-process app-flow suite. Device hardware is an acceptance concern. */ runE2eTest(item: ChecklistItem): Promise; runE2eSuite(): Promise; } /** * A client whose ACCEPTANCE verification runs on the developer machine * (browser clients). E2e suites are local for EVERY client — the mobile * fake-backend suite runs IN-PROCESS (RNTL over the FakeBackend, * suite/mobile-app/e2e), so the discriminant below is only about * where the real-backend, device-bound verification happens. */ export interface LocallyTestedClientAgent extends ClientAgentBase { readonly uiTestExecution: "local"; } /** * A client whose ACCEPTANCE verification needs an environment that exists * only on the runner hardware (simulator/emulator + the real stack) — * that route is the RemoteTestExecutor and this job definition. */ export interface RemoteTestedClientAgent extends ClientAgentBase { readonly uiTestExecution: "remote"; readonly acceptanceJob: RemoteJobName; } export type ClientAgent = LocallyTestedClientAgent | RemoteTestedClientAgent; export {};