Skip to content

Change itemsTarget from float to int for query budgeting - #1395

Merged
DZakh merged 10 commits into
claude/multichain-indexer-query-control-kebggnfrom
claude/sourcemgr-reservation-logic-qjfysw
Jul 9, 2026
Merged

Change itemsTarget from float to int for query budgeting#1395
DZakh merged 10 commits into
claude/multichain-indexer-query-control-kebggnfrom
claude/sourcemgr-reservation-logic-qjfysw

Conversation

@DZakh

@DZakh DZakh commented Jul 9, 2026

Copy link
Copy Markdown
Member

Summary

Refactors the query budget system to use integers instead of floats for itemsTarget, improving precision and simplifying budget calculations throughout the fetch state management.

Key Changes

  • Type change: itemsTarget field in query and pendingQuery types changed from float to int
  • Budget calculation: densityItemsTarget function now:
    • Takes density as a parameter instead of deriving it from partition state
    • Returns int instead of float
    • Applies Math.ceil to density-based calculations and enforces a minimum of 1
  • Density extraction: New getTrustedDensity helper function extracts density calculation logic, requiring two responses before trusting the estimate
  • Gap filling: pushGapFillQueries refactored to:
    • Accept partitionBudget parameter for calculating "available density" when no trusted density exists
    • Use trusted density for chunked queries (only when density > 0)
    • Fall back to available density for open-ended probes
  • Water-fill algorithm: Updated to:
    • Calculate probeItemsTarget once per round as an even split of fresh budget
    • Only chunk when trusted positive density exists
    • Apply ceiling and minimum-1 logic to all density-based itemsTarget calculations
  • Budget tracking: All budget accumulation now converts int itemsTarget to float at the point of use
  • SourceManager: Simplified query execution to pass itemsTarget directly without ceiling/validation logic (now handled upstream)
  • Tests: Updated all test fixtures to use integer literals for itemsTarget

Notable Implementation Details

  • Minimum itemsTarget is now 1 (enforced via Pervasives.max(1, ...)) rather than a named constant, ensuring queries never ask the backend for 0 items
  • Density is only trusted after two responses; single-sample estimates are treated as unknown density
  • Chunking only occurs with positive trusted density; zero-density partitions use open-ended probes instead
  • Available density for gap fills is calculated as partitionBudget / remainingRange, spreading the budget proportionally over remaining work

https://claude.ai/code/session_01McpcXkR3pPWfEcq4mCj9Sw

claude added 4 commits July 9, 2026 10:18
…ensity

- Floor itemsTarget at 1 at creation (densityItemsTarget, water-fill chunk
  loop, probe) so a query's budget reservation always equals the
  maxNumLogs-style cap sent to the server; drop SourceManager's 2000-item
  fallback that let density-0 queries return up to 2000 unaccounted items.
- Emit density-priced chunks only for a trusted positive density; density-0
  and unknown-density partitions get a single open-ended probe sized at the
  even split of the tick's fresh budget (maxItemsTarget cap removed). This
  removes the chunkCost=0 path that flooded 10 free hard-bounded chunks per
  partition and froze the 1.8x range growth.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01McpcXkR3pPWfEcq4mCj9Sw
The ceil-to-int conversion now happens once at query creation, so the
reservation, the budget accounting, and the server cap all use the same
integer value; SourceManager passes it through untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01McpcXkR3pPWfEcq4mCj9Sw
Gap queries now use getTrustedDensity: chunks only on a trusted positive
density (same rule as the water-fill); a trusted-zero density prices the
whole gap as one open query, and a partition with no density signal prices
it by available density — its equal-divide budget spread over the remaining
range this tick — so a small gap reserves proportionally little instead of
a noisy one-sample estimate or a NaN from dividing by a zero range.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01McpcXkR3pPWfEcq4mCj9Sw
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bca3d759-fb97-411a-a9e6-708f27589961

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

Chains beyond the most-behind one in the budget waterfall are now capped
at that leader's target progress, mapped onto their own block range
(ChainState.progressAtBlock/blockAtProgress), so no chain runs further
ahead than the chain the shared buffer pool is prioritizing. A chain
visited after the pool is exhausted simply sits out the round — its
reservations release as responses land, so the next tick redistributes.

FetchState's dynamic-contract partition merge now inherits the sum of
its parents' trusted densities (weighted onto the merged partition's
min query range) instead of resetting to 0, so a merge with density
history doesn't regress to an unpriced probe.

Update E2E/rollback tests to the now-serialized cross-chain query
dispatch (most-behind chain queries first; siblings follow once its
response releases budget) and to give density-dependent chunking tests
a nonzero item count to trust.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01McpcXkR3pPWfEcq4mCj9Sw
When a chain's target block is clamped (head, endBlock, or the
cross-chain alignment cap), a known-density chain's fresh budget is now
capped at density x clamped range (in-flight reservations stay on top so
they don't crowd out new partitions). The unused remainder stays in the
waterfall's pool and flows to the next chain in the same tick, instead
of being held by an oversized probe until the response lands.

This also removes the drain loop the infinite-reorg-loop test needed:
the non-reorg chain's post-rollback refetch now reserves only its real
range cost, so the reorg chain gets budget immediately.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01McpcXkR3pPWfEcq4mCj9Sw
A query clamped at the head sized exactly at density x range truncates at
the server cap whenever the range is slightly denser than the estimate,
forcing an immediate catch-up query for the last few blocks. Double the
range cost for head-bound targets so one query usually suffices; the
extra reservation releases as soon as the response lands.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01McpcXkR3pPWfEcq4mCj9Sw
…droom

- targetBlock now clamps at endBlock (when below the head) via a shared
  fetchCeiling helper, so endBlock'd chains stop sizing and aligning
  against range they'll never fetch.
- A chain with no positive density signal caps its fresh budget at 5k,
  so one unknown chain measuring its first responses no longer holds the
  whole cross-chain pool.
- Head/endBlock-bound queries get 3x (was 2x) density headroom against
  truncating at the server cap and needing a catch-up query.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01McpcXkR3pPWfEcq4mCj9Sw
Remove redundant & references in format!/anyhow! arguments flagged by
the CI-pinned clippy (rust 1.97). Pre-existing on the base branch,
unrelated to the SourceManager/waterfall changes in this PR — fixed
here since it was blocking cargo-test from going green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01McpcXkR3pPWfEcq4mCj9Sw
Removing the redundant & in anyhow!'s self.id.to_string() surfaced a
second lint on the same line: ChainId (u64) already implements Display,
so .to_string() inside the format arg is itself redundant.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01McpcXkR3pPWfEcq4mCj9Sw
@DZakh
DZakh merged commit 74ed18f into claude/multichain-indexer-query-control-kebggn Jul 9, 2026
8 checks passed
@DZakh
DZakh deleted the claude/sourcemgr-reservation-logic-qjfysw branch July 9, 2026 14:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants