Source-bound remote runs and recovery.

Run product-owned journeys on Stado, retain their exact source identity, and recover an interrupted watch without repeating the work.

What is submitted#

Probierz packages its toolkit and the application source, records the exact Git revision and worktree hash, and submits one job to the selected Stado host. `--app-repo` selects the primary checkout that is actually measured and packed.

The worker receives `PROBIERZ_APP_SOURCE`, `PROBIERZ_TOOLKIT_ROOT` and `PROBIERZ_SOURCE_IDENTITY`. Its manifest records the submitter's identity rather than trying to read the submitter's absolute checkout paths on another machine.

Cargo source, a prebuilt native application bundle with its source, and Node source are supported provisioning modes. Cargo provisioning builds all product binaries; `--binary` selects the entry point without dropping required sibling helpers such as Jeden's macOS sandbox helper. A queued job is accepted work, not a successful journey.

Every Stado `desktop:cua` bundle run also builds the CLI from the submitted source, exports `PROBIERZ_STADO_BIN`, and puts that candidate first on `PATH`. The graphical interface uses the matching CLI for every selected journey, not an older installed command.

For iOS, Android and native macOS, the WebdriverIO Appium service owns the server for each run, including remote authoring validation. The remote launcher does not kill another Appium process, start a shared background server, or poll a TCP port. Windows uses its separately provisioned WinAppDriver.

The mobile and native runners disable Mocha's test and hook clock limit with its documented zero value and do not retry failed WebDriver requests. Appium sessions on iOS, Android and macOS set appium:newCommandTimeout to zero to disable idle expiration; their owner still closes them at completion. WebdriverIO request and element-readiness clocks remain a separate limitation: zero connectionRetryTimeout restores the installed library's default rather than disabling it.

Run the real Jeden lifecycle#

The `task-contract-lifecycle` journey uses the real Jeden CLI and RPC, changes isolated settings, and asks a real Brama-backed model to create, edit and delete a file. It inspects the final file and session records, including all seven task-report entries.

The example assumes sibling product checkouts. Both Jeden manifests use `https://brama.wisent.com`, the `probierz` model identity and the configured `local-openai/chat-primary` deployment; they do not require a local forwarding process or a new paid provider. Secret values are materialized from the application manifest's references and do not belong in command arguments.

Dedicated-host lifecycle
probierz remote run tui --app jeden   --spec jeden-task-contract-lifecycle --host stado:mini   --cargo-release --app-repo ../jeden --binary jeden   --env PROBIERZ_JOURNEY=task-contract-lifecycle --no-watch

Native GUI evidence#

The registered `jeden-desktop` journey opens the real Settings screen, reads the seven requirements through Jeden RPC, and inspects a real recorded task report in the conversation without a duplicate final answer.

Native GUI readiness is read through Stado's host gui-automation status command. Probierz requires a declared automated console session, the CuaDriver app and granted Accessibility permission. A failed read or an unready session prevents submission and keeps the observed error. The check does not grant operating-system permissions or open consent prompts.

For Mac2 recordings, screen-capture-kit, given a bundle id and an output .mp4 file, selects the largest matching capturable window from one ScreenCaptureKit read after the application session exists. An absent window fails immediately instead of polling for a later launch. Unknown, duplicate or incomplete options, including its removed wait-seconds option, exit 2 before capture starts. Capture and writer failures exit 1.

Built native candidate
probierz remote run desktop:cua --app jeden-desktop   --spec jeden-desktop-task-contract --host stado:mini   --app-bundle-path ../jeden-desktop/.build/Jeden.app   --app-repo ../jeden-desktop --no-watch

Conditions and credentials#

Repeated `--env NAME=VALUE` and `--env=NAME=VALUE` are equivalent for non-secret remote conditions, including values containing `=`. Conditions use the same selected journey contract on the submitter and the worker.

