Uh oh!
There was an error while loading. Please reload this page.
fix(read): trace every locator + prove the real chain resolves a Resource (#836, #1590) - #98
fix(read): trace every locator + prove the real chain resolves a Resource (#836, #1590)#98MichaelTaylor3d wants to merge 1 commit into
Conversation
…urce (#836, #1590) The #836 read-leg DATA root was misdiagnosed repeatedly as "the Downloader re-locates by the raw resource id UNBRIDGED -> 0 providers, so no fetchRange is issued." Systematic tracing of the ACTUAL production download-locator chain refutes that: download_locator = SelfExcludingLocator(UnionLocator([ PoolProviderLocator(connected_pool), # offers EVERY connected peer CapsuleFallbackLocator(SelfExcludingLocator( # bridges resource -> capsule UnionLocator([DhtProviderLocator, ...]))), ])) For a ContentId::Resource query BOTH sources resolve the holder: * PoolProviderLocator offers every connected pool peer for ANY content id (resource key included), keyed to the resource, at the reachable pool addr. * CapsuleFallbackLocator bridges the resource key to the announced parent capsule record on the Downloader's OWN locate path (locate_and_confirm), not only on the engine's find_providers probe. The prior read-leg tests used dig-download's MockProviderLocator, which IGNORES the content id and answers EVERY query (resource key included) -- so they silently bypassed the resource->capsule bridge and could never reproduce the real "the resource key resolves nobody; only the capsule key does" condition. This change: 1. Adds DEBUG ground-truth tracing to every locator's find_providers (CapsuleFallback: per-branch + merged counts; SelfExcluding: inner vs kept; Union: per-source + merged counts) so the NEXT arbiter e2e shows exactly which source offered (or failed to offer) the holder for the failing read -- the decisive per-source fact the prior misdiagnoses lacked. 2. Adds two characterization/regression tests that compose the REAL production chain (CapsuleFallback bridge + pool union + self-exclusion) around a capsule-only DHT source and a best_address()-faithful transport, proving a ContentId::Resource resolves + fetches from the connected holder both WITH a reachable pool entry and WITHOUT one (pure capsule-bridge). Both are GREEN at a51980f, refuting the locator-composition hypothesis. No behaviour change (observability + tests only); patch bump. Does NOT close #836 -- see the PR body for the reframed root cause (a discovery-convergence / reachability race, not a locator bug) and the next diagnostic step. Co-Authored-By: Claude <noreply@anthropic.com>
MichaelTaylor3d
commented
Jul 25, 2026
e2e race-diagnostic verdict: RACE REFUTED (retry-after-convergence probe)Ran the decisive retry-after-convergence probe on this branch ( CONNECT / ANNOUNCE / DISCOVER all PASS. Both nodes The verdict-defining result
read #2, with the holder fully converged in the pool, still 404s. The pool was already converged at read #1 too. The race reframe is WRONG. Real root cause — a self-dial / reflexive-candidate bug in the resource-FETCH legThe locator composition works:
Implication for the fixBounded relocate / retry-while-converging will not fix this (the pool is already converged and the holder already located). The fix must correct the peer-fetch dial-candidate handoff ( Evidence: Fleet torn down, zero survivors (verified). No issue closed. |
MichaelTaylor3d
commented
Jul 25, 2026
Closing stale trace-investigation draft per read-leg resume anchor (dig_ecosystem#1586, 2026-07-25T15:26Z). Superseded by the ground-truth runtime key-trace lane: LOCATE-empty root persists on main 77c1422 after PR#100; new lane prints runtime .to_key() at pool_locator offer + download-core lookup and asserts a fetchRange RPC is TRANSMITTED. Branch fix/836-downloader-resource-locate stays on remote as prior art. |
TL;DR — the #836 read-leg hypothesis is REFUTED (misdiagnosis #3), not fixed-blind
The read-leg DATA root has been misdiagnosed 2-3x as a locator-composition bug: "the Downloader re-locates by the raw resource id UNBRIDGED → 0 providers → no fetchRange." I traced the ACTUAL production download-locator chain and proved that is false. This PR ships the instrumentation + the proof; it does NOT close #836 (the true cause is elsewhere — see below). Draft, do not merge as-is.
Traced ground truth (the end of the misdiagnosis)
The production download locator (
NodeContent::new+for_dht) is:For a
ContentId::Resourcequery, BOTH sources resolve the holder:PoolProviderLocator(pool_locator.rs) offers every connected pool peer for ANY content id — resource key included — keyed to the resource, at the peer's reachable pool address. It is NOT capsule-only.CapsuleFallbackLocator(capsule_fallback.rs) bridges the resource key → the announced parent capsule record, and it sits insidedownload_locator(vialocator.clone()), so the bridge is applied on the Downloader's ownlocate_and_confirmpath — not only on the engine'sfind_providersprobe.Confirmed facts from reading the code + dig-download 0.7.1 source:
dig_dht::ContentId::to_key()includes the retrieval_key, sodownload_key(resource) != download_key(capsule). The arbiter log linefetch_resource: ... content=bf77d1d6 located=1(bf77d1d6 = the capsule key) is therefore a fetch for the capsule id (the #1586 backfill), not the resource read's bridged probe — one root of the prior misreads.getAvailability(peer.rs::availability_presence) treats a RESOURCE item as capsule-presence (availableiff the capsule root is held), so a resource confirm succeeds at a holder that holds the capsule.locate_and_confirm(orchestrator.rs:860) calls the injecteddownload_locatorwith the full resource id;run_innererrors immediately (NotFound) if the first confirm is empty — it relocates only on a progress stall, never on an empty first locate.Why the prior tests never caught it
Every prior read-leg test used dig-download's
MockProviderLocator, which ignores the content id and answers every query (resource key included). That bypasses the resource→capsule bridge entirely and models a DHT that announced the resource key — a condition that never exists in production. So the tests were green against the wrong condition.What this PR adds
capsule_fallback.rs,self_excluding_locator.rs,union_locator.rs;pool_locator.rsalready logged): input content id (variant/key) + per-branch/per-source output counts + merged count. The next arbiter e2e will show which source offered (or failed to offer) the holder for the failing read — the decisive per-source fact the prior misdiagnoses lacked.download.rs) composing the REAL chain (CapsuleFallback bridge + pool union + self-exclusion) around a capsule-only DHT source and abest_address()-faithful transport:resource_read_resolves_via_the_real_chain_when_only_the_capsule_is_announced— pool holder @ reachable + DHT capsule @ unreachable → serves via the pool.resource_read_bridges_to_capsule_on_the_download_locate_without_a_pool_entry— empty pool + reachable DHT capsule → serves via the bridge alone.Both are GREEN at a51980f, proving the download locate resolves a Resource whenever a holder is present.
No behaviour change (observability + tests only). Patch bump: workspace
0.58.3 → 0.58.4, dig-node-core0.18.2 → 0.18.3.Reframed root cause + next step (for the orchestrator)
Since the real chain resolves a Resource whenever a reachable holder exists in either source, the e2e DATA 404 means that at the failing read moment neither source had a reachable holder: the gossip pool had not yet converged to include the holder (so no reachable pool address), leaving only the DHT capsule record whose advertised address is unreachable on the relayed net — and dig-download errors immediately on that empty-confirm (no relocate). i.e. a discovery-convergence / reachability race on the first read, not a locator bug. The four prior locator PRs (#95/#96/#97/#1590) could not fix it because the locator was never the fault.
Resume step: re-run
runlegs-read-arbiter.shon cacheda51980f+ this branch. The new tracing will print, at the failing resource read,union_locator: per_source=[<pool>, <capsule-fallback>]andcapsule_fallback: by_resource/by_capsule/merged— confirming whether the pool was empty (race) and whether the DHT capsule branch returned an unreachable-only record. That pins the fix to one of: (a) make the Tier-2 read resilient to the convergence race (bounded relocate/retry while peers are connecting, since dig-download won't relocate on an empty first confirm), or (b) seed the connected pool + DHT routing synchronously before the node begins serving reads. I deliberately did NOT ship a speculative retry — that would be fixing blind against an unconfirmed condition, the exact trap that produced the prior misdiagnoses.Closes none. Refs #836, #1590, #1586, #1572, #1062.