Found 2026-10-07 while verifying #44 part 3 in production.
What is wrong
The one-off bridge history read (bridgescan::history) bisected qtc.omft.near's supply over #218,346,736 to #218,778,736 and found all 16 supply changes, which is correct (checked independently against the archive). It recorded only 13. Three mints are missing, and they are exactly the three pre-node Quantus deposits that show no link:
NEAR supply change
amount
mint tx (height, shard)
Quantus tx
#218,676,261
+0.996
2MxiR9ew… #218,676,259, shard 8
0xee8f1f47…
#218,755,277
+0.5
Es1A6ca7… #218,755,275, shard 8
0x27b75d95…
#218,770,179
+5,990
4FyNHUrX… #218,770,177, shard 8
0x82cf2a74…
Each is an ordinary bridge-mng.near → omft.near ft_deposit, signed two blocks before the supply change, inside LOOKBACK = 4. So nothing about the matching rule is wrong. Every drop was a read failure that was not treated as one:
if let Ok(Some(chunk)) = archive.chunk(..) turns an error into "this chunk has no mint". For the 0.5 QTC change this produced the only log line: mints around a supply rise do not sum to it; not linked … found 0.
let Ok((_, at)) = archive.block_at(..) else { continue } drops a mint that was found, and logs nothing. That is the 0.996 and 5,990 QTC cases.
The withdrawal branch has the same shape, through chunk, tx_outcomes and block_at.
The cursor is then saved anyway, so the job considers its history read and never looks again.
The FastNEAR archive is currently answering most chunk and block calls with 429 (reproduced today, from a workstation and not only from bob). So this is the normal case, not bad luck.
The opposite failure is there too: supply_at retries an error forever, with no limit and only a debug log line. If the archive refused a height permanently, the history read would hang silently, which is the "waiting for a query that cannot resolve" this issue grew out of.
Also
/bridge/deposits lists every Balances::Transfer into a deposit address, which includes the fee payer's ~0.001 QTC gas top-up before each sweep. That reports 650 deposits, 307 linked, when the real figure is about 313, 308 linked. The hash job also fetches block bodies for those top-ups for nothing.
Fix
A read error in the history read is a failure to resolve that change, never an empty answer. Archive reads retry with a bounded backoff and log at warn when they give up.
A change is in one of three states: resolved; mismatched (every read succeeded and the mints still do not sum to the change, which is terminal, logged and left unlinked); or unread (retried in later passes). The cursor is saved only when nothing is left unread.
supply_at is bounded and returns an error. A failed bisection is logged and retried as a whole after a delay.
A migration clears the history cursor so the read runs again. Inserts are on conflict do nothing, so re-reading is safe.
Exclude the fee payer's transfers from /bridge/deposits and from the hash job.
Found 2026-10-07 while verifying #44 part 3 in production.
## What is wrong
The one-off bridge history read (`bridgescan::history`) bisected `qtc.omft.near`'s supply over #218,346,736 to #218,778,736 and found all **16** supply changes, which is correct (checked independently against the archive). It recorded only 13. Three mints are missing, and they are exactly the three pre-node Quantus deposits that show no link:
| NEAR supply change | amount | mint tx (height, shard) | Quantus tx |
|---|---|---|---|
| #218,676,261 | +0.996 | `2MxiR9ew…` #218,676,259, shard 8 | `0xee8f1f47…` |
| #218,755,277 | +0.5 | `Es1A6ca7…` #218,755,275, shard 8 | `0x27b75d95…` |
| #218,770,179 | **+5,990** | `4FyNHUrX…` #218,770,177, shard 8 | `0x82cf2a74…` |
Each is an ordinary `bridge-mng.near → omft.near ft_deposit`, signed two blocks before the supply change, inside `LOOKBACK = 4`. So nothing about the matching rule is wrong. Every drop was a **read failure that was not treated as one**:
- `if let Ok(Some(chunk)) = archive.chunk(..)` turns an error into "this chunk has no mint". For the 0.5 QTC change this produced the only log line: `mints around a supply rise do not sum to it; not linked … found 0`.
- `let Ok((_, at)) = archive.block_at(..) else { continue }` drops a mint that *was* found, and logs nothing. That is the 0.996 and 5,990 QTC cases.
- The withdrawal branch has the same shape, through `chunk`, `tx_outcomes` and `block_at`.
The cursor is then saved anyway, so the job considers its history read and **never looks again**.
The FastNEAR archive is currently answering most `chunk` and `block` calls with 429 (reproduced today, from a workstation and not only from bob). So this is the normal case, not bad luck.
The opposite failure is there too: `supply_at` retries an error forever, with no limit and only a debug log line. If the archive refused a height permanently, the history read would hang silently, which is the "waiting for a query that cannot resolve" this issue grew out of.
## Also
`/bridge/deposits` lists every `Balances::Transfer` into a deposit address, which includes the fee payer's ~0.001 QTC gas top-up before each sweep. That reports 650 deposits, 307 linked, when the real figure is about 313, 308 linked. The hash job also fetches block bodies for those top-ups for nothing.
## Fix
- A read error in the history read is a **failure to resolve that change**, never an empty answer. Archive reads retry with a bounded backoff and log at `warn` when they give up.
- A change is in one of three states: resolved; mismatched (every read succeeded and the mints still do not sum to the change, which is terminal, logged and left unlinked); or unread (retried in later passes). The cursor is saved only when nothing is left unread.
- `supply_at` is bounded and returns an error. A failed bisection is logged and retried as a whole after a delay.
- A migration clears the history cursor so the read runs again. Inserts are `on conflict do nothing`, so re-reading is safe.
- Exclude the fee payer's transfers from `/bridge/deposits` and from the hash job.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Found 2026-10-07 while verifying #44 part 3 in production.
What is wrong
The one-off bridge history read (
bridgescan::history) bisectedqtc.omft.near's supply over #218,346,736 to #218,778,736 and found all 16 supply changes, which is correct (checked independently against the archive). It recorded only 13. Three mints are missing, and they are exactly the three pre-node Quantus deposits that show no link:2MxiR9ew…#218,676,259, shard 80xee8f1f47…Es1A6ca7…#218,755,275, shard 80x27b75d95…4FyNHUrX…#218,770,177, shard 80x82cf2a74…Each is an ordinary
bridge-mng.near → omft.near ft_deposit, signed two blocks before the supply change, insideLOOKBACK = 4. So nothing about the matching rule is wrong. Every drop was a read failure that was not treated as one:if let Ok(Some(chunk)) = archive.chunk(..)turns an error into "this chunk has no mint". For the 0.5 QTC change this produced the only log line:mints around a supply rise do not sum to it; not linked … found 0.let Ok((_, at)) = archive.block_at(..) else { continue }drops a mint that was found, and logs nothing. That is the 0.996 and 5,990 QTC cases.chunk,tx_outcomesandblock_at.The cursor is then saved anyway, so the job considers its history read and never looks again.
The FastNEAR archive is currently answering most
chunkandblockcalls with 429 (reproduced today, from a workstation and not only from bob). So this is the normal case, not bad luck.The opposite failure is there too:
supply_atretries an error forever, with no limit and only a debug log line. If the archive refused a height permanently, the history read would hang silently, which is the "waiting for a query that cannot resolve" this issue grew out of.Also
/bridge/depositslists everyBalances::Transferinto a deposit address, which includes the fee payer's ~0.001 QTC gas top-up before each sweep. That reports 650 deposits, 307 linked, when the real figure is about 313, 308 linked. The hash job also fetches block bodies for those top-ups for nothing.Fix
warnwhen they give up.supply_atis bounded and returns an error. A failed bisection is logged and retried as a whole after a delay.on conflict do nothing, so re-reading is safe./bridge/depositsand from the hash job.