Problem
In src/engine.ts, `run()` uses `Promise.all` for the divergence fan-out and the deepen pass. If a single branch's `callLLM` throws (rate limit, timeout, malformed response the schema can't recover from), the entire run rejects and every other already-completed branch's work is thrown away.
Fix
- Swap `Promise.all` for `Promise.allSettled` in the branch fan-out (`frames.map(...)`) and the deepen pass (`toDeepen.map(...)`).
- Add a `failedFrames: { frameId: string; error: string }[]` field to `RunResult` (types.ts) so callers/CLI can report partial failure instead of a silent gap or a hard crash.
- Emit a `RunEvent` of kind `"frame:failed"` so `cli.ts`'s progress printer can surface it (` ✗ failed: `).
- A run should only hard-fail if zero branches succeed.
Notes
`divergeBranch`, `scoreIdeas`, and `clusterIdeas` already fail open internally on JSON-parse errors (return empty). This issue is specifically about the network/LLM-call layer throwing before it even gets to `parseJSON`.
(Re-filed as part of a backlog reset; previously tracked as #38.)
Problem
In src/engine.ts, `run()` uses `Promise.all` for the divergence fan-out and the deepen pass. If a single branch's `callLLM` throws (rate limit, timeout, malformed response the schema can't recover from), the entire run rejects and every other already-completed branch's work is thrown away.
Fix
Notes
`divergeBranch`, `scoreIdeas`, and `clusterIdeas` already fail open internally on JSON-parse errors (return empty). This issue is specifically about the network/LLM-call layer throwing before it even gets to `parseJSON`.
(Re-filed as part of a backlog reset; previously tracked as #38.)