Contents

Standalone Project QA Plans

Run a saved plan immediately without an item or deployment run:

yoke qa plan run --plan PLAN --project P

Each fresh run freezes cases and host baselines in saved order in existing QA execution, requirement, run, review, and artifact records. Its standalone execution owns the evidence and changes no item transition, delivery acceptance, or stage gate. An interrupted live run resumes its immutable roster and cursor in its owning session. Latest-execution reads select the unique live owner first, then the greatest database-assigned execution order. Requirement creation, timestamp precision, and random execution ids do not determine that order. The identity column is added on boot to existing databases; historical rows receive an order at that convergence, which cannot recover their original same-second creation order. Unsupported runners or missing capabilities refuse before any case executes.

Commands require --checkout-path PATH --expected-sha FULL_SHA: the checkout must be clean at that commit. CI cases require the SHA and --expected-branch REF, a published branch or tag at that commit, and a case-declared ci_workflow. They dispatch with declared ci_workflow_inputs, verify the run's actual commit, and record its URL and conclusion. Manual CI does not publish, rebase, or open a landing PR, including on merge-queue projects.

Browser, terminal, machine-state, inspection, and exploratory cases retain their target, capability, serial lease, evidence, and review contracts. Read proof with yoke qa plan get PLAN --project P --full, then inspect returned requirement and run ids through QA reads. Abort with yoke qa plan abort --project P --execution-id ID --reason TEXT. An in-flight host abort retains custody until the runner records case cleanup; only a declared baseline requires restoration. An as_is case or chain without a baseline settles on its no-restore cleanup receipt. Follow safe host cancellation when it returns qa_abort_restore_pending. --continue-mission resumes a stale-settled mission with its unchanged plan snapshot and preserved host state. Continuation commands omit --test-machine; the scheduler keeps simultaneous cases on their declared driver and full host set. For single-host cases it recovers each platform’s original host from durable leases and runs, and selects a fresh eligible host only for a platform not used before. Read yoke qa plan run --help for the complete requirements.

Function protocol

Source-generated plans record their exporter commit with yoke qa plan-cases sync --project P --plan-id N --cases-file SOURCE_EXPORT. The commit must be on the project's verified default branch. A source-bound plan whose cases the Yoke build itself generates also converges when a server running that build boots, moving forward to the build commit; every other source-bound plan moves only through sync. Once bound, a plan requires provenance on every replacement and refuses the interactive editor; manual one-off correction plans remain separate. Source sync against a serving build without this field refuses before writing and names the required release. Frozen deployment snapshots retain source provenance. A stage materializes its frozen definitions even after the saved plan changes; a selected or refreshed source not carried by the run's candidate refuses qa_plan_source_candidate_mismatch. Release a candidate carrying the newer source, or use a run-bound correction. A plan the run froze while unbound keeps its frozen cases for that run after a later sync binds it; its stages, retraction and retirement proceed. A snapshot with no source field at all refuses qa_plan_source_snapshot_missing. A sync moves only forward: its revision must equal or descend from the plan's recorded revision. An older revision refuses qa_plan_source_revision_regression and an unprovable recorded revision refuses qa_plan_source_ancestry_unverified; both name the two revisions and write nothing. Export from current main and sync again.

Standalone project QA uses qa.plan_execution.begin with a project-scoped global target and payload plan, optional source_revision, source_ref, checkout_path, test_machine, and continue_mission. Adapter: yoke qa plan run --plan PLAN --project P; read its --help for source bindings. State, heartbeat, advance, complete, abort, review, and machine/mission calls retain that target and verify the execution's project and actor/session. Responses carry standalone_plan_id; snapshots and proof reads carry standalone_execution_id. Requirement-targeted recording verifies the same owner, and browser context accepts a standalone qa_requirement target. Standalone execution uses existing QA records and never credits item or deployment gates.

Case environment obligations

Every case is self-contained: it never relies on the runner's seat, claim or session.

A case can declare "target_envs": ["prod"] in the JSON supplied to yoke qa plan-cases replace or yoke qa plan edit. These are unique registered environment names on the plan's project, each with a reviewable URL. Use [] to keep the plan's default target. qa plan edit puts every case field in its document, target_envs and stage_reason included; a save that leaves out a field of an existing case and would reset its stored value is refused as qa_plan_edit_unedited_field_changed, naming each case and field.

stage_reason is optional descriptive metadata. It accepts creates_or_destroys_data or changes_infrastructure; an unknown value refuses as stage_reason_invalid. Target resolution uses target_envs independently of this metadata.

When the plan's project declares qa.restrict_execution_to_self: true on the environment the control plane runs as, that control plane runs only QA that targets its own environment; Yoke's hosted Stage and Production declare it. There, a standalone yoke qa plan run whose case targets another environment refuses with cannot execute QA target. Run the plan from the target environment's own control plane (yoke --env NAME qa plan run --plan PLAN --project P), or prove the case through a deployment QA stage that targets that environment. Without the setting, a control plane may run a plan against any registered environment.

Item materialization creates one requirement per environment and host baseline, with target_env and an immutable execution target on each row. Rematerializing keeps matching case key, baseline, and environment identities, and waives only variants removed from the definition. Deployment stages materialize only cases applicable to their own target; evidence from Production cannot prove Stage.

Attach delivery cases at the workflow's release transition with --qa-phase post_deploy, then materialize them before release composition so Stage-targeted obligations enroll the item on a matching supplemental run. The item stays at its release wait until every blocking target is accepted. missing_target_proof names the missing environment and matching active flows; if no flow can carry it, configure an item QA stage for that environment and deliver the same candidate through it. Use target-relative commands such as BASE_URL rather than hardcoded Stage or Production endpoints in shared cases.

