# Trace an action to a failure

Canonical: https://fairleadhq.com/docs/recorder/developers/trace-a-failure/

Updated: 2026-10-10
Publication state: published
Product version: Source verified — 52de40a

Agent summary: Follow recorded actions, requests, and errors while keeping causality explicit. Action associations are timing-based leads rather than proven causes.

## Prerequisites

- A recorded session and the tester's expected and actual result

## Inputs

- A failing action with related requests and errors

## Outputs

- An evidence-backed investigation with explicit hypotheses

## Limitations

- Action associations are timing-based leads rather than proven causes

## Permissions

- Access to the recorded evidence

## Privacy

- Review logs and recorded values before copying or running artifacts


Follow recorded actions, requests, and errors while keeping causality explicit.

Start with the tester's expected and actual result, then trace the retained evidence around the failing action.

## Worked example: the sticky Blocked tag

Download and extract the [real sample bundle](https://fairleadhq.com/downloads/fairlead-recorder-sample-v1.zip). Open the recording folder described in [bundle structure](https://fairleadhq.com/docs/recorder/schema/#sample-reproduction-bundle). This investigation uses the supplied files directly.

The application in this recording is Quackban, a card board on SpaceDucking. See [About Quackban and credits](https://fairleadhq.com/docs/recorder/schema/#about-quackban-and-credits) for attribution to Ministry of Testing and the MoTaverse creators.

### Establish the expected result

In `session.md`, QA expects moving a card out of Blocked to clear its Blocked tag. The recorded path creates `QB-DEMO sticky Blocked` in Pond Redesign, moves it to Blocked, then to In progress. The session starts at `2026-10-07T04:43:24.309Z` and lasts 42 seconds.

The description also mentions Done and a reload in earlier runs. Those are tester observations about other attempts: this recording does not contain those checks.

### Match actions to the HAR

Action offsets in `session.md` are relative to the session start. HAR `startedDateTime` values are absolute UTC times. Add the offset to the start to locate nearby traffic, then confirm the card ID and payload rather than relying on timing alone.

All HAR indexes below are zero-based; Markdown action numbers are one-based.

| Evidence | Time (UTC, 2026-10-07) | What to inspect |
| --- | --- | --- |
| Action 17: Clicked Blocked | `04:43:49.834` (+25.525s) | The first lane change. |
| `log.entries[2]`: POST | `04:43:49.837` | Move payload contains the card ID and `status: "blocked"`. |
| `log.entries[3]`: GET | `04:43:50.465` | Board response after entering Blocked. |
| Action 20: Clicked In progress | `04:43:56.535` (+32.226s) | The move that should clear the tag. |
| `log.entries[4]`: POST | `04:43:56.539` | Move payload contains the same ID and `status: "in_progress"`; no `blocked` field is sent. |
| `log.entries[5]`: GET | `04:43:57.141` | Board response after leaving Blocked. |

The move endpoint ends in `ef480cff6458da319ee4e576095f30ac06003e3931bf8be09ee209dea582919f`; the board endpoint ends in `e4c54e0e02fd6c771bbd5710d32e931705db77533c1189bdcba83ed643a2f8b2`. These are recorded application routes, not Recorder APIs or stable endpoint names for other builds.

### Read the serialized payload

In the HAR, parse `request.postData.text` and `response.content.text` as JSON for these entries. Their bodies use an application serialization format with parallel `p.k` (keys) and `p.v` (values) arrays. This wrapper belongs to the captured application, not HAR or Recorder's Report schema.

For the second move, `t.p.v[0].p.k` is `["id", "status"]` and `t.p.v[0].p.v[1].s` is `"in_progress"`. The card ID is `3229d3de-fb6d-4196-8f89-f0bf94d63392`.

In the last board response, `p.v[0].p.v[2].a` contains the cards. The sample card is at index 44. Match its ID when inspecting another capture; array positions can change. Within that card, key 4 is `status` and key 10 is `blocked`. The status value is `{"t":1,"s":"in_progress"}` and the blocked value is `{"t":2,"s":2}`, unchanged from the preceding board response. The initial board response has `{"t":2,"s":3}` for blocked. QA's note interprets this transition as false → true → true; use the application's serializer to decode these tags in application tooling.

Save this TypeScript as `inspect-sample.mts` in the extracted recording folder. With Node.js 24 or later, run `node inspect-sample.mts` to print the relevant raw fields without sending any requests:

```typescript
import { readFileSync } from "node:fs";

type EncodedField = { t: number; s?: string | number };
type EncodedCard = { p: { k: string[]; v: EncodedField[] } };

const { log: { entries } } = JSON.parse(readFileSync("network.har", "utf8"));
const cardId = "3229d3de-fb6d-4196-8f89-f0bf94d63392";
const move = JSON.parse(entries[4].request.postData.text);
console.log("move fields:", JSON.stringify(move.t.p.v[0].p.k));
console.log("new status:", move.t.p.v[0].p.v[1].s);

for (const index of [1, 3, 5]) {
  const body = JSON.parse(entries[index].response.content.text);
  const cards: EncodedCard[] = body.p.v[0].p.v[2].a;
  for (const card of cards) {
    const fields = Object.fromEntries(
      card.p.k.map((key, i) => [key, card.p.v[i]]),
    );
    if (fields.id.s === cardId) {
      console.log(index, fields.status.s, JSON.stringify(fields.blocked));
    }
  }
}
```

Expected output:

```text
move fields: ["id","status"]
new status: in_progress
1 backlog {"t":2,"s":3}
3 blocked {"t":2,"s":2}
5 in_progress {"t":2,"s":2}
```

This is a reader for this sample's payload shape, not a general HAR or application-protocol decoder.

### Separate the finding from the hypothesis

`screenshots/003-area.png` shows the card with a red Blocked badge. Its crop does not show the lane heading; use the action sequence and final board response for the In progress state. `002-full.png` shows an earlier state with the card in the Blocked lane.

The evidence supports investigating the lane-change update and the relationship between `status` and `blocked`. Check the application contract: should the server clear the flag when a card leaves Blocked, should the client send another field, or can the flag be managed independently? The missing field alone does not decide that design question or prove a database defect.

All six requests returned HTTP 200. No `console.log` is included, and the summary reports zero console errors. The creation payload is redacted. Record these limits, then inspect application code and add a [regression assertion](https://fairleadhq.com/docs/recorder/developers/playwright-export/#adapt-the-sample-recording) for the agreed behavior.

## Find the action in the bundle

Locate the action in the numbered **Recorded actions** section of `session.md`. Confirm its label, relative offset, and surrounding sequence. Use `steps.json` or a generated script when you need candidate selectors or converted input values. If the action is outside the [retained interval](https://fairleadhq.com/docs/recorder/developers/capture-support/#recording-retention), ask for the missing context or a focused new recording.

## Follow related traffic

Use the action's relative offset and the session start to locate nearby entries in `network.har`. Check method, URL, status, payload, response, and timing. Confirm the same subject with an identifier or value before treating the request as related.

Follow related console entries and available stack traces. Keep background requests, polling, and unrelated warnings in view: nearby activity can be coincidental.

## Treat associations as leads

Artifact relationships reconstructed from timestamps are leads, not proven causes. The bundle does not preserve the Viewer's inferred-link control or every association detail.

For example, a save action followed by a 500 response supports investigating that request. It does not by itself establish whether the failure originated in validation, a downstream service, or a separate concurrent operation.

## Test the explanation

Use [backend correlation](https://fairleadhq.com/docs/recorder/session-correlation/) where configured, or [reproduce the request](https://fairleadhq.com/docs/recorder/developers/reproduce-a-request/) in an appropriate test environment. Compare the evidence with application code and server logs before naming a cause.

## Leave a useful handoff

Record the failing action, relevant request and error timestamps, confirmed observations, and remaining hypotheses in the issue or investigation record. Cite filenames and HAR entry indexes so another reader can verify the reasoning. Ask the tester for a new `notes.md` or Description when missing context must be preserved in another bundle.

Missing bodies, redacted values, or absent earlier events limit the conclusion. State those gaps rather than treating missing evidence as proof of absence.