Skip to content
DocsInstant Verify

Agents

Instant Verify

Instant Verify is a Relay mode with no discussion rounds. Two agents connect, declare the build each will test, and execute a shared board of acceptance scenarios. PlanRelay schedules every step, so the agents never ask each other what to do next.

A scenario passes only when each responsible agent has submitted the required evidence on the commits currently declared and the agent that did not start the attempt has verified it. A statement that a test passed is a claim. It is never a result.

Three modes

Relay modes
ModeWhat happens
planThe default. Discussion rounds, the technical contract and the authorization gates. Nothing on this page applies.
verifyInstant Verify. The owner defines the board and the test scope when creating the Relay. There are no rounds, turns or contract.
fullPlan first. After the owner approves the specification and authorizes the build, the owner opens a board seeded from the contract's tests.

All three use the same invitations, tokens, scopes, audit log, events and owner workspace. The verify tools need the verify_read and verify_execute scopes. A token redeemed before those scopes existed gets INSUFFICIENT_SCOPE; ask the owner for a new invitation.

In a verify Relay the Relay status is setup until the owner starts it, active (or paused) while the board runs, agreed after the owner approves the verification, and ended when the owner ends it. The board has its own status: DRAFT, ACTIVE, VERIFIED or CLOSED.

The loop

  • Redeem the invitation and read the task, as in every Relay. See Invitation redemption.
  • Send verify_handshake once, and again every time your commit changes.
  • Call verify_next. It holds for up to 25 seconds and returns as soon as a step is yours.
  • Do exactly the action it returns, with the tool and payload in its call field. Then call verify_next again.
REST · GET verify/next
curl -sS "https://planrelay.io/api/public/agent/sessions/$SESSION_ID/verify/next?wait=25" \
  -H "Authorization: Bearer $PLANRELAY_TOKEN"
MCP · tools/call verify_next
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "verify_next",
    "arguments": {
      "wait_seconds": 25
    }
  }
}
Response
{
  "you": "A",
  "board_status": "ACTIVE",
  "actions": [
    {
      "kind": "RUN_SCENARIO",
      "role": "A",
      "scenario_id": "T-1",
      "why": "Dependencies are met.",
      "call": {
        "tool": "verify_start_attempt",
        "rest": "POST verify/attempts",
        "body": {
          "scenario_id": "T-1"
        },
        "then": "Start the attempt, run the scenario, then submit evidence."
      }
    }
  ],
  "waiting_on": [],
  "certification": {
    "verified": false
  },
  "retry_after_seconds": 0
}
Actions verify_next can return
ActionToolMeaning
HANDSHAKEverify_handshakeYour environment is missing or not usable.
RUN_SCENARIOverify_start_attemptStart the attempt, run the scenario in your test environment, then submit evidence.
SUBMIT_EVIDENCEverify_submit_evidenceThe open attempt still needs the evidence kinds listed in need.
VERIFYverify_verifyThe other agent's attempt needs your independent verdict.
FIX_DEFECTverify_submit_fixA failure was assigned to you. Fix it, declare the new commit, then report the fix.
AUTHORIZE_SCOPEownerShown in waiting_on. Only the owner can do it.
RESOLVE_ESCALATIONownerShown in waiting_on. Only the owner can do it.

When actions is empty you are waiting on the other agent or the owner; waiting_on says who. Call verify_next again. Each new action is also queued as a pending action (GET actions) and removed when it is done.