A standalone execution has one immutable target. A plan requiring other environments refuses with qa_plan_requires_environment_scopes before writing cases. Use each item requirement or matching deployment QA stage to collect those separate proofs; a standalone plan run never completes an item gate.

Cases that wait for real traffic

Some checks can only be judged once real production traffic has happened after a deploy, such as "a real failed direct wake that a relay then claimed". Run at stage entry, they fail or prove nothing. Give such a case "wake_path": "manual" and a one-line wake_evidence:

{"case_key": "relay-claim-observation", "method_id": "exploratory-mission", "wake_path": "manual", "wake_evidence": "a session wake that failed directly and a relay then claimed exists after this release"}
wake_path Starts
automatic (default) When its stage begins: the stage driver wakes the member's owner
manual Once its owner confirms wake_evidence: the stage driver wakes the owner to check it

Write wake_evidence as the evidence itself, as something a registered read can confirm (yoke deployment-runs get, yoke db read, yoke qa requirement list), not as a time or a hope. Method, runner and verdict path are unchanged, and the case stays blocking until it is settled, waived or removed. manual without evidence refuses wake_evidence_required; evidence on an automatic case refuses wake_evidence_without_manual_wake; an unknown path refuses wake_path_invalid; more than one line or 300 characters refuses wake_evidence_not_one_line.

While one of a member's manual cases is open, the stage driver sends its owner one notice per open manual case instead of the ordinary stage wake, because one stage execution runs the member's whole roster. The notice names the evidence: check it with a registered read, run the member's cases if it exists, otherwise ask the operator through yoke say --steering to waive or remove the case. A parked holder is woken; a member with no live holder reaches the project's steering seat. The steering fleet report lists each open one under "waiting on manual wake" with its run, item, requirement, case, evidence, owner and run command. To mark an already materialized requirement, set the evidence first, then the path:

yoke qa requirement update --requirement-id N --field wake_evidence --value '<evidence>'
yoke qa requirement update --requirement-id N --field wake_path --value manual

The write reaches only that row. Correct the plan case as well, so later materializations carry it.

Recover a lost check-in response

yoke qa plan run --plan PLAN --project P --resume-execution-id EXECUTION_ID

Keep the original source and machine arguments. A response timeout leaves the action's outcome unknown: it does not cancel a server success. The check-in retries once with its exact request id, allowing the existing request ledger to replay a late success. It returns only cursor, target/roster identity, custody and liveness timing; it does not rebuild a full resume response.

If communication stays unavailable, outcome_unknown names the execution, phase, request, attempts and saved request evidence. A confirmed pause keeps its cursor, results and machine leases; it does not renew them. When the pause cannot be confirmed, preserve the command capture and last known custody. Park the owning session with yoke sessions touch --mode parked --reason "QA communication pause" while restoring communication. When a pause was unconfirmed, add the returned --recovery-file PATH to exact-ID re-entry: it reapplies only that saved pre-case check-in pause. A consumed receipt or changed cursor refuses; inspect the current outcome instead of reusing an old receipt.

Exact-ID re-entry validates the actor/session, subject, frozen source/target and live host custody before another case can start. Completed cases stay recorded. A lost heartbeat during cleanup stays in the capture and does not block case result submission. If submission also loses its response, outcome_unknown preserves that request and its result payload for inspection. An unadvanced action or recording outcome refuses automatic re-entry: keep the saved result and request evidence and ask the control-plane operator to inspect the durable cursor. No command replays an unrecorded case submission. Lost custody, permission refusals and terminal executions refuse with recovery. Never reset a host, spend another one-shot approval, or create a fresh campaign to repair a lost reply. Actual case failures and intentional aborts keep their own outcomes. Pause/resume needs a serving release carrying qa.plan_execution.pause and qa.plan_execution.resume; a serving-floor refusal names the control-plane operator who must supply it. Older heartbeat responses may contain a full resume contract; the client needs only the accepted check-in receipt.

Retire a plan

yoke qa plan retire PLAN --project P --reason "why the plan is retired"

Retire a plan when it should stop answering new work: its cases are wrong or unrunnable and no item still needs it. Run the command from a session holding a live steering seat covering the plan's project; any other caller refuses with steering_seat_required and the seat recipe. PLAN is the slug or numeric id.

Retirement records retired_at, the reason and the acting actor on the plan. The plan stays readable: yoke qa plan get PLAN --project P shows the retirement (a case whose recorded correction history is broken shows outcome replacement_graph_invalid with its named repair, retired or not), and yoke qa plan list --project P --include-retired lists retired plans beside active ones. Recorded requirements, runs and reviews keep their evidence. From then on the plan refuses edits and materialization. There is no un-retire; author a corrected plan with yoke qa plan create.

While anything still depends on the plan, retirement refuses with qa_plan_retire_dependents and names each dependent with the command that settles it:

Dependent Settle it with
Unsettled item requirement, not yet executed yoke qa item-plan retract
Unsettled requirement with a failed or missing latest attempt yoke qa requirement waive or supersede
In-flight execution whose roster reaches the plan let it finish, or yoke qa plan abort
Project default that attaches the plan to new items yoke qa project-default unset

A requirement whose newest attempt passed does not hold the plan, and neither does a copy on a finished item: nothing can run it again, and a finished item cannot be claimed to retract it. Retirement retracts those unexecuted copies, and the attachment behind them, in the same transaction with the rationale QA plan retired: <reason>, and returns their ids in retracted_requirement_ids. Executed copies stay as recorded history. Repeating retirement on a retired plan returns the recorded retirement unchanged with already_retired: true, so a retry after a lost reply is safe. The command needs a serving release carrying qa.plan.retire; an older server refuses with the serving floor named.

Standalone plans · Yoke