Case study / Hummingbot

A status result landed on the wrong order.

One fix sent upstream. Other findings the maintainers had already fixed themselves.

Hummingbot is an open-source trading bot framework. In October 2026 arnx reviewed commits from a large gateway change that had merged in August. This page keeps three things apart:

1. Repository and reviewed commit

hummingbot/hummingbot. Upstream pull request #8431 merged on 2026-08-26 with 47 commits. We picked single commits from it to review after the fact:

2. Expected behavior

GatewayBase.update_order_status polls the status of each tracked order's transaction. Each result should be applied to the order whose transaction it describes. An order whose hash lookup failed should be skipped for that round and nothing else.

3. Actual behavior

The method looks up each order's transaction hash, drops the lookups that failed, and asks for the status of the remaining hashes. It then paired those results with the full order list by position:

gateway_base.py, before the fix
for tracked_order, tx_details in zip(tracked_orders, update_results):

Once one order is dropped, every result after it lands on the wrong order. An order with no transaction yet can receive another order's status, and the order that does have a hash gets no status that round.

4. Suspected defect

Before any test ran, the reviewer suspected: The status results are zipped against tracked_orders, but tx_hash_list drops orders whose exchange_order_id raised an exception. The results shift onto the wrong orders. The filter that drops failed lookups predates the reviewed commit. The commit added a new branch that counts not-found results, and that branch inherited the misalignment.

5. Generated test

Written by arnx, as accepted
def test_s4_s5_not_found_applied_to_correct_order(loop):
    c = make_connector(("A", "B"))
    a = c._order_tracker.fetch_tracked_order("A")
    b = c._order_tracker.fetch_tracked_order("B")
    c._set_current_timestamp(T0 + c.TX_NOT_FOUND_DEADLINE + 1)
    hb = "1" * 88

    async def boom():
        raise RuntimeError("no hash")

    a.get_exchange_order_id = boom
    poll(loop, c, [a, b], {hb: -2})
    records = c._order_tracker._order_not_found_records
    assert records["A"] == 0
    assert records["B"] == 1

Order A's hash lookup fails. Order B's transaction is not found. The miss should count against B only.

6. Execution result

From review.md, quoted
### F4 · confirmed by the second opinion
- Failure: `assert 1 == 0`
- Reviewer: tx_hash_list skips orders whose hash lookup fails, but results are paired
  with the unfiltered orders. B's NOT_FOUND was counted against A (A's count was 1,
  not 0), so a healthy order can be declared lost.
- Before the change (new-code): what it tests does not exist on the code before the
  change

arnx found this twice. The first review, on 2026-10-23 with arnx 0.1.1, ran 13 tests in 13 minutes 32 seconds for $0.43. A second review of the same commit on 2026-11-03, with arnx 0.1.7 and arnx Cloud, took 11 minutes 29 seconds and was billed $0.63. The quote above is from the second. These numbers come from our local review records, not from a public page.

The before/after check could not call it a regression. The test uses a constant the commit adds, so there was nothing to compare on the older code. We then reproduced the misalignment by hand on the repository's head at the time.

7. Correction

The fix keeps each order paired with its own hash and zips the results with the orders that were actually queried. Orders whose lookup failed are still skipped for that round, as before. A coding agent wrote the fix from arnx's fix prompt. The test in the pull request is arnx's accepted test, trimmed to the one case. The owner of arnx opened the pull request.

8. Verification result

From the pull request: on the development branch the new test fails with assert 1 == 0; with the fix A has 0 misses and B has 1. The gateway connector and executor tests report 572 passed without the fix and 573 with it. The full suite with the fix, minus three paths that depend on the environment, reported 8,643 passed.

On GitHub on 2026-11-12: open since 2026-10-23, no maintainer review, not merged. Whether the maintainers consider it a bug worth fixing is not yet known.

9. Upstream references

Findings the maintainers had already fixed

The review of 056912818, on 2026-10-23 with arnx 0.1.1, ran 11 tests in 31 minutes 53 seconds for $1.83. It confirmed four issues and left a fifth waiting on a question. We checked each against the repository's later history. All five had been fixed by later commits in the same pull request, in August:

arnx's issues on 056912818 and the upstream commits that had already fixed them
Issue arnx reported Fixed upstream in
A transaction not found for a few seconds was treated as dropped and submitted again 4db6f3a9c, 2026-08-21
Closing a position lost the collected fee and rent figures 8124b61e7, 2026-08-19
The gateway swap command passed an argument that had been removed 2fd25da33, 2026-08-19
A helper method had lost its static-method marker 2fd25da33, 2026-08-19
A timed-out transaction was reconciled as confirmed with an empty position address 508148358, 2026-08-19

The dates settle the question of cause. The fixes are from August 2026. arnx reviewed the commit in October 2026. The developer found and fixed these on their own, most within hours of the reviewed commit. What the comparison shows is narrower: on this commit, the issues arnx confirmed were ones the developer also chose to fix.

Which upstream commit fixed which issue is our reading of the history, recorded in our notes. The commits are public; the mapping is ours.

10. Limitations and observations

Last reviewed 2026-11-12 against arnx 0.1.11. The release documentation is canonical for your installed version.