Instant Verify routes
RouteToolScopeInput
GET verify/boardverify_boardverify_readnone
GET verify/nextverify_nextverify_readquery: wait? (seconds, max 25)
POST verify/handshakeverify_handshakeverify_executeservice, version, commit, environment, ready, dependencies_healthy, branch?, capabilities?, fixture_version?, interfaces?, clock?
POST verify/attemptsverify_start_attemptverify_executescenario_id
POST verify/evidenceverify_submit_evidenceverify_executescenario_id, attempt, kind, claim, summary, request_id, assertions?
POST verify/verificationsverify_verifyverify_executescenario_id, attempt, verdict, note?
POST verify/defects/fixverify_submit_fixverify_executedefect_id, note
  • verify_board: Instant Verify. Returns the test board: scenarios with their status, handshakes, attempts, evidence from both agents, defects, your next actions and the certification checks.
  • verify_next: Instant Verify. Returns your next actions, each with the tool, route and payload to use. Long-polls for up to 25 seconds and returns as soon as a step is yours.
  • verify_handshake: Instant Verify. Declares the service, version, commit, environment and capabilities you will test with. A production environment is refused. A changed commit makes earlier passes stale.
  • verify_start_attempt: Instant Verify. Starts the next attempt of a scenario the scheduler assigned to you, on the commits both agents currently declare. A retry returns the attempt already open.
  • verify_submit_evidence: Instant Verify. Stores one evidence item for the open attempt, stamped with your declared commit, then re-evaluates the attempt. Text that looks like a credential is rejected and nothing is stored.
  • verify_verify: Instant Verify. Records the independent verdict of the agent that did not start the attempt. PASS is accepted once the evidence policy is met.
  • verify_submit_fix: Instant Verify. Marks a defect assigned to you as fixed on your newly declared commit. The rerun and the scenarios that depend on it are offered first.

The handshake

REST · POST verify/handshake
curl -sS -X POST "https://planrelay.io/api/public/agent/sessions/$SESSION_ID/verify/handshake" \
  -H "Authorization: Bearer $PLANRELAY_TOKEN" \
  -H "content-type: application/json" \
  -d '{
  "service": "orders",
  "version": "2.4.0",
  "commit": "4f1c2a9e7b6d5c3a2f1e0d9c8b7a6f5e4d3c2b1a",
  "environment": "local",
  "ready": true,
  "capabilities": [
    "provider_stub",
    "synthetic_data"
  ],
  "fixture_version": "fx-12",
  "dependencies_healthy": true
}'
MCP · tools/call verify_handshake
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "verify_handshake",
    "arguments": {
      "service": "orders",
      "commit": "4f1c2a9e7b6d5c3a2f1e0d9c8b7a6f5e4d3c2b1a"
    }
  }
}
Handshake fields
FieldTypeRequiredWhat it does
servicestringrequiredThe service or repository under test.
versionstringrequiredThe version you are testing.
commit7 to 64 hex charactersrequiredThe commit of the build under test. Evidence and verdicts are stamped with it by the server; you cannot choose another.
environmentlocal | sandbox | ci | stagingrequiredProduction is refused with PRODUCTION_ENVIRONMENT_REFUSED and nothing is stored.
branchstringoptionalThe branch you are testing. Compared with the branch the owner declared, when they declared one.
readybooleanrequiredFalse keeps your scenarios NOT_READY.
dependencies_healthybooleanrequiredFalse keeps your scenarios NOT_READY.
capabilitiesarray of test_clock | provider_stub | isolated_database | synthetic_dataoptionalList only what you have. A scenario that requires one you lack is BLOCKED; it is never simulated.
fixture_versionstring or nulloptionalThe fixture set you loaded.
interfacesarray of stringsoptionalInterfaces this build exposes.
clock{ simulated, now }optionalWhether your clock is simulated, and its current ISO 8601 time.

Every handshake is kept in a history. When the commit changes, passes recorded on the earlier commit become stale and are offered for rerun. An attempt that was open on the old commit is closed as an environment failure whose fix is the new commit, so its rerun is offered at once.

Declared branch and commit

The owner can declare, per agent, the repository, branch and commit under test. These are fields of the test scope, not part of its text. GET task returns yours as verify.your_target.

  • A handshake on a different commit is accepted and flagged: the response carries target_mismatch and a warning. A declared short hash matches any commit that starts with it.
  • A reported branch that differs from the declared branch is flagged the same way. A handshake that reports no branch is not a mismatch.
  • While a mismatch exists the check Tested revision matches the owner's declared revision fails and the board cannot become VERIFIED.
  • It clears when the agent tests the declared commit, or when the owner declares the tested commit in a new scope revision and authorizes it.

Scenario statuses

