Quick answer: A concrete request and its raw response are dynamic evidence, and they carry weight that a static suspicion cannot. When a review flags a changed API path, store the request that exercises it, the response with status and body, and the asserted side effect, and keep them with the review record. This turns a claim about what the code might do into evidence of what it did, and the check can be rerun later.
Why the request and response count as evidence
Static evidence reasons about the code, through typecheck, lint, build, or a model hypothesis, and it is valuable but never executes the path. A request is different. It runs the real endpoint and returns an observable response, which is direct evidence of the behavior rather than an inference about it.
The response also exposes what the diff cannot show. A 200 with a body that breaks the contract, or a normal response that hides the wrong side effect, only becomes visible when the call is made and the output is read.
Evidence types side by side
| Evidence | Runs the code? | What it shows |
|---|---|---|
| Typecheck, lint, build | No | Static consistency and known patterns |
| Contract and type drift | No | The schema and the code disagree |
| AI hypothesis | No | A model claim, always labeled |
| Request and response | Yes | The endpoint's real behavior |
| Test, coverage, smoke | Yes | Dynamic verification across paths |
The request row is the smallest unit of dynamic evidence, and it is the natural confirmation for a flagged API change.
How to capture it well
- Build a request that reaches the flagged path with the input the trigger needs.
- Send it and record the status and the full response body, not a summary.
- Assert the body against the contract so a type or field mismatch is visible.
- Record the side effect, since the response alone does not show the storage change.
- Attach the request and the raw output to the review record with the decision.
- Rerun the same call later to confirm the evidence still reproduces.
Take a flagged deletion filter. The request sends a selection change with archived notes present, and the response is a normal 200. The raw body alone looks fine, but the attached side effect shows an archived row was removed, which is the evidence that confirms the suspicion. A second request that keeps the archived note is stored alongside it, and the pair documents both the defect and the corrected behavior.
Reading a 200 honestly
A success status is transport evidence, and it is not enough on its own. Read the body against the contract and the side effect in the data, because the endpoint can accept the call while returning the wrong value or writing the wrong row. Treat a 200 that fails either assertion as a failed verification rather than a pass.
Each evidence item carries a reproducible command and raw process output, and the deterministic verdict, with no LLM involved, passes only fully verified evidence. An AI-only claim stays a hypothesis until a request or a test backs it.
Powerduck keeps the request, the response, and the decision in the review, so the dynamic evidence stays attached to the code rather than in a separate tool.
Capturing headers and timing
The body is not the whole response. Record the headers that carry the contract, such as content type and any rate or pagination metadata, since a body that looks right can arrive with the wrong type or a missing link the next step needs. Note the timing as well, because a request that returns the correct value too slowly can break a flow that assumes a prompt answer. These are still dynamic evidence, and they are reproducible from the same call. Keep the raw response intact rather than trimming it to the fields you expected, because the unexpected field is often the one that reveals the drift, and a truncated record cannot answer a question that comes up later.
Honest limits
The request confirms the path the call exercises, and it does not cover untested branches, so keep those cases visible. Dynamic loading and external consumers can also remain outside the call, and the model can raise false suspicions or miss defects.
When a request cannot reach the flagged branch, treat the result as inconclusive and change the input rather than counting the attempt as a pass.
Frequently asked questions
What makes a request dynamic evidence? It executes the real endpoint and returns an observable response instead of reasoning about the code.
Is the response body enough? No. Assert the body against the contract and check the side effect, since the storage change is hidden from the payload.
Why store the raw output? It is the basis for the decision and lets the same check be rerun and audited later.
The bottom line
Treat a stored request and its raw response as dynamic evidence that confirms a static suspicion, keeping the call, the asserted body, and the side effect with the review record. A 200 alone is not enough, and a request that never reaches the branch stays inconclusive. The observable behavior is stronger than a claim about what the code might do, and the reproducible record is what makes the decision defensible. Read more in the API scenario testing guide.

Top comments (0)