# How to Debug Failed Branches Using frameId and ideaId Tracking in ADHD

> Debug failed branches in ADHD with frameId and ideaId tracking. Pinpoint exact failure points in your event stream and resolve pipeline collapses efficiently.

- Repository: [Udit Akhouri/adhd](https://github.com/UditAkhourii/adhd)
- Tags: how-to-guide
- Published: 2026-08-19

---

**ADHD emits `frameId` and `ideaId` identifiers through every phase of its divergence-and-deepening engine, allowing you to trace exact failure points in the event stream without guessing which frame or idea caused the pipeline to collapse.**

When the **ADHD** code-generation pipeline drops a branch or returns empty results, guessing which prompt failed wastes engineering time. The repository solves this by propagating stable **`frameId`** and **`ideaId`** values through every divergence, scoring, and deepening step. This guide shows you how to debug failed branches using frameId and ideaId tracking so you can pinpoint malformed LLM outputs and zero-idea frames by reading the event stream and the source files in **[`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts)** and **[`src/render.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/render.ts)**.

## How Identifiers Are Assigned in the Source Code

### Frame Definitions in [`src/frames.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/frames.ts)

Each **frame** carries a stable `id` field that becomes the **`frameId`** for every branch spawned from it. In **[`src/frames.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/frames.ts)** (lines 5‑23), the frame objects are declared with unique identifiers the engine references during the **diverge** phase.

### Branch and Idea Objects in [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts) and [`src/types.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/types.ts)

During the diverge phase, **[`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts)** (lines 352‑364) returns each **branch** as an object containing `{ frameId, ideas }`. Every **idea** inside that branch receives a generated `id` and inherits the parent `frameId`. The type definitions in **[`src/types.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/types.ts)** (lines 3‑22) enforce these fields, ensuring every **`Idea`** and **`Branch`** payload remains traceable.

### Event Emission and CLI Visibility

The engine fires lifecycle events—**`frame:start`**, **`frame:done`**, **`deepen:start`**, and **`deepen:done`**—from [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts) (lines 356‑361) that embed these IDs. On the consumption side, **[`src/render.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/render.ts)** (lines 35‑44) formats branch output for the CLI so IDs remain visible when a branch fails, while **[`src/cli.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/cli.ts)** (lines 124‑126) writes concise status lines to **`process.stderr`** for live debugging.

## Common Failure Points and How IDs Expose Them

### Diverge Phase: Zero-Ideas or Malformed JSON

If the **LLM** call for a frame returns no ideas or unparseable JSON, the `frame:done` event reports **`count = 0`**. The embedded `frameId` tells you exactly which frame’s prompt caused the problem, so you can inspect the raw LLM response for that specific frame.

### Scoring Phase: Missing or Unparseable Idea Fields

When an idea cannot be parsed or is missing required fields, the **`deepen:start`** event still surfaces the `ideaId`. You can locate the offending idea object in the raw LLM response and compare it against the expected shape defined in [`src/types.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/types.ts).

### Deepen Phase: Empty Sub-Ideas

A follow-up LLM call that fails to produce sub-ideas results in a **`deepen:done`** event containing the same `ideaId` but a zero-length **`childIdeas`** array. This signal means the seed idea identified by that `ideaId` could not be expanded, and you should inspect its **`idea.text`** and the prompt sent to the model.

### Rendering Phase: Omitted Branches

If the final report omits a branch, [`src/render.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/render.ts) reveals which `frameId` (and optionally `ideaId`) were dropped. Comparing the rendered output against the earlier event log lets you verify whether the omission happened during generation or formatting.

## Step-by-Step Debugging Workflow

### Enable Verbose Event Logging

The default CLI already prints events, but you should run with the **`--verbose`** flag to ensure every `frame:start` and `deepen:done` line is emitted:

```bash
adhd "my problem" --frames 5 --ideas 6 --verbose

```

### Capture the Event Stream

Pipe **`stderr`** and **`stdout`** to a file so you can grep the sequence later:

```bash
adhd "my problem" … 2>&1 | tee debug.log

```

### Search the Log for Failure Signatures

Look for lines that indicate zero output or deepening failures:

```

frame:done   0 ideas (hardware-eyes)
deepen:start   a1b2c3 :: some promising idea
deepen:done    a1b2c3   (no child ideas)

```

- **`frameId = hardware-eyes`** tells you which frame produced zero ideas.
- **`ideaId = a1b2c3`** tells you which seed idea produced no children.

### Re-Run the Problematic Piece in Isolation

You can call the low-level functions directly from a **Node** REPL or a small script using the stored IDs. Import **`divergeBranch`**, **`deepenIdea`**, and the **`FRAMES`** array to target the exact failure:

```typescript
import { divergeBranch, deepenIdea } from "./src/engine";
import { FRAMES } from "./src/frames";

// Re-run the failed frame:
const frame = FRAMES.find(f => f.id === "hardware-eyes")!;
const branch = await divergeBranch(problem, context, frame, 6, model);
console.log(branch);   // inspect raw LLM output

// Re-run the failing idea:
const idea = branch.ideas.find(i => i.id === "a1b2c3")!;
const deep = await deepenIdea(problem, idea, [], model);
console.log(deep);

```

### Inspect Raw LLM Prompts and Responses

The **`frame.prompt`** defined in [`src/frames.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/frames.ts) and the generated **`idea.text`** give direct clues about why the model returned nothing or malformed JSON. Compare the prompt template against the actual LLM response captured in your log or REPL output.

### Adjust Parameters and Iterate

After identifying the faulty `frameId` or `ideaId`, tweak the prompt, increase **`ideasPerFrame`**, or adjust the **temperature**. Re-run the engine and verify that the event log now shows non-zero counts for all `frameId`s and successful `deepen:done` entries.

## Automating Failure Detection

A post-run script can flag any frame that produced zero ideas or any idea that failed to deepen:

```typescript
import * as fs from "fs";

const log = fs.readFileSync("debug.log", "utf-8").split("\n");
log.forEach(line => {
  if (line.includes("frame:done") && /0 ideas/.test(line)) {
    const id = line.match(/\(([^)]+)\)/)![1];
    console.warn(`⚠️ Frame "${id}" produced no ideas`);
  }
  if (line.includes("deepen:done") && /no child ideas/.test(line)) {
    const id = line.match(/ideaId: (\w+)/)![1];
    console.warn(`⚠️ Idea "${id}" could not be deepened`);
  }
});

```

Running this script after each execution highlights exactly which `frameId` or `ideaId` needs attention before you dive into manual log inspection.

## Summary

- **`frameId`** originates from the stable `id` field in [`src/frames.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/frames.ts) and tags every branch during the diverge phase in [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts).
- **`ideaId`** is generated per idea and inherited from the parent `frameId`, with shapes enforced in [`src/types.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/types.ts).
- The engine emits `frame:start`, `frame:done`, `deepen:start`, and `deepen:done` events that carry these IDs, consumed by [`src/cli.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/cli.ts) and rendered by [`src/render.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/render.ts).
- A `frame:done` event showing `0 ideas` maps directly to a failed `frameId`.
- A `deepen:done` event showing `no child ideas` maps directly to a failed `ideaId`.
- You can replay isolated failures by importing `divergeBranch` and `deepenIdea` from [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts) and targeting the exact IDs.

## Frequently Asked Questions

### Where are `frameId` and `ideaId` defined in the ADHD source code?

The `frameId` values come from the stable `id` fields declared in [`src/frames.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/frames.ts) (lines 5‑23). The `ideaId` values are generated during branch creation in [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts) (lines 352‑364) and enforced by the type definitions in [`src/types.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/types.ts) (lines 3‑22).

### How do I know if a specific frame failed to produce ideas?

Listen for the `frame:done` event in the output stream. If the event reports `0 ideas` and includes a `frameId` such as `hardware-eyes`, that frame’s LLM call returned no parseable ideas. You can then inspect the prompt for that exact `frameId` in [`src/frames.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/frames.ts).

### Can I re-run a single failed branch without executing the entire engine?

Yes. Import `divergeBranch` and `deepenIdea` from [`src/engine.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/engine.ts), look up the specific frame from `FRAMES` in [`src/frames.ts`](https://github.com/UditAkhourii/adhd/blob/main/src/frames.ts), and call the functions with the problematic `frameId` or `ideaId`. This lets you debug the raw LLM response in isolation without rerunning the full pipeline.

### What does a zero-length `childIdeas` array indicate during the deepen phase?

In the `deepen:done` event, a zero-length `childIdeas` array tied to a specific `ideaId` means the follow-up LLM call could not generate sub-ideas for that seed idea. You should inspect the `idea.text` and the deepening prompt to determine why the model returned an empty result.