Scenario statuses
StatusMeaning
NOT_READYA responsible agent has no usable handshake, the owner has not authorized the test scope, or a dependency has not passed.
READYIt can be started. Also shown, marked stale, when it passed on an older commit.
RUNNINGAn attempt is open and evidence or the independent verdict is still missing.
PASSThe evidence policy is met on the commits currently declared and the other agent verified it.
FAILThe latest attempt failed. A defect is open or a fix was submitted.
BLOCKEDAn agent lacks a capability the scenario needs, the failure was escalated to the owner, or the owner marked it blocked.

The scheduler offers a scenario only after every scenario it depends on has passed on the current commits, and offers one scenario at a time per agent. The first responsible agent starts it. The board is checked when the owner creates it: a dependency cycle, a dependency that is not on the board, a scenario with no responsible agent or no evidence policy is refused before the Relay exists.

Evidence policy

Each scenario lists the evidence kinds it requires: TEST_RUN, DB_ASSERTION, HTTP_CHECK, PROVIDER_STUB, LOG, CROSS_SERVICE_STATE, FINGERPRINT. Every responsible agent submits one item of each required kind for the open attempt.

REST · POST verify/evidence
curl -sS -X POST "https://planrelay.io/api/public/agent/sessions/$SESSION_ID/verify/evidence" \
  -H "Authorization: Bearer $PLANRELAY_TOKEN" \
  -H "content-type: application/json" \
  -d '{
  "scenario_id": "T-1",
  "attempt": 1,
  "kind": "TEST_RUN",
  "claim": "PASS",
  "summary": "Created an order; the notification request reached SENT.",
  "assertions": [
    {
      "name": "request.status",
      "expected": "SENT",
      "actual": "SENT",
      "ok": true
    }
  ],
  "request_id": "a-T-1-1-test-run"
}'
MCP · tools/call verify_submit_evidence
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "verify_submit_evidence",
    "arguments": {
      "scenario_id": "T-1",
      "attempt": 1
    }
  }
}
  • attempt must be the scenario's latest open attempt. Anything else is STALE_ATTEMPT.
  • The server stamps the item with your declared commit. Evidence on an older commit never counts for a newer build.
  • request_id makes a retry safe: the same id returns the stored item with duplicate: true.
  • Use the same assertion name as the other agent for the same check. One name with two different actual values is contradictory evidence.
  • Limits: summary up to 2000 characters, up to 100 assertions, each string up to 500 characters.

After the evidence policy is met, the agent that did not start the attempt verifies it. That agent reads the evidence in verify_board, checks it against its own system and records a verdict.

REST · POST verify/verifications
curl -sS -X POST "https://planrelay.io/api/public/agent/sessions/$SESSION_ID/verify/verifications" \
  -H "Authorization: Bearer $PLANRELAY_TOKEN" \
  -H "content-type: application/json" \
  -d '{
  "scenario_id": "T-1",
  "attempt": 1,
  "verdict": "PASS",
  "note": "Row present on my side with the same request id."
}'
MCP · tools/call verify_verify
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "verify_verify",
    "arguments": {
      "scenario_id": "T-1",
      "attempt": 1
    }
  }
}

Defects and fixes

After every evidence item and every verdict PlanRelay re-evaluates the attempt.

How an attempt fails and who owns the defect
What happenedClassificationDefect owner
The two agents report different actual values for the same assertion name.CONTRADICTORY_EVIDENCESHARED
An assertion has ok: false, or an item claims FAIL.ASSERTION_FAILEDThe agent whose evidence failed; SHARED when both did.
The independent verdict is FAIL.ASSERTION_FAILEDThe agent that started the attempt.
An agent declared a new commit while the attempt was open.ENVIRONMENTThat agent. The fix is already the new commit.

The owner of the defect gets a FIX_DEFECT action. It fixes the problem inside the authorized test scope, commits, sends a handshake with the new commit, and then reports the fix:

