> ## Documentation Index
> Fetch the complete documentation index at: https://orbit.nckrtl.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Gateway response fixtures

> Recorded Gateway responses are the contract that CLI tests replay, so a response change shows which commands it reaches before it ships.

# Gateway response fixtures

This page tells a contributor how a Gateway response change reaches the CLI tests. A fixture is one recorded Gateway response under `packages/php-sdk/fixtures/<family>/<command>/<case>.json`. The Gateway test suite records it and the [API reference](/docs/api/overview) validates it. The CLI test suite replays it through a Saloon mock and compares the complete command output with a stored expectation.

Task group fixtures include nullable `vm_power`, separately from task status. CLI tests cover the **VM power** label for known states and omit the label and JSON field when power is null. The SDK accepts a missing power field and ignores unknown optional response fields, so a field rename does not make an older client reject the task group.

Tool scan and adoption fixtures distinguish formula, cask, and Vite+ global identities, registered and informational packages, dependencies, unsupported artifacts, per-manager scan states, inspection time, and failed scans. Scan fixtures also record authorization and unmanaged-node refusals. Adoption fixtures record a created Tool, the same intent, a repaired failure, constraint conflicts and violations, a busy scope, a missing or unsupported package, and authorization failure. The CLI replays those responses for `tool:adopt`.

Doctor fixtures include informational-only healthy reports and mixed reports with drift or unverifiable findings. Node fixtures include an enrolled Mac with empty roles. Web fixtures preserve registered Tools while a live inventory request fails.

Node key fixtures under `nodes/node-wireguard-key` record an updated Node, a Gateway-role refusal, and a sanitized hub projection failure. The `node:wireguard-key` CLI tests replay each response in human and JSON modes. Keep the projection failure's error code and step, but never record remote process output or private key material. [WireGuard key recovery](/docs/cli/node#orbit-nodewireguard-key) owns the stored-key and identical-replay behavior; subprocess feature tests cover interrupted publication separately from response fixtures.

