# Runner E2E fixture authoring The fixture catalog is executable production-contract data. Keep it small, typed, deterministic, and free of raw credentials. ## Agent profiles Add `RunnerProfileFixture` entries in `catalog.ts`. A profile declares: - a stable ID and searchable groups; - legacy or native generation; - adapter/provider and required credential; - a model imported from its adapter constant or qualified runner profile; - supported environment IDs; - expected runtime metadata; and - an agent payload factory. Do not duplicate model IDs, qualification decisions, CLI versions, or runner artifact rules. Codex profiles import `DEFAULT_CODEX_LOCAL_MODEL`, OpenCode profiles import `QUALIFIED_OPENCODE_MODEL`, and ACPX profiles import `QUALIFIED_ACPX_PROFILES`. Add or qualify models at their owning production source first. Agent `adapterConfig.env` values must be `{type:"secret_ref", secretId, version:"latest"}` objects supplied to the factory. A fixture source containing a raw secret-looking value is rejected by catalog validation. ## Environments An `EnvironmentFixture` declares driver/provider, credential requirements, attempt deadline, lifecycle behavior, expected execution target, and a payload factory validated by the shared environment schema. The local environment is instance-managed: company creation ensures it exists, and the public API intentionally rejects a second local environment. The setup registry therefore discovers that row through the public environments API. This still provides full isolation because every cell starts a new Paperclip instance and database. Daytona creates a sandbox environment through the public API. Keep `reuseLease:false`, `runnerLifecycleMode:"per_turn"`, short provider cleanup backstops, a Daytona secret reference, and an immutable image digest. Teardown must delete the environment with reusable-lease destruction and must fail the cell if cleanup cannot be confirmed. Future providers (SSH, E2B, Modal, Cloudflare, Kubernetes, Novita, exe.dev) should implement the same setup/probe/cleanup contract before being added to a matrix. Unsupported profile/environment combinations belong in `supportedEnvironments`, not in ad hoc test conditionals. ## Task cases and matchers A `RunnerTaskFixture` owns a work mode, a typed flow, expected run count, nonce-based title/prompt/marker factories, per-environment attempt deadlines, deterministic matchers, and expected terminal state. Single-turn prompts should make one bounded request with observable output and no nondeterministic judging. The `plan_revision_acceptance` flow must also provide revision-request and Plan marker factories. Every selected case runs in its own isolated Paperclip process, and independent cases may run concurrently. Follow-up turns inside one case retain their shared task state. Each case creates and tears down its own company, secrets, environment selection, agent, and browser-created task. The current plan case proves three runs on the same issue: publish a two-step Plan, request a three-step revision through the UI, and accept the exact new revision through the UI before verifying implementation and Done. The matcher union supports message exact/contains/regex/ordered checks, issue and run state, runtime/environment metadata, files, artifacts, JSON paths, and JSON Schema. The initial cases use normalized `message_contains` plus state, runtime, and environment assertions; the plan flow additionally verifies canonical document revision IDs, bodies, step counts, interaction targets, and visible previews. Add matcher behavior and credential-free tests together. Adding a task expands the matrix. Update the catalog's intentional matrix-size assertion and its unit test in the same change. Paid tests never silently skip a missing credential or unsupported artifact. ## New Paperclip object fixtures Register new objects in `live-fixtures.ts` with explicit dependencies in `FixtureRegistry`. Setup must use a public API. Teardown runs in reverse order and is invoked after partial setup failures. Direct database writes and private test-only runner endpoints are prohibited. The expected dependency shape is: ```text company └── encrypted secrets └── environment └── agent └── browser-created task ``` Projects, goals, apps, and configuration fixtures can be inserted into that graph without changing the launcher. Keep returned fixture state to IDs and sanitized metadata; never retain raw secret values. ## Required checks Run before a fixture change is reviewed: ```bash pnpm test:e2e:runner:unit pnpm test:e2e:runner:typecheck pnpm test:e2e:runner -- --list ``` Then run the narrowest paid cell that exercises the fixture. A full matrix is a manual or scheduled campaign, not a PR requirement.