Method details

The full rules behind the records: what each field on a bug page means, how bugs were split into records, how every record was checked, and what is still uncertain. The short version is enough for most readers.

What counts as a bug

A stability bug is a crash, assert, hang, deadlock, data race, undefined behavior, memory or file descriptor leak, or timeout, in libmultiprocess, in Bitcoin Core's IPC code, or in Bitcoin Core code that would not exist without IPC.

Included:

Not included: compiler warnings and static-analysis findings with no runtime effect, documentation, wrong return values with no stability effect, feature work, and bugs in Rust or Python clients outside Bitcoin Core. A static-analysis fix does count when the defect it found could really execute. Borderline cases were recorded with low confidence rather than left out.

One bug per root cause

Each record is one root cause.

Splitting is a judgment. Merging the one pair split from a single commit gives 101 records. Also merging the three pairs that share one report (a killed wallet process seen from both sides, for example) gives 94. Splitting records that merge several sightings gives up to 104.

Classification fields

Each bug page ends with its classification. The values, in plain words:

Status

Scope

Where the defect was, not where it was seen.

Symptom

What the defect can do, which may be worse than anything anyone saw.

Observed effect and where seen

Trigger and phase

The trigger is the event that sets the bug off.

The phase is when in the process's life it happens: startup, steady state, shutdown, or any time. A node dropping its clients at shutdown is trigger local disconnect, phase shutdown.

Side and component

Side says where the defective code runs: the server that implements an interface, the client that calls it, both, the event loop itself, or the code that spawns processes. It is not about who disconnected. Component names the part of the code: in the library, for example the proxy and connection code (proxy-io), the per-call context handling (type-context), the thread map, the event loop, spawning, or mpgen; on the Bitcoin side, init, the IPC glue in src/ipc, the mining interface, RPC or signals; or the upstream Cap'n Proto library, the compiler toolchain, or the test harness.

Root cause kind

Peer

The libmultiprocess C++ client is methodical: it never abandons a request, never disconnects before calling destroy, and shuts down in order. Other clients do all of these.

Where it lived

Fix

Reports

Each independent report is listed with its date, reporter and kind: a CI failure, testing a pull request, real use of a deployed node or client, noticed in passing, code review, Antithesis, fuzzing, a sanitizer run, a new test, or later recognized as the same bug when another report was examined. Repeated CI failures on one thread are one report. Each report is also marked for whether it says a language model helped ("stated"), reads as if one did ("likely"), or neither. The "likely" marks are judgments of writing style.

Dates

How each record was checked

  1. Candidates. Scripts listed every commit, pull request and issue in both repositories that might be a stability fix, plus the multiprocess tracking issue and the maintainer's notes. All data came from local copies; nothing was fetched while writing.
  2. First reader. Each candidate was read with its diff and discussion and either written up as a record or set aside with a reason. Records needing a closer look were flagged by fixed rules: fixes to core teardown code, two or more threads, a disputed mechanism, or a doubtful split.
  3. Added fields. After a first look at the data, each record gained a list of every independent report, what was actually observed, what kind of peer it takes, and a phase. Each record was read again to fill them.
  4. Second reader. Every record was checked again against every fix commit, the pull request body and review comments, and every linked report. Each field was confirmed or corrected, and the reason written down. Questions only the maintainer could answer were sent to him; he settled twelve. The 16 records added in October 2026 were checked against the code and the reports by the agent that wrote them, and have not had a separate second reader yet.
  5. Public text. The bug pages were written from the checked records. Where the code or logs contradict a commit message, pull request or review comment, the page follows the evidence and says so. Those cases are collected on the corrections page.

What the second pass changed, for example:

Two independent readings

The patterns on the findings page come from two interpretations of the finished set. The first was written from the first-pass records. The second was written later from the checked records, without reading the first, and ends with a comparison. They agree on the main results: failures are fail-stop, disconnects are the central trigger, shutdown bugs appear in every period, fixes cause later bugs, detection follows new tools, and the "waves" describe the order of fixes rather than successive classes. They disagreed on details where the data had changed in between: whether the client side was tested before 2026 (it was), the ranking of root causes, and how large the review-driven 2026 group is. The findings follow the current data.

Known limitations

Acknowledgements

Every bug on this site was found, reported, diagnosed or fixed by someone, and each bug page credits the people involved, with links to their reports. Thanks to all of them, including the Stratum v2 developers and operators whose reports from real deployments are the most direct evidence here, the developers who wrote the Rust and Python clients and tests that exercised the code in new ways, and the Antithesis team. Thanks also to an independent red team for the 2026 security reviews, whose reports are published on the audit reports pages with permission.