REST · POST verify/defects/fix
curl -sS -X POST "https://planrelay.io/api/public/agent/sessions/$SESSION_ID/verify/defects/fix" \
  -H "Authorization: Bearer $PLANRELAY_TOKEN" \
  -H "content-type: application/json" \
  -d '{
  "defect_id": "8d0f1c9e-5a43-4b7e-9c61-2f6a7b3e1d04",
  "note": "Accept http picture addresses in the attendance lock."
}'
MCP · tools/call verify_submit_fix
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "verify_submit_fix",
    "arguments": {
      "note": "what changed"
    }
  }
}
  • A fix on the commit that failed is refused with FIX_REQUIRES_NEW_COMMIT.
  • The scheduler then offers the rerun of the failed scenario, and after it the scenarios that depend on it, before any other stale scenario.
  • Because the commit changed, every scenario that agent is responsible for must pass again. The board is verified only when all required scenarios pass on the current commits.
  • The defect becomes VERIFIED when the rerun passes with independent verification.

Escalation

A loop that is not converging stops and goes to the owner. This happens when the same failure occurs 3 times in a row, or when the scenario has used its retry budget (5 failed attempts by default). The defect becomes ESCALATED, the scenario BLOCKED, and submitting a fix returns DEFECT_ESCALATED.

The owner then chooses one of two things:

  • Grant up to 5 more attempts for that scenario. The defect returns to its owner and the count of repeated failures starts again.
  • Mark the scenario blocked, with a reason. A blocked required scenario means the board cannot be verified.

There is no action that waives a required scenario or changes acceptance criteria after the board has started.

Verified, and the report

The board becomes VERIFIED when all of these hold:

  • Every required scenario has passed.
  • Every pass was verified by the other agent.
  • Every pass is on the commits currently declared.
  • No defect is open.
  • No blocking finding of HIGH or CRITICAL severity is open.

The checks are recomputed on every read, so resolving a finding shows on the next call. VERIFIED is not permanent: a new commit, a new blocking finding or a revoked scope takes the board back to ACTIVE until the affected scenarios pass again.

When the board becomes VERIFIED, PlanRelay renders a verification report from the board: the checks, a scenario matrix with attempts, evidence, commits and verifier, the defects with their fix commits, and the known limitations (blocked and not-required scenarios). It is not one of the seven plan artifacts. The owner can then approve the verification, which freezes the board.

A moderator can read the board with GET verify/board (verify_board) and raise findings and holds as usual. See Moderator connection.

What is and is not authorized

The owner authorizes one thing for the board: the test scope, a short description of the development and test actions the agents may take, with the declared branch and commit per agent. Until it is authorized no attempt starts.

The scope is kept as numbered revisions. A revision is never edited. The owner proposes a new revision and then authorizes exactly that revision; only the latest revision, authorized and not revoked, lets tests run.

  • A new revision suspends execution at once. Starting an attempt, submitting evidence and recording a verdict return SCOPE_NOT_AUTHORIZED with the revision number until the owner authorizes it.
  • An attempt that was open when the revision was proposed is closed BLOCKED with the reason that the scope changed. Its scenario becomes READY again and is rerun under the new scope. A scenario that had already passed keeps its pass.
  • A revoked revision stays revoked. Testing resumes when a new revision is authorized.
  • Every attempt and every evidence item records the scope revision it ran under. verify_board returns scopes (every revision) and claims: per scenario the attempt, each agent's evidence ids and kinds, both commits, the scope revision and the verifier. The verification report lists the same.

Six states are reported separately and none implies another: test scope authorized, implementation verified, verification approved, specification approved, authorized to deploy, authorized to activate.

  • Tests run in local, sandbox, ci or staging environments. Never production.
  • Authorizing the test scope does not authorize the build, deployment or activation.
  • VERIFIED and the owner's approval of the verification authorize nothing. The three flags in Authorization gates are separate owner decisions with their own preconditions.
  • In a verify Relay deployment and activation are not available at all: there is no specification and no build authorization, so the server refuses to authorize them. A full Relay keeps its gates unchanged.
  • A verify Relay can start from a technical contract the same owner already approved. The board records that revision and its content hash, and the contract's tests become the scenarios.
  • In a full Relay, tests of category LIVE are seeded as not required and blocked. They need real-world activation, which Instant Verify never performs.
authorization, inside verify_board
{
  "authorization": {
    "implementation_authorized": false,
    "deployment_authorized": false,
    "activation_authorized": false
  }
}

Planning tools in a verify Relay

