Test your integration
The failure mode is silent: an agent that stops calling preflight.action still works. Every test
passes, every run succeeds, and governance quietly evaporates. Nothing surfaces it — which is exactly
why it needs a test.
Assert on calls, not on outcomes
Section titled “Assert on calls, not on outcomes”srv := vectadynetest.New(t)srv.VerdictFor("code.apply_patch", wire.DecisionBlock, "fragile file")defer srv.Close()
client, _ := vectadyne.New(vectadyne.Config{Endpoint: srv.URL()}.WithDefaults())result := runAgent(client)
srv.AssertCalled(t, wire.ToolPreflightAction) // it ASKEDsrv.AssertRequestCount(t, 1) // and did not retry a refusalif result.Acted { t.Error("agent acted despite a block verdict")}from vectadyne.testing import FakeControlPlane
with FakeControlPlane() as fake: fake.verdict_for("code.apply_patch", "block", "fragile file") result = run_agent(mcp_url=fake.mcp_url)
fake.assert_called("preflight.action") assert fake.request_count == 1 assert not result.actedTypeScript has no bundled fake — stub fetch and collect the calls. See
the tutorial.
Assert the request count
Section titled “Assert the request count”A block must produce exactly ONE request. So must a warn, and so must a forbidden fault.
This is not pedantry. An SDK or a retry wrapper that retried a refusal would hammer the control plane to receive the same answer, and the bug is invisible from the return value — you get the right verdict either way. Only the count shows it.
| Scenario | Requests |
|---|---|
block verdict | 1 |
warn verdict | 1 |
forbidden fault | 1 |
503 then 200 | 2, returning the success |
| Partially-accepted batch | 1 — returned, not retried |
The four tests worth having
Section titled “The four tests worth having”1. It asks. Assert preflight.action or context.assemble was called on the governed path.
2. It honours a hold. Given block, the action does not happen. This is where the
inverted polarity between SDKs gets caught.
3. A warn proceeds. Given warn, the action does happen. Easy to get backwards, and it is
the test that catches an integration that has quietly become an inline gate.
4. An unknown decision holds. Feed it a decision your client has never seen. It must hold.
Fail-closed is a property worth pinning, because the natural
implementation — decision not in ("block", "require_approval") — gets it wrong.
def test_unknown_decision_holds(): with FakeControlPlane() as fake: fake.verdict_for("code.apply_patch", "quarantine", "from a newer server") assert not run_agent(mcp_url=fake.mcp_url).actedTurning retries off
Section titled “Turning retries off”The fakes let you disable retries so a failure is reported on the first attempt rather than the third:
MaxAttempts = 1 # exactly one attempt, no retriesMaxAttempts = 0 # unset — the SDK installs its default of 30 and 1 mean different things on purpose. A design where the zero value meant “no retries” could
not distinguish “unset” from “disabled”, so defaults would silently overwrite the caller.
Do not test against a live control plane
Section titled “Do not test against a live control plane”Unit tests against a real endpoint are slow, need a credential, and fail for reasons unrelated to your code. Use the fake for behaviour; save the live endpoint for one smoke test.