Task fixtures include a GitHub feedback fixup with `fixup_problem: review:{reviewer_id}` and an immutable findings packet in `brief`. Record that response from the Gateway fixture test with example identities and findings. Its `review-findings` deliverable and optional `project-check` use the existing response schema. Replaying the fixture must preserve source provenance without interpreting review text as an action. The [Tasks contract](/docs/reference/tasks#review-fixup-lifecycle) owns the meaning of those fields.

Task response fixtures include a `topology` array on each subtask. Default cases record `[]`; the declared case records `app-dev`. Re-record all responses that contain subtasks when this field changes, regenerate OpenAPI and the web API types, and update the matching CLI expectations. Human subtask details show `Topology` only for a nonempty declaration; JSON keeps the array in both cases. [Compute drivers](/docs/reference/compute-drivers) defines the accepted workload roles and readiness gate.

Process response fixtures include `user`, which is null when the Process uses its derived account. When an explicit account is selected, the response includes that name both in `user` and in `runtime_config.user`; see [Node accounts](/docs/reference/processes-and-schedules#node-account).

Instance create, list, and show fixtures include `routes`, every Route of the Instance, and each Route includes `web_root`. Instance create, list, and show fixtures include `annotator_port` and `annotator_url`. Both are null without an assigned annotator port; an Instance with a port but no Route still has a null URL. Re-record these fixtures when either field changes, regenerate the OpenAPI schema, and replay the Instance CLI contracts. Human detail output shows the annotator properties only when a port is assigned, while JSON retains the nullable fields. The web API types must also be regenerated from the same OpenAPI schema.

Gateway fixtures record the [desired fleet state](/docs/reference/self-update#desired-fleet-state) with an available, a fallback, and a pending CLI release, and `gateway:status` as an active peer sees it. The Gateway test serves the release-shaped GitHub responses under `apps/gateway/tests/Fixtures/GitHub/CliRelease`. The `self-update` contract downloads the stand-in binaries under `apps/cli/tests/Fixtures/SelfUpdate`, whose checksums those fixtures name.

An Agent pin change updates the Gateway and Fleet fixtures with the released version, asset URLs, and verified checksums. Update the SDK checksum expectations, CLI download stand-ins, and matching CLI output together. The Agent release checksums remain separate from the local stand-in checksums used by `self-update` tests.

Gateway release fixtures under `gateway-releases` record one release record at each point the CLI can see it: queued, running, live, switched back, paused, and rolled back. `gateway:release:deploy` and `gateway:release:rollback` replay the queued response and then a sequence of record reads, so their expected output shows how the progress tree follows a release. The automatic release fixtures record the state disabled, enabled, paused, and resumed.

Project Document fixtures record a complete file lifecycle, reads of earlier versions, revision conflicts, and redacted storage status. The SDK and CLI replay the same envelopes, preserving IDs, revisions, checksums, cursors, and request IDs. Human show, list, and version-history expectations live under `apps/cli/tests/Expected/project-documents`; raw read and download tests check exact bytes separately.

Gateway rollback fixtures record a queued code switch with `force: false` and no force member in the rollback phase. The request is bodyless. The crossing-refusal fixture is removed because Laravel owns migration discovery; [Gateway recovery](/docs/reference/gateway-recovery#laravel-owns-migrations) explains the decision.

## Record a fixture

A Gateway fixture test sends a request with deterministic data and calls `record_fixture()` from `apps/gateway/tests/Support/ResponseFixtures.php` with the fixture name, the SDK request class that sends the route, and the route.

```php theme={"dark"}
record_fixture($this->getJson('/api/v1/nodes')->assertOk(), 'nodes/node-list/default', ListNodesRequest::class, 'GET /api/v1/nodes');
```

A normal test run asserts that the response still equals the recorded file. A run with `ORBIT_FIXTURES=record` rewrites the file. Use the request id `fixture_request_id()` so recorded and expected output stay stable.

```bash theme={"dark"}
cd apps/gateway && ORBIT_FIXTURES=record vendor/bin/pest --filter=Fixtures
```

Instance fixtures include nullable `seed_path` and `seed_commit` fields. These name the default's checkout and its last deployed commit, or the seed selected for a new workspace. Re-record create, list, and show responses together, then update the CLI's JSON expectations; human tables keep their existing columns.

The recorded file holds the request class, the route, the status, and the body. It holds no secrets, because fixture tests use example values. Project fixtures include source defaults and task settings such as `task_check`; update the corresponding CLI expectations when those response fields change. Task fixtures share one id sequence with their subtasks. A subtask id is greater than its task id, and creating another task does not reuse a subtask id.

The `tasks/tasks-show/watched` fixture records a running task whose branch pull request was opened outside Orbit. It has `watched_pr_url`, `watched_pr_number`, and `watched_pr_state`, while `pr_url` remains null. The default task fixtures keep the watched fields null. The SDK and CLI replay both cases so a watched pull request cannot become the reviewed pull request by accident. When these fields change, re-record every response that includes a task and update its CLI JSON expectation. The [branch watch](/docs/reference/tasks#watch-the-branch-while-subtasks-are-open) owns their meaning.

The `tasks/tasks-question-close` fixtures record a question closed as `superseded` and the `tasks.question_closed` refusal of a second close with another status. The SDK and the CLI replay both.

## Validate a fixture

`bin/api-fixtures --check` validates every fixture body against the response schema for its route and status in `docs/openapi.json`. The `apps/docs` checks run it, so a fixture whose body differs from the API reference fails continuous integration. Regenerate the reference with `composer docs-openapi` when a response shape changes on purpose. The inputs that command reads are on [API reference generation](/docs/reference/api-reference).

## Replay a fixture in the CLI

A CLI contract test loads a fixture by name with `gateway_fixture_mock()` from `apps/cli/tests/Helpers/GatewayFixtures.php`, runs the command, and compares the output with `apps/cli/tests/Expected/<family>/<command>/<case>.human.txt` or `.json` through `expect_output()`.

```php theme={"dark"}
MockClient::global(gateway_fixture_mock('nodes/node-list/default'));
expect(Artisan::call('node:list'))->toBe(0);
expect_output(Artisan::output(), 'nodes/node-list/default.human.txt');
```

A normal run asserts the exact output. A run with `ORBIT_EXPECTED=update` rewrites the expected files after a reviewed change.

```bash theme={"dark"}
cd apps/cli && ORBIT_EXPECTED=update vendor/bin/pest --filter=Contract
```

## Watch a fixture in a terminal

A development checkout of the CLI can replay recorded responses under a real command, so you can watch the rendering that the contract tests hold. Set `ORBIT_DESIGN=1`, name the fixtures in `ORBIT_GATEWAY_FIXTURES`, and point `ORBIT_HOME` at an empty directory. The replay seeds a Gateway profile there. The CLI binary does not include the replay. `apps/cli/design/README.md` also covers the design sketches that `ORBIT_DESIGN=1` loads.

```bash theme={"dark"}
export ORBIT_DESIGN=1 ORBIT_HOME=/tmp/orbit-replay
ORBIT_GATEWAY_FIXTURES=projects/project-list/default apps/cli/orbit project:list
```

## Find the commands a change reaches

`bin/cli-contract` runs only the CLI tests that replay the named fixtures. With `--changed`, it takes the fixtures that differ from `origin/main`. With `--preview`, it renders every contract case into a temporary directory and lists the commands whose output differs from `tests/Expected`, with a diff per file. That list is the map of the commands a rendering change reaches. With `--coverage`, it lists the product commands that have no expected output yet.

```bash theme={"dark"}
bin/cli-contract nodes/node-add/created
bin/cli-contract --changed
bin/cli-contract --preview
bin/cli-contract --coverage
```

The change cycle is: change the Gateway, re-record the fixtures, review the fixture diff, run `bin/cli-contract --changed`, fix or accept each command's output, and update the expected files.

## Web app fixtures

The web app's demo mode and its tests run against the files under `apps/web/fixtures/fleet`. These files use the same format without a request class. They are written by hand as one coherent fleet, because a recorded fixture covers one route and the web app needs records that refer to each other. `bin/api-fixtures --check` validates them together with the recorded fixtures.

The demo fleet has one tool inventory for each active Node. Node 1 is an empty Linux read: `brew` completed with no packages, `brew-cask` unsupported, and `vp` absent. Node 2 is a partial Linux read: `brew` incomplete, `brew-cask` unsupported, and `vp` conflicting, so none of those empty arrays is an inventory. Node 3 is unreachable and has no inventory fixture; the demo refuses a scan with `tool.node_inactive`.

Node 4 is the macOS read: registered packages with a newer observed version, the `openssl@3` dependency, unsupported casks, a formula and a cask both named `visual-studio-code`, and `ghost`, which the demo lists as supported and then refuses on adopt. The demo adopt, update, and remove handlers change only that in-memory fleet.

## Families with fixtures

The directories under `packages/php-sdk/fixtures` list the families that have recorded fixtures and contract tests. Add a family by recording from its Gateway tests with `record_fixture()` and writing its CLI contract test in the same change. Extension responses are replayed by the `extension:list`, `extension:enable`, and `extension:disable` command contracts; do not leave a changed extension fixture without a CLI test that names it. `bin/cli-contract --coverage` shows the commands that still have no expected output.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.