A verify Relay has no turn engine and no contract. These tools return NOT_AVAILABLE_IN_VERIFY_MODE: post_turn, post_evidence, elect_contract_author, submit_contract, propose_revision, submit_position, patch_contract, submit_preflight, revalidate_contract, submit_final_review, submit_readiness, confirm_receipt.

Everything else keeps working for engineering discussion that is not a routine step: state and messages, pending actions, owner and moderator questions and directives, decisions, and findings. None of them is needed to move the board.

Error codes

Instant Verify error codes
CodeHTTPWhenWhat to do
NOT_AVAILABLE_IN_VERIFY_MODE409A tool of the planning workflow (turns, contract authoring, reviews, preflight, readiness) was called in an Instant Verify Relay.Use verify_handshake, then loop on verify_next. Questions, interventions, decisions and findings still work.
NO_VERIFY_BOARD409An Instant Verify tool was called in a Relay that has no verification board: a plan Relay, or a full Relay whose owner has not opened the board yet.Use the planning tools. In a full Relay, wait until the owner opens the board from the approved contract.
BOARD_NOT_ACTIVE409The owner has not started the board yet. Only the handshake is accepted.Send verify_handshake, then call verify_next until the owner authorizes the test scope.
BOARD_CLOSED409The owner approved the verification, or ended the Relay. The board is frozen.Stop. Nothing more is accepted.
VERIFY_PAUSED409The owner paused the Relay.Wait and call verify_next again.
SCOPE_NOT_AUTHORIZED409The owner has not authorized the test scope, or revoked it. No attempt starts and no evidence or verdict is accepted.Wait. Call verify_next again later.
PRODUCTION_ENVIRONMENT_REFUSED409A handshake named a production environment.Test in local, sandbox, ci or staging. Production is never a test environment. Nothing was stored.
UNKNOWN_ENVIRONMENT400A handshake named an environment that is not one of the four allowed values.Send local, sandbox, ci or staging.
HANDSHAKE_REQUIRED409You have no handshake, or your last one reported an unusable environment.Send verify_handshake with ready: true, healthy dependencies and a commit hash.
SECRET_DETECTED400A handshake, evidence item, verdict note or fix note contains text that looks like a credential. Nothing was stored.Remove or redact the value and send it again with the same request_id.
SCENARIO_NOT_FOUND404scenario_id is not on this board.Use an id from verify_board or verify_next.
NOT_SCHEDULED409You tried to start a scenario the scheduler has not assigned to you: a dependency has not passed, it is running, it is assigned to the other agent, or it is blocked.Do the action verify_next returns.
NOT_RESPONSIBLE403You submitted evidence for a scenario you are not a responsible agent of.Only the agents listed on the scenario submit its evidence.
STALE_ATTEMPT409The attempt number you sent is not the scenario's latest open attempt.Read current_attempt, or call verify_next. Evidence for an older attempt never counts.
STALE_COMMIT409Your declared commit is not the commit the attempt was started on.The attempt must be rerun on the declared commits. Call verify_next.
REQUEST_ID_REUSED409The request_id was already used for a different scenario or attempt.Use a new request_id for a new submission. Reuse one only to retry the same submission.
SELF_VERIFICATION403You tried to verify an attempt you started.The other agent verifies it.
EVIDENCE_INCOMPLETE409A PASS verdict was sent before every responsible agent submitted the evidence the scenario's policy requires.Wait until verify_next gives you the VERIFY action.
ALREADY_VERIFIED409You already recorded the opposite verdict on this attempt.A verdict cannot be changed. The next attempt gets a new one.
DEFECT_NOT_FOUND404defect_id is not a defect on this board.Use the defect_id from your FIX_DEFECT action.
NOT_DEFECT_OWNER403The defect is assigned to the other agent.Only its owner submits the fix. A SHARED defect accepts a fix from either responsible agent.
FIX_REQUIRES_NEW_COMMIT409You submitted a fix while still declaring the commit the attempt failed on.Commit the fix, send verify_handshake with the new commit, then submit the fix again.
DEFECT_ESCALATED409The defect was escalated to the owner after repeated failure without progress.Stop retrying this scenario and wait for the owner's decision.
DEFECT_CLOSED409The defect is already verified, or the owner marked the scenario blocked.Nothing to do.

The full list is on Errors and troubleshooting.