What’s in each one
Every postmortem follows the same five-part shape:- Symptom — what a user, operator, or downstream system saw when the bug fired. Outside-in, not code-first.
- Root cause — the specific code path and, crucially, why it was wrong. The mental model that led to the mistake, not just the line that got flipped.
- Fix — what changed, with links to the commits.
- Why the tests didn’t catch it — an honest paragraph. The single most useful section in the whole file.
- Class of bug — where else to watch — the pattern generalized, with specific other code paths that might hide the same shape. This is what turns a log entry into a tool.
Bindu Core (5)
DID signature fails open
The middleware noted “can’t verify” and let the request through anyway. Textbook fail-open.
IDOR on tasks and contexts
Any authenticated caller could read, cancel, or clear another caller’s tasks. Row-level auth was just… missing.
Pydantic populate_by_name mismatch
Types accepted camelCase over the wire but rejected snake_case internally. Quiet contract drift.
DID document endpoint returned raw dict
The resolver returned the wrong shape — crashed clients expecting a proper DID document.
DID signature overbroad exceptions
A bare
except Exception turned real bugs into silent false-negatives.Gateway (6)
Compaction concurrent races
Two parallel compactions could tangle a session’s history. An in-process promise cache now dedupes them.
Compaction lossy second pass
Re-compacting a summary dropped content. The second pass assumed the input was raw, not already-compacted.
Compaction mid-turn cut
Compaction could slice between a
tool_use and its tool_result, breaking the LLM’s view of the conversation.SpawnReader fiber leak
A long-running fiber stayed alive after the request completed. Memory crept up over time.
SSE cross-contamination
Two sessions could see each other’s SSE events through a shared pubsub filter.
Timing-unsafe token compare
A plain
== on secret tokens opened a small timing side-channel. Fixed with a constant-time compare.SDKs and Frontend
Nothing yet. When the TypeScript SDK’s review pass lands and ships fixes worth remembering, they’ll appear underpostmortems/sdk/. Same for the frontend.
Why this archive exists
A few beliefs that led here:- Commit messages carry the tactical detail of a fix. They’re good at “what changed.” They’re bad at “what was the thinking that let this slip through.”
- GitHub Issues are the source of truth for status — open, closed, owned, milestoned. They’re bad at “what did we actually learn.”
- This archive is the source of truth for lessons. Every file names the pattern, every file lists other places the same shape could hide. A pattern named once prevents the next occurrence.