`PROBIERZ_JOURNEY=<journey>` selects one declared journey. A declared `journeyOverrides.when.PROBIERZ_JOURNEY` group selector, such as Stado's `cli-release-qualification`, selects its complete group when every condition matches. Submission, worker execution, source identity and evidence attribution use that same selection.

Unknown selectors and unmatched named groups are configuration refusals before source upload or job submission: `PROBIERZ_JOURNEY <value> is not declared for this surface`. An unrelated override cannot accept an unknown selector, and a selected spec cannot mark unselected journeys as passed.

Remote jobs preserve CARGO_HOME and RUSTUP_HOME, defaulting to $HOME/.cargo and $HOME/.rustup, and put $CARGO_HOME/bin on PATH. Product journeys can isolate their application HOME without losing the compiler or dependency cache. On macOS, $HOME/.stado/bin also precedes system and Homebrew locations. Single-file native provisioning does not supply separate runtime helpers; use Cargo source provisioning for Jeden on macOS.

The selector is `local`, `stado` (any consumer with capacity), `stado:<target>` (one registry host) or `stado?key=value&...`, whose pairs become fields of the Stado placement request; no provider, cost cap or GPU model is built in. Selectors that do not pin a host detect the worker's actual operating system and architecture before provisioning Node. They support Linux and macOS on x64 or arm64, use an installed Node when present, and refuse unsupported combinations instead of fetching an incompatible binary.

A dedicated host selector changes placement only. Every upload, submission, status read and evidence download uses Stado's configured endpoint; stado:macbook no longer substitutes a fixed loopback port.

Remote object storage uses an explicit STADO_API_URL when present. Otherwise HOME must be set to an absolute directory before Probierz reads Stado's .stado/forwards/stado-object-api.local marker. Missing, empty or relative HOME is a named configuration refusal, never a marker lookup under the command's working directory.

Remote spec authoring reads STADO_MODEL_ROUTER_URL and PROBIERZ_MODEL from the selected surface's conditions, then from the submitting process. Jeden pins local-openai/chat-primary for its model-scoped bearer rather than requesting the broader any selector. The bearer must permit that exact model; a grant for codex/gpt-5.6-sol alone does not authorize it.

Credentials use the application's `secretRefs`. Brama must recognize the configured bearer, request-signing identity and model permissions; merely finding a nonempty token does not prove that a model ran.

Recover instead of submitting again#

Submission requests and responses remain under `test-results/.remote/`. Before waiting, stderr prints the saved request and accepted job ID, so an interrupted client does not lose the identity of its existing job.

`stado collect` returns the current state immediately and imports evidence only when the job is terminal. `stado resume` holds Stado's status read until that same job reaches a terminal state, without a polling interval or a clock budget. A failed read is reported as unreachable with Stado's error. Both operations preserve the original run ID, source identity, reports and supported media.

Existing-job recovery
probierz remote collect <job-id> --app jeden --host stado:mini
probierz remote resume <job-id> --host stado:mini

Interpret the recorded result#

A queued or running result is not passed. A failed journey keeps its failed verdict after collection, even when downloading its evidence succeeds. Missing or wrong-application evidence is refused.

Reports, traces and screenshots describe the path actually exercised; an HTTP 401 is an authentication failure, not model or GUI evidence. A failed status read does not establish a job's terminal state and does not submit a replacement job.

Each input upload invokes Stado once. A refused put, including exit 69, fails immediately with the local source, destination and Stado's output. Probierz does not delay and retry the upload.

A failed Stado command emits a probierz-process-failure record with its command, arguments, exit code, captured stdout and stderr, and spawn error before the bounded probierz-failure summary. Read that full process record when a long object URL leaves the summary without the actual cause.

MCP exposes the same separate operations as `probierz_stado_run`, `probierz_stado_collect` (`jobId`, `appId`, `host`) and `probierz_stado_resume` (`jobId`, `host`); `watch: false` on a submission becomes `--no-watch`.