/** * The inner feature loops, in four shapes along two axes: * * - DISCIPLINE: test-first (write the test alone, prove it RED, then * implement and prove it GREEN) vs. tests-with-code (author both in * one step, prove GREEN only). * - EXECUTION: per-item (local clients) vs. batched (remote clients — * one suite run serves every pending item, verdicts read from its * output, covered tests re-run for free). * * Batched test-first is a slightly weaker discipline than per-item * test-first (tests in a batch are authored before each other's * implementations exist) — negligible for independent e2e items, and it * collapses 2·N remote runs to ~2 per batch round. * * All four shapes share the same exit condition: every checklist item * covered AND the independent reviewer finds nothing missing. Every * role call receives its instructions as a WorkOrder. */ import type { ClientAgent } from "./client-agent.js"; import { type RunDeps } from "./shared.js"; import type { ChecklistItem, CoverageChecklist, IterationBudgets, ScenarioSlice, TddLoopName, TestRun } from "./types.js"; interface LoopCommonOpts { deps: RunDeps; budgets: IterationBudgets; loop: TddLoopName; slice: ScenarioSlice; buildChecklist: () => Promise; /** * Lane-scoped work-preservation commit (laneProgressPreserver), called * after every item this loop proves green — so fan-out work never sits * uncommitted for hours while a sibling lane is mid-red. */ preserveProgress?: (item: ChecklistItem) => Promise; /** * Arbiter between reviewer and writer (reviewCoverage): every review * finding is judged against the current tree before adoption, so two * sessions can never stall a loop into escalation over a case one of * them already covered. The TDD loops require this judge anyway; the * basic loops carry it for the review rounds alone. */ judgeAlreadyImplemented?: (item: ChecklistItem) => Promise; } /** * Test-first, per item: write the test ALONE, execute, require RED; then * implement and execute until GREEN. Each phase has its own budget. * * A test that passes immediately has TWO possible causes, so it is * JUDGED, never assumed: the item's behavior may already be implemented * (a stale review finding, a resumed run, work an earlier item pulled * in) — then the fresh test is a legitimate regression test and the item * is covered as-is; only a test judged VACUOUS is rewritten. */ export declare function runFeatureTddLoop(opts: LoopCommonOpts & { /** Resolves to the written test's exact title (recorded on the item). */ writeTest: (item: ChecklistItem) => Promise; writeImplementation: (item: ChecklistItem) => Promise; execute: (item: ChecklistItem) => Promise; /** true = the behavior already exists; the premature pass is legitimate. */ judgeAlreadyImplemented: (item: ChecklistItem) => Promise; }): Promise; /** * Tests-with-code, per item: author both in one step, execute, repair * until GREEN. No red is ever observed. */ export declare function runFeatureBasicLoop(opts: LoopCommonOpts & { /** Resolves to the written test's exact title (recorded on the item). */ writeTestAndImplementation: (item: ChecklistItem) => Promise; execute: (item: ChecklistItem) => Promise; }): Promise; /** * Run a client's e2e feature loop with the right shape: the discipline * comes from the resolved tddMode for this client. Execution is * PER-ITEM for every client — e2e is in-process/local everywhere since * the Detox retirement (uiTestExecution governs acceptance only), and a * per-item titled run is the only honest verdict: a batched suite's * green output lists no passing test names, so an item's absence there * proves nothing (live-run lesson: a green suite judged an existing * test "never written" and the item burned its budget). Work orders are * resolved here and passed into every role call. */ export declare function runClientE2eFeatureLoop(deps: RunDeps, budgets: IterationBudgets, slice: ScenarioSlice, client: ClientAgent, testFirst: boolean): Promise; export {};