Skip to content

feat(router): approx indexer support per-insert pruning TTLs - #12793

Open
michaelfeil wants to merge 7 commits into
ai-dynamo:mainfrom
michaelfeil:agent/per-insert-prune-deadlines
Open

michaelfeil wants to merge 7 commits into
ai-dynamo:mainfrom
michaelfeil:agent/per-insert-prune-deadlines

Conversation

@michaelfeil

@michaelfeil michaelfeil commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • accept an optional per-routing-decision pruning TTL, falling back to the configured TTL
  • use the same enqueue-and-register ordering for configured and overridden TTLs
  • keep the later expiry when observations overlap and continue using the existing bucketed scheduler
  • cover the single, flat, flat-binary, concurrent, and concurrent-compressed approximate indexers

Closes #12785

Validation

  • cargo fmt --all
  • cargo clippy -p dynamo-kv-router --all-targets -- -D warnings
  • cargo test -p dynamo-kv-router --lib ttl_override -- --nocapture (6 passed)
  • cargo test -p dynamo-kv-router --lib (836 passed, 2 ignored)

Summary by CodeRabbit

  • New Features

    • Added optional per-request retention periods for routing decisions.
    • Routing matches can now expire sooner or remain available longer than the configured default.
    • Retention settings are applied consistently across local, concurrent, remote, and side-overlay processing.
  • Bug Fixes

    • Prevented reinsertion from shortening an existing entry’s expiration time.
  • Tests

    • Added coverage for custom expiration periods, legacy request compatibility, and retention timing.

Signed-off-by: Michael Feil <63565275+michaelfeil@users.noreply.github.com>
@copy-pr-bot

copy-pr-bot Bot commented Aug 7, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@michaelfeil
michaelfeil temporarily deployed to external_collaborator August 7, 2026 00:19 — with GitHub Actions Inactive
@michaelfeil
michaelfeil temporarily deployed to external_collaborator August 7, 2026 00:19 — with GitHub Actions Inactive
@github-actions github-actions Bot added feat external-contribution Pull request is from an external contributor trusted-contributor Org-External user who is trusted to run CI without Org-member approval labels Aug 7, 2026
@dynamo-ops

Copy link
Copy Markdown
Contributor

/ok to test df9de92

@github-actions github-actions Bot added the router Relates to routing, KV-aware routing, etc. label Aug 7, 2026
@michaelfeil michaelfeil changed the title feat(router): support per-insert pruning TTLs feat(router): approx indexer support per-insert pruning TTLs Aug 7, 2026
@michaelfeil
michaelfeil temporarily deployed to external_collaborator August 7, 2026 00:38 — with GitHub Actions Inactive
@dynamo-ops

Copy link
Copy Markdown
Contributor

/ok to test c351350

@michaelfeil
michaelfeil temporarily deployed to external_collaborator August 7, 2026 00:43 — with GitHub Actions Inactive
@dynamo-ops

Copy link
Copy Markdown
Contributor

/ok to test 18c05c5

@datadog-official

This comment has been minimized.

@michaelfeil

Copy link
Copy Markdown
Contributor Author

@codex review

@michaelfeil
michaelfeil temporarily deployed to external_collaborator August 7, 2026 04:03 — with GitHub Actions Inactive
@michaelfeil
michaelfeil marked this pull request as ready for review August 7, 2026 04:03
@michaelfeil
michaelfeil requested review from a team as code owners August 7, 2026 04:03
@dynamo-ops

Copy link
Copy Markdown
Contributor

/ok to test 332a213

@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 14b3b56e-b068-4536-8fd3-777949b4be9f

📥 Commits

Reviewing files that changed from the base of the PR and between 027e7ad and 2e93c8d.

📒 Files selected for processing (14)
  • lib/bench/tests/mooncake_trace.rs
  • lib/kv-router/src/indexer/branch_sharded.rs
  • lib/kv-router/src/indexer/kv_indexer.rs
  • lib/kv-router/src/indexer/local.rs
  • lib/kv-router/src/indexer/pruning.rs
  • lib/kv-router/src/indexer/tests.rs
  • lib/kv-router/src/indexer/thread_pool.rs
  • lib/kv-router/src/indexer/traits.rs
  • lib/kv-router/src/indexer/types.rs
  • lib/llm/src/kv_router.rs
  • lib/llm/src/kv_router/indexer/mod.rs
  • lib/llm/src/kv_router/indexer/recording.rs
  • lib/llm/src/kv_router/indexer/remote.rs
  • lib/llm/src/kv_router/indexer/side.rs
🚧 Files skipped from review as they are similar to previous changes (9)
  • lib/llm/src/kv_router/indexer/side.rs
  • lib/kv-router/src/indexer/traits.rs
  • lib/llm/src/kv_router.rs
  • lib/kv-router/src/indexer/kv_indexer.rs
  • lib/bench/tests/mooncake_trace.rs
  • lib/kv-router/src/indexer/local.rs
  • lib/kv-router/src/indexer/branch_sharded.rs
  • lib/kv-router/src/indexer/pruning.rs
  • lib/llm/src/kv_router/indexer/mod.rs

Walkthrough

Changes

The routing indexer now accepts optional per-request TTL overrides. The override flows through request processing, recording, worker insertion, and pruning. Existing expiry behavior remains the default, while later expiries are preserved during reinsertion.

Routing TTL override

Layer / File(s) Summary
TTL contract and expiry semantics
lib/kv-router/src/indexer/types.rs, lib/kv-router/src/indexer/traits.rs, lib/kv-router/src/indexer/pruning.rs
Routing requests and pruning APIs accept optional TTL overrides. Existing later expiries are retained. Tests cover default, shorter, and later TTLs.
Indexer API propagation
lib/kv-router/src/indexer/kv_indexer.rs, lib/kv-router/src/indexer/branch_sharded.rs, lib/kv-router/src/indexer/local.rs, lib/kv-router/src/indexer/thread_pool.rs
Indexer interfaces and routing methods forward the override to hash processing and worker insertion.
Recording path propagation
lib/llm/src/kv_router/indexer/recording.rs, lib/llm/src/kv_router/indexer/remote.rs, lib/llm/src/kv_router/indexer/side.rs
Primary, remote, and side-overlay recording paths forward the override.
Call-site compatibility and routing tests
lib/kv-router/src/indexer/tests.rs, lib/bench/tests/mooncake_trace.rs, lib/llm/src/kv_router.rs, lib/llm/src/kv_router/indexer/mod.rs
Existing callers pass None. Tests cover short per-request expiry, serialization compatibility, and existing routing behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: per-insert pruning TTL support for the approximate router indexer.
Description check ✅ Passed The description covers the changes, validation, and required linked issue; it omits only some optional template sections.
Linked Issues check ✅ Passed The implementation propagates optional TTLs, preserves later deadlines, retains default behavior, and adds variant coverage for issue [#12785].
Out of Scope Changes check ✅ Passed The changed files support TTL propagation, pruning behavior, compatibility, or tests required by issue [#12785].
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/kv-router/src/indexer/tests.rs`:
- Around line 1099-1103: Flush and settle the indexer after
process_routing_decision_for_request and before the first assert_request_score
call in the single-variant test. Reuse the existing
route_approx_tokens/flush_and_settle behavior or invoke the established flush
helper directly so the queued routing event is applied before assertions.

In `@lib/kv-router/src/indexer/thread_pool.rs`:
- Around line 810-822: The EventWithAck acknowledgement is only being awaited,
so failed event application can leave pruning registrations active. In
lib/kv-router/src/indexer/thread_pool.rs lines 810-822, inspect the
acknowledgement boolean and fail or roll back when it is false; in
lib/kv-router/src/indexer/pruning.rs lines 381-408, ensure
enqueue_and_insert_worker_block_entries delays timer registration until
successful application or restores every prior expiry during rollback.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: abd3e512-e445-46e3-9f69-ba4db6aeabf3

📥 Commits

Reviewing files that changed from the base of the PR and between 027e7ad and 332a213.

📒 Files selected for processing (14)
  • lib/bench/tests/mooncake_trace.rs
  • lib/kv-router/src/indexer/branch_sharded.rs
  • lib/kv-router/src/indexer/kv_indexer.rs
  • lib/kv-router/src/indexer/local.rs
  • lib/kv-router/src/indexer/pruning.rs
  • lib/kv-router/src/indexer/tests.rs
  • lib/kv-router/src/indexer/thread_pool.rs
  • lib/kv-router/src/indexer/traits.rs
  • lib/kv-router/src/indexer/types.rs
  • lib/llm/src/kv_router.rs
  • lib/llm/src/kv_router/indexer/mod.rs
  • lib/llm/src/kv_router/indexer/recording.rs
  • lib/llm/src/kv_router/indexer/remote.rs
  • lib/llm/src/kv_router/indexer/side.rs

Comment thread lib/kv-router/src/indexer/tests.rs Resolved

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

Open in Devin Review

Comment thread lib/kv-router/src/indexer/tests.rs Resolved

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 332a21305c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/kv-router/src/indexer/pruning.rs Resolved
@michaelfeil
michaelfeil temporarily deployed to external_collaborator August 7, 2026 04:29 — with GitHub Actions Inactive
@dynamo-ops

Copy link
Copy Markdown
Contributor

/ok to test 4c53db4

@michaelfeil

Copy link
Copy Markdown
Contributor Author

@codex review

Signed-off-by: Michael Feil <63565275+michaelfeil@users.noreply.github.com>
Signed-off-by: Michael Feil <63565275+michaelfeil@users.noreply.github.com>
Signed-off-by: Michael Feil <63565275+michaelfeil@users.noreply.github.com>
Signed-off-by: Michael Feil <63565275+michaelfeil@users.noreply.github.com>
@michaelfeil
michaelfeil force-pushed the agent/per-insert-prune-deadlines branch from 4c53db4 to 3b29e65 Compare August 7, 2026 04:33
@michaelfeil
michaelfeil temporarily deployed to external_collaborator August 7, 2026 04:34 — with GitHub Actions Inactive
@dynamo-ops

Copy link
Copy Markdown
Contributor

/ok to test 3b29e65

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4c53db4571

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Signed-off-by: Michael Feil <63565275+michaelfeil@users.noreply.github.com>
@michaelfeil
michaelfeil temporarily deployed to external_collaborator August 7, 2026 04:46 — with GitHub Actions Inactive
@dynamo-ops

Copy link
Copy Markdown
Contributor

/ok to test 2e93c8d

@michaelfeil

Copy link
Copy Markdown
Contributor Author

@CodeRabbit review

@michaelfeil

Copy link
Copy Markdown
Contributor Author

@codex review

@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: 2e93c8d1ed

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Signed-off-by: Michael Feil <63565275+michaelfeil@users.noreply.github.com>
@michaelfeil
michaelfeil temporarily deployed to external_collaborator August 7, 2026 05:09 — with GitHub Actions Inactive
@dynamo-ops

Copy link
Copy Markdown
Contributor

/ok to test e86da26

@michaelfeil

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

Reviewed commit: e86da2675e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@PeaBrane PeaBrane left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI-generated neutral review; human evaluation is requested. This is neither an approval nor a request-changes verdict.

For bounded, trusted TTLs, the existing FxHashMap/BTreeMap plus per-worker-minimum heap design appears compatible with heterogeneous expiries: this PR does not introduce per-block timer tasks or a fundamentally heavier scheduling container. The main concerns are where expiry authority and identity are lost across boundaries.

A possible architectural direction is to treat expiry as validated, versioned state: expose a bounded receiver-owned retention policy on the wire; compute an absolute internal deadline at admission so queue/transport time counts; carry a generation with heap entries and pending removals so stale work is conditional; and publish heap rebuilds with an epoch check or reconciliation. That should preserve the bucketed scheduler and hot read path while addressing the inline policy, race, and coverage gaps.

for key in keys {
match self.timers.entry(key.clone()) {
Entry::Occupied(entry) if *entry.get() == expiry_time => {
Entry::Occupied(entry) if *entry.get() >= expiry_time => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI review — human evaluation requested: Please re-evaluate the previously discussed stale-removal race against #12785's acceptance criterion. This max-expiry check only helps while the key remains in the timer map. Once queue_due removes the timer and queues a bare BlockEntry, a refresh can install a later timer, yet the stale queued Removed can still delete the refreshed tree entry, including during the worker-ack window before the later expiry is registered. If this PR intends to close that criterion, pending work likely needs to carry an expiry/generation and apply removal only when it is still current. Scanning the pending queue during insertion would not cover a removal already enqueued downstream.

/// Locally-computed rolling sequence hashes for the routed request.
pub sequence_hashes: Vec<SequenceHash>,
/// Optional pruning TTL for this routing decision.
pub ttl_override: Option<Duration>,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI review — human evaluation requested: Please assess whether a raw, arbitrary Duration is safe on this served-indexer wire boundary. The receiver forwards it into pruning without a cap; a large value can bypass the configured retention bound, increase live entries and expiry buckets, and an extreme representable value can make Instant + ttl panic. A bounded receiver-owned retention class, or receiver-side validation/capping plus checked_add, would keep untrusted policy outside the indexer.

worker,
local_hashes,
sequence_hashes,
ttl_override,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI review — human evaluation requested: This carries a relative TTL through the queue/RPC, but the pruning manager samples Instant::now() only when it later processes the request. Local backpressure, a worker acknowledgement, or remote transport therefore does not consume the requested lifetime; a request with five seconds remaining after ten seconds in transit receives another five seconds. If the intended contract is event-age-bounded retention, consider computing a validated absolute internal deadline at admission and carrying that through private queues rather than restarting a relative duration at each boundary.

new_next >= old_next,
"approximate prune expiry moved earlier during insert"
);
self.inner.push_worker_expiry(worker, new_next);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI review — human evaluation requested: Please verify the interaction with concurrent heap rebuilds. A rebuild snapshots per-worker minima without serializing against this push, then replaces the heap wholesale. An insertion can publish a newly earlier minimum after its worker was snapshotted, only for the rebuild to overwrite and lose that entry; if another worker remains heap-top, stale-top validation does not rediscover the omitted worker until later. Heterogeneous TTLs make new_next < old_next routine. A mutation epoch/retry, serialization, or post-build reconciliation would make publication robust.

let long_expiry = *pm.get_expiry(&2).expect("long expiry missing");
pm.insert_at(vec![2], now, Some(Duration::from_secs(5)));

assert!(short_expiry < long_expiry);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI review — human evaluation requested: This checks the leaf map's computed expiries, but it does not demonstrate that the background scheduler wakes for a newly earlier deadline. The interface-level test later calls flush, which synchronously drains due work and can pass even if the wake-up path is wrong. A deterministic test could insert a long TTL followed by a shorter TTL for another block on the same worker, observe ordered background removal without relying on flush, and repeat descending deadlines past the heap-rebuild threshold.

let encoded = rmp_serde::to_vec_named(&decoded).unwrap();
let round_trip: IndexerRecordRoutingDecisionRequest =
rmp_serde::from_slice(&encoded).unwrap();
assert_eq!(round_trip.ttl_override, decoded.ttl_override);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI review — human evaluation requested: This proves only the MessagePack shape. It does not exercise RouteRecordingTarget → RemoteIndexer → ServedIndexerRecordEngine, where TTL forwarding can be lost even while serialization still round-trips. Please consider a behavioral remote-path test using a long configured default and Some(Duration::ZERO) (or another short override), then assert that observed expiry follows the override.

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

@github-actions github-actions Bot added the Stale label Sep 9, 2026
@awesome-pro

Copy link
Copy Markdown
Contributor

here is my idea for next changes

1. unbounded wire Duration → Instant + ttl panic. . a TTL arriving over the wire is attacker- or bug-controlled, and Instant::now() + ttl panics on overflow.
Minimal hardening: parse the wire duration as Duration, cap it at a configured maximum (reject above the cap with a protocol error rather than clamping silently), and compute the deadline with checked_add, degrading to "no TTL" (or rejecting the insert) on overflow.
that takes to review's third point if the deadline is absolute and derived at the consumer after dequeue, the "relative TTL ignores queue/transport time" complaint disappears.

2. Concurrent heap rebuild losing an earlier minimum. If two rebuilds race, the older minimum can overwrite the newer state and a TTL fires late.
a clean fix is to make the heap's min monotonic across rebuilds (compare-and-set the wake-up deadline: never move a deadline later without a fresh scan) or to serialize rebuilds through the existing shard lock. would take the CAS approach as it keeps rebuilds concurrent and makes the invariant local.


@PeaBrane what do you think of these ideas?
@michaelfeil if you are still driving this happy to implement either as follow-ups on your branch instead. and if not, happy to carry on from my side.

@devin-ai-integration

Copy link
Copy Markdown
Contributor

External-PR triage (head e86da2675e)

Blocker: Merge conflict with main, and no reviewer was requested (now requested: router CODEOWNERS). @awesome-pro's Sep 28 safety/design suggestions are also still open.

Next action (@michaelfeil (author)): Rebase onto main, resolve conflicts, and reply to the open suggestions. Router CODEOWNERS then review.

Automated external-PR triage. This comment is edited in place on each run.

Written by Devin

@devin-ai-integration
devin-ai-integration Bot requested a review from a team October 9, 2026 15:54

This branch was previously deployed

1 inactive deployment
external_collaborator — e86da267 Deployed Aug 7, 2026 by michaelfeil via ok-to-test #7514
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external-contribution Pull request is from an external contributor feat router Relates to routing, KV-aware routing, etc. size/L Stale trusted-contributor Org-External user who is trusted to run CI without Org-member approval

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support per-insert deadlines in approximate-indexer pruning

4 participants