Verification
Workbench QA tabs:
| Tab | Meaning |
|---|---|
| Methods | Registered contracts cases use to prove a claim (command, browser, …) |
| Plans | Project-scoped ordered cases and attachments |
| Activity | Readable outcomes from requirements, runs, evidence |
Plans prioritize review and failed cases, show recency, and expand full review reasons. Activity pages through the latest 500 cases per project, including earlier days, with text, outcome and local-date filters. It shows the loaded boundary; filters never search older cases. Rows show known item identities immediately and add public references after lookup. Failed reads offer Retry and remain distinct from a successful empty result.
How gates work
Workflows attach plans to transitions (for example reviewing-implementation). Run the full suite once through its QA case:
yoke qa case run --requirement-id <id>
Binding your project's command
Bind a source-level command with no deployment environment flags:
yoke qa registered-command set --project <p> --scope quick --command "<argv>"
This converges the registered-command-quick plan, case, runner, and default
gate attachments. Any shell argv works, including Maven, PHPUnit, xcodebuild,
docker compose run --rm tests, or pytest. Use a reliable documented slice
for quick; add --scope full only for a genuinely broader command.
Read a binding through its project-local plan slug:
yoke qa plan get registered-command-quick --project <p> --full
Replace quick with full, e2e or smoke for another scope. The plan
shows the bound command in method_config and its target. A not-found plan means that scope has no
binding; confirm the command and register it with set above.
quick and full always materialize a project target, even when the project
has exactly one declared environment. Plan list and detail views label this
project source · no deployment environment.
Deployed scopes use one explicit target contract:
| Runner | e2e / smoke registration |
|---|---|
| Local, declared environment | add --environment SITE/NAME (or an environment ID) |
| Local, runtime URL | add --requires-base-url; the case run must supply HTTP(S) --base-url |
CI via scope_workflows (e2e only) |
add --environment SITE/NAME; runtime URL mode is refused |
Post-deploy smoke uses a Command case on the release candidate. A CI mapping
for it refuses deployment_ci_case_unsupported; remove that mapping.
Local deployed scopes require one target. Invalid targets refuse before writes.
Generic yoke qa plan create still requires --environment.
Test roots are independent Project Structure entries. Record each monorepo
tree with a keyed test_roots put; the quick command may intentionally cover
one slice while the full command aggregates all suites.
Declaring a GitHub Actions test workflow routes those scopes to CI:
yoke projects capability-settings set --project <p> --cap-type ci_workflow_file \
--new --settings-json '{"workflow_file":"ci.yml"}'
Without that declaration the scopes run locally in the item's worktree, which
is a correct configuration rather than a downgrade. A project-structure
verification_profiles.test_command entry is descriptive and is never the
gate command. Jenkins, GitLab CI, Bitbucket Pipelines, fastlane, and an
XCTest or container command without an Actions test workflow stay on the local
command method; they are not ci_workflow_file declarations.
Name the workflow that runs the suite. The binding refuses one the gate cannot reach, because the gate starts a workflow by dispatching it:
- No
workflow_dispatchtrigger carrying ayoke_dispatch_idinput — refused for every project; the gate could never start a run. - No
pull_requesttrigger — reported, and refused for a project declaringmerge_queue, whose gate reads the landing pull request's own run. - Not a file under
.github/workflows/, or not a workflow at all — refused, naming any other CI system the repository carries.
Where the control plane holds no checkout for the project, the declaration cannot be read and the result names that rather than guessing. The boot-time convergence never refuses over a stale declaration: it binds the local runner and reports the reason, so one project's rename cannot stop a fleet from booting.
Declaring merge_queue requires GitHub bound, ci_workflow_file declared,
and that workflow carrying a merge_group trigger — without it the queue's
integration gate has nothing to run and a queued pull request never merges.
Proving an exact producer candidate
The configured release-time exact-pair consumer proof gate owns this proof. Item merges need no separate consumer build or verification-only companion; consumer code changes still need their companion. When an explicitly requested consumer case uses a producer candidate, hand it the full commit the producer gate actually pushed after any rebase.
Declare a producer candidate in the case's method_config.ci_workflow_inputs:
yoke qa requirement add --item PREFIX-N --method-id command-ci \
--qa-phase verification --workflow-transition reviewing-implementation \
--method-config '{"command":"...","ci_workflow":"ci.yml",
"ci_workflow_inputs":{"product_ref":"<40-hex candidate>"}}' \
--instructions "..." --expected-outcome "..."
When inputs carry product_ref, QA checks the full 40-hex commit on the
producer remote before preparing a dispatch. The workflow's existing
product_repo input takes precedence; otherwise the consumer item must have
one upstream cross-project companion project with a GitHub repository binding.
Missing or ambiguous repositories refuse by name. product_ref_unpublished
means the producer must finish its publishing gate and send the pushed commit;
update the consumer requirement and retry. An unreadable repository refuses
product_ref_unverified; restore GitHub read access before retrying. Cases
without product_ref skip this check.
Values must be non-empty strings, and the reserved yoke_dispatch_id
correlation input is refused — dispatch sets that one itself. Every dispatch
path carries the declared inputs: the gate's first dispatch, its one
never-started redispatch, and the merge boundary's post-rebase run, which
reads them back from this same requirement rather than from anything the
merge command was told.
Correlated CI identity includes a deterministic digest of the effective
dispatch arguments (project, repository, workflow, ref, and all resolved
inputs). Correcting product_ref on an unchanged requirement and consumer
commit starts a fresh dispatch. Identical retries, including reordered input
keys, recover the same run; never-started retries and merge-boundary dispatches
use the same binding. No-input cases keep their existing adoption and rejoin
behavior. Historical run records are retained. A genuinely different payload
under the same bound identity still refuses idempotency_key_collision:
review the differing payload and its recorded intent rather than retrying it
unchanged or altering old run history.
A case declaring inputs never reuses a run it finds. GitHub's run record
does not expose the inputs a workflow_dispatch run was posted with, so a run
sitting on the right commit cannot be shown to have built against the right
candidate — and one built against a different candidate is not covering
evidence. Adoption and attachment are therefore skipped, and the gate
dispatches the only run whose inputs are known. A pull_request run carries
no dispatch inputs at all, so a project verifying through its merge queue
refuses the declaration by name instead of recording a proof it cannot make.
Cases declaring no inputs adopt completed successful runs and attach to
in-progress runs. Failed, cancelled and timed-out runs request a fresh dispatch
on the same commit; the rejected run identifies that retry.
When the project has no suite
A repository with nothing runnable does not get an empty gate. An empty
requirement set refuses as GATE_QA_REQUIREMENTS_EMPTY; it can never report
green for a review nobody performed.
Offer a minimal suite first; one real test makes a real gate. When that is declined — an idea-only repo, a content site, a client who will not fund tests yet — record the decision instead of inventing an argv:
yoke qa no-tests attest --project <p> --reason "<why there is no suite>"
The reason is required. One call records the posture and retires any
registered-command-* plan, so a project can never hold both declarations.
For every workflow that consumes project testing defaults, command absence
seeds a blocking no_tests_declared requirement where
registered-command-quick would have attached. Its passing run is recorded by
an agent and labeled agent-attested / no-tests-declared; it never implies a
suite ran. Registering any command while the explicit posture stands — the
command-ci runner included — is refused by name.
When the project later gains a suite, clear the posture and bind the command:
yoke qa no-tests clear --project <p> --reason "<what changed>" && yoke qa registered-command set --project <p> --scope quick --command "<argv>"
Registration also refuses an argv the repository provably lacks: a path-shaped
command like vendor/bin/phpunit that is not in the checkout is named and
rejected rather than bound as a gate that would fail wherever it ran. A bare
program name the registering machine lacks is reported, not refused — the
suite often runs somewhere that machine is not.
Known-red and flaky suites
Do not bind a known-red or materially flaky suite as a blocking project
default merely to make it visible. Preserve its roots, exact argv, and known
condition. Seed each relevant item with a blocking implementation_review
requirement and a non-blocking command case for the suite. The advisory case
records the current result without manufacturing a green gate or making a
known baseline failure block every item.
When the project binds CI for quick/full scopes, commit and let the case runner push the lane branch; the verdict names the CI run URL and head sha.
Local iteration
While implementing, use impacted selection:
yoke watch pytest --impacted main --bounded
When the project declares a ci_workflow_file capability, that selection
runs on its CI against the pushed lane commit — so commit first; it refuses
an uncommitted tree and a checkout on the base branch. --local (or
YOKE_PYTEST_LOCAL=1) runs it on this machine instead, under one
machine-wide xdist worker budget.
Full-suite authority on protected merges is CI (when configured). Local full sweeps are the CI-outage fallback.
Browser QA
Browser cases can select method_config.color_scheme: "light" or "dark".
Each case owns its preference; omission keeps the ordinary browser behavior.
Requested and observed media preference travel with run and screenshot evidence.
Missing/mismatched observations fail; Browser configuration
explains recovery. Separate cases inspect both modes, with normal visual review.
Browser methods use the packaged browser runtime. Browser targets owns method configuration; Browser scenarios owns actions, assertions and execution. The QA platform owns obligation and gate rules.
Linux onboarding installs the packaged browser in user space and checks its
system libraries through Playwright. Missing libraries install automatically
with root or passwordless sudo. An interactive terminal lets the OS request
the sudo password once; unattended machines without that authority fail fast
with the missing dependencies and a repair step. Agent-time setup uses the same
function through yoke qa browser setup. Screenshot captures use the platform
temporary directory unless an output directory is supplied.
Scoped release QA can require several Test Machines. Use yoke watch qa-plan -- --item ITEM --stage STAGE --project P without a host
pin. The command gives each machine its own ordered execution and FIFO lease,
then credits all results to the same member. After a host wait or independent
review, repeat that command to continue. Every required host must pass before
member acceptance. A case needing several hosts at once declares
method_config.test_machines beside its driving test_machine; its plan
execution holds the complete set through the case and review. See
case attachment.
Item QA on releases
Open Shipping, then open a deployment run to inspect its carried items. Both pages show each item's applicable post-deploy obligations before deployment copies, attempts or artifacts exist. Not started means proof is still owed; Waived records an explicit waiver and does not count as passing.
Active releases show current source requirements and attached-plan cases for their QA destinations. A matching deployment copy supplies that release's result and evidence. Previous releases keep their own attempts; takeover starts with pending obligations on the replacement run. Completed releases retain their frozen definitions and results when item sources later change.
An empty obligation list, loading, and a failed read are different states. A named Item QA read error includes its recovery: reload the page, then ask the project operator to repair the named definition or target if it persists.
- Local connection repair
Repair local credentials and actor references while preserving the selected connection.
- Server health readiness
Read cached server readiness, startup probes and named recovery.
- Browser action evidence
Budget browser actions and retain original failure and timing evidence.
- QA platform
Read obligation dimensions, materialization and evidence gates.
- Requirement discharges
Derive requirements and settle waived, superseded or retracted obligations.
- Requirement state
Evaluate current attempts, review authority and exact subject proof.
- Standalone plans
Run project plans and recover an interrupted or ambiguous execution.
- Success policy
Apply all-pass aggregation and attempt-local measurements.
- Case attachment
Bind cases to authorized items, tasks and deployment targets.
- Consumer proof
Use the release-time exact-pair gate and diagnose producer failures.
- Starting state and activity
Declare Machine starting state and read case activity.
- Deployment plan execution
Run frozen cases across members, machines and shared host turns.
- Deployment QA continuity
Continue existing QA through takeover and recover the exact execution.
- Failed item QA
Keep correction ownership, wait for delivery and retest the qualifying candidate.
- Browser targets
Select Browser targets, methods, identities and viewport configuration.
- Browser scenarios
Author actions and assertions, then execute the Browser case.
- Browser evidence
Read captures and distinguish execution from inspected verdicts.
- Browser identities
Declare personas, sign in and use isolated browser profiles.
- Exploratory missions
Define discovery territory and follow execution, review and human gates.
- Exploratory evidence
Use substrates, retain evidence and submit mission decisions.
- QA model
Read requirement, execution and artifact storage contracts.
- QA CLI
Use registered requirement, execution and evidence commands.
- Machine QA
Use built-in machine methods and prepare controlled test hosts.
- Test Machine desktop
View remote desktops and recover cleanup or disk-space refusals.
- Linux golden home
Read Linux baseline capture, restore and timeout recovery.
- Linux desktop applications
Detect installed desktop versions without starting the apps.
- Product smoke
Find the source-maintainer smoke procedure and project plan entry.
- Real harness QA
Find real-harness Machine checks and their subject identity contract.