Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
0810020
feat(sim): faithful /generate scale simulation (mock sim engine, load…
slin1237 Aug 27, 2026
5d17b9f
feat(sim): turn2 same-vs-random SMG scenario, smoke profile, report f…
slin1237 Aug 27, 2026
086dac8
feat(sim): conns-per-origin loadgen knob and fleet-size-sweep scenario
slin1237 Aug 27, 2026
cb39dca
feat(sim): multi-turn sessions and hit-rate calibration scenario
slin1237 Aug 27, 2026
ed0e1a5
fix(sim): production-validity corrections from benchmark review
slin1237 Aug 27, 2026
5d55070
test(sim): corrected 3-seed results for calibration, TTL, and assignm…
slin1237 Aug 27, 2026
e823316
fix(sim): second-round review corrections (revision, KV pinning, wind…
slin1237 Aug 28, 2026
458ed3a
feat(sim): radix-replica scenario — per-replica tree accuracy under s…
slin1237 Aug 28, 2026
010aaca
docs(sim): round-3 results — revision A/B, calibration, key stability…
slin1237 Aug 28, 2026
cb79109
fix(test): initialize the mock worker's sim fields in gateway integra…
slin1237 Aug 28, 2026
ba9561a
feat(sim): event-driven KV routing legs — gRPC sim workers with Subsc…
slin1237 Aug 28, 2026
6c5786b
docs(sim): kv-events results — worker broadcast repairs sprayed ingress
slin1237 Aug 28, 2026
f427b42
feat(radix-index): generic radix membership index service crate
slin1237 Aug 28, 2026
c942850
test(radix-index): live wire smoke; bridge core into the library
slin1237 Aug 28, 2026
5b6b6b7
feat(gateway): emit the cache-aware selection branch in decision logs
slin1237 Aug 28, 2026
c843813
feat(gateway): remote radix-index seam behind --kv-indexer-url (M1)
slin1237 Aug 28, 2026
3e20f2f
feat(gateway): skip local KV subscriptions when a remote index is con…
slin1237 Aug 28, 2026
f22b312
feat(radix-index): apply-delay staleness injection knobs
slin1237 Aug 28, 2026
bdf51f4
feat(radix-index): publish prompt-plus-output placements; fast-fail q…
slin1237 Aug 29, 2026
9f189b9
refactor(gateway): carry the remote-index client on AppContext
slin1237 Aug 29, 2026
eb6a53b
feat(radix-index): service hardening — admin plane, graceful shutdown…
slin1237 Aug 29, 2026
ec8de8c
docs(radix-index): crate README — the kv_index import is under evalua…
slin1237 Aug 29, 2026
a84c635
chore(radix-index): drop dead apply_delay helper superseded by the dr…
slin1237 Aug 29, 2026
0beaa02
docs(radix-tree): spec for the ground-up generic prefix index (R0)
slin1237 Sep 1, 2026
b2ea503
feat(radix-index): own the wire hash scheme — wire_hash module, golde…
slin1237 Sep 1, 2026
1e4f5f1
test(radix-tree): model-referee differential harness (R0)
slin1237 Sep 1, 2026
be4fd90
test(radix-tree): pinned performance workload, oracle baseline (R0 co…
slin1237 Sep 1, 2026
8d4a0a9
feat(radix-tree): R1 flat core — referee-equal, oracle-beating writes…
slin1237 Sep 1, 2026
2083d94
test(radix-tree): scale axis for the pinned bench; TokenTree/StringTr…
slin1237 Sep 1, 2026
a8ef003
test(radix-tree): verification campaign — invariant auditor, chaos fu…
slin1237 Sep 1, 2026
36dbcbf
feat(radix-tree): interned holder sets, u64 generations, &self reads;…
slin1237 Sep 1, 2026
7d987af
fix(radix-tree): review wave two — non-destructive refused moves, tot…
slin1237 Sep 1, 2026
e0850ea
docs(radix-tree): verification campaign scoreboard update
slin1237 Sep 1, 2026
0a82bfd
docs(radix-tree): R3 chain-native layout design note
slin1237 Sep 1, 2026
0005ef1
feat(radix-tree): R3 chain-native core — referee-equal on first diffe…
slin1237 Sep 1, 2026
7fb9a8a
fix(radix-tree): R3 immune to fingerprint collisions — content-verifi…
slin1237 Sep 1, 2026
caf68a6
test(radix-tree): P4 — mixed-phase query sampling and leak-hunting so…
slin1237 Sep 1, 2026
73c3411
docs(radix-tree): scoreboard cleanup and queue states
slin1237 Sep 1, 2026
357c640
docs(radix-tree): C1 met — 10,000-seed fuzz, zero divergences
slin1237 Sep 1, 2026
1d48ffc
docs+test(radix-tree): R3 passes every original gate; alloc gate cove…
slin1237 Sep 1, 2026
71324f1
feat(radix-tree): chain-native core becomes the primary RadixTree; th…
slin1237 Sep 1, 2026
b2515a8
fix(radix-index): relay only state-changing applies — kills symmetric…
slin1237 Sep 1, 2026
b601194
docs(radix-tree): F5/F7 met; F6 found and fixed the relay echo; P4 so…
slin1237 Sep 1, 2026
609fb50
docs(radix-tree): campaign complete — every locally-provable criterio…
slin1237 Sep 1, 2026
419ef0a
feat(radix-index): R2 — the service engine runs on the verified radix…
slin1237 Sep 1, 2026
c43700a
fix(radix-index): capacity is runaway protection, not an eviction mir…
slin1237 Sep 1, 2026
286fc0d
chore(radix): cleanup — public naming, crate README, comment and doc …
slin1237 Sep 1, 2026
94a1ce9
fix(radix-index): audit wave one — relay correctness, bounded ingest,…
slin1237 Sep 2, 2026
5c49989
test(radix-tree): close the audit's harness-validity gaps
slin1237 Sep 2, 2026
28a11c1
feat(radix-index): per-keyspace locking, keyspace GC, live replica-co…
slin1237 Sep 2, 2026
81158b7
feat(radix-index): event-fed holder liveness — lifecycle controls, ep…
slin1237 Sep 2, 2026
5eb4625
test(radix-tree): workload-profile matrix — 4 stream shapes, p50/p90/…
slin1237 Sep 2, 2026
46cfe0e
feat(gateway): feed the remote index from every dispatch + fleet life…
slin1237 Sep 2, 2026
cfd0b25
Merge remote-tracking branch 'origin/main' into feat/radix-index-expe…
slin1237 Sep 2, 2026
991d6f6
chore(radix-index): strip the sim harness and checked-in results from…
slin1237 Sep 2, 2026
a52a639
feat(radix-index): shared-lock duplicate fast path + split placement …
slin1237 Sep 2, 2026
61f1046
test(radix-index): throttled load characterization — G2 met at refere…
slin1237 Sep 2, 2026
7aeefb2
feat(radix-index): digest publish — duplicate placements cost O(1) on…
slin1237 Sep 2, 2026
e9268a8
feat(radix-index): client-side digest publishing (opt-in) + reconnect…
slin1237 Sep 2, 2026
b416637
fix(ci): codespell — unparseable -> unparsable in service flag valida…
slin1237 Sep 2, 2026
e95cf67
chore(radix-tree): move design/campaign docs out of the shipped crate
slin1237 Sep 2, 2026
87f0689
feat(mock-worker): sim engine for KV-cache-aware routing scenarios
slin1237 Sep 2, 2026
b88b9aa
Merge mock-worker-sim: restack the index PR on the mock-worker base
slin1237 Sep 2, 2026
79d36ad
chore(radix-tree): move SPEC.md out of the shipped crate
slin1237 Sep 2, 2026
50f14c8
perf(radix-index): batched single-lock event apply — 20k-worker event…
slin1237 Sep 2, 2026
41b2020
perf(radix-index): yield the write lock between apply sub-batches
slin1237 Sep 2, 2026
d05f720
refactor(radix-index): use main's mock-worker engine; drop the redund…
slin1237 Sep 2, 2026
f0585dc
refactor(radix-index): remove orphaned mock_worker/sim.rs
slin1237 Sep 2, 2026
ef6450d
test(gateway): drop old mock-worker sim fields from grpc/zmq integrat…
slin1237 Sep 2, 2026
b9ec522
Merge main: MiniMax-M3 vision protocol fields (#2371), Kimi-K3 tool s…
slin1237 Sep 2, 2026
a228b4f
refactor(gateway): own remote-index routing in the policy registry
slin1237 Sep 2, 2026
a559a2c
feat(gateway): extend remote-index routing to gRPC PD/EPD
slin1237 Sep 2, 2026
2e84db8
feat(gateway): adopt remote-index routing in the HTTP regular path
slin1237 Sep 2, 2026
687a441
feat(gateway): string-mode (Bytes keyspace) routing for tokenless HTTP
slin1237 Sep 2, 2026
90f13a9
test(radix-index): cover the engine fault-tolerance perimeter
slin1237 Sep 2, 2026
9295a7c
fix(radix-index): evict timed-out client queries; cover fault paths
slin1237 Sep 2, 2026
6185b95
test(radix-index): cover bridge epochs, digests, and lifecycle relay
slin1237 Sep 2, 2026
833ba14
fix(radix-index): reconstruct chunked snapshots without seq-dedup
slin1237 Sep 2, 2026
3ad8e00
fix(radix-tree): interner orphan + dead overlap fast-path; harden audit
slin1237 Sep 2, 2026
afb1dc7
test(index): guard-path coverage for empty/degenerate inputs
slin1237 Sep 2, 2026
885c4bb
fix(radix-index): address review — epoch acks, digest safety, relay echo
slin1237 Sep 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["model_gateway", "crates/protocols", "crates/reasoning_parser", "crates/tool_parser", "crates/workflow", "crates/tokenizer", "crates/auth", "crates/mcp", "crates/kv_index", "crates/data_connector", "crates/multimodal", "crates/mm_rdma", "crates/wasm", "crates/mesh", "crates/grpc_client", "crates/engine_zmq_client", "bindings/python", "bindings/golang", "clients/rust", "clients/openapi-gen", "crates/mock_worker"]
members = ["model_gateway", "crates/protocols", "crates/reasoning_parser", "crates/tool_parser", "crates/workflow", "crates/tokenizer", "crates/auth", "crates/mcp", "crates/kv_index", "crates/data_connector", "crates/multimodal", "crates/mm_rdma", "crates/wasm", "crates/mesh", "crates/grpc_client", "crates/engine_zmq_client", "bindings/python", "bindings/golang", "clients/rust", "clients/openapi-gen", "crates/mock_worker", "crates/radix_index", "crates/radix_tree"]
resolver = "2"

[workspace.dependencies]
Expand Down
79 changes: 79 additions & 0 deletions crates/kv_index/src/event_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
/// Seed for XXH3 hashing.
pub const XXH3_SEED: u64 = 1337;

/// Rolling prefix hash over content hashes: `XXH3(prev || current)`, the
/// same chaining `PositionalIndexer` computes internally. Exported so
/// out-of-process publishers (the radix index service's placement feed)
/// can synthesize byte-identical position chains for identical prefixes.
#[inline]
pub fn chain_prefix_hash(prev: SequenceHash, current: ContentHash) -> SequenceHash {
let mut bytes = [0u8; 16];
bytes[..8].copy_from_slice(&prev.0.to_le_bytes());
bytes[8..].copy_from_slice(&current.0.to_le_bytes());
SequenceHash(xxhash_rust::xxh3::xxh3_64_with_seed(&bytes, XXH3_SEED))
}

/// Shard count for the main index DashMap.
/// Tuned iteratively — higher values reduce per-shard contention under concurrent
/// reads+writes at the cost of more memory for shard locks.
Expand Down Expand Up @@ -187,6 +199,36 @@ pub fn compute_request_content_hashes(tokens: &[u32], block_size: usize) -> Vec<
.collect()
}

/// Content hash of a raw byte block (position-independent), the byte-mode
/// analogue of [`compute_content_hash`]. Same XXH3-64 hasher and seed,
/// fed the bytes directly, so the two symbol kinds live in disjoint
/// content-hash spaces without any shared state.
pub fn compute_byte_content_hash(bytes: &[u8]) -> ContentHash {
use std::hash::Hasher;
let mut hasher = xxhash_rust::xxh3::Xxh3::with_seed(XXH3_SEED);
hasher.write(bytes);
ContentHash(hasher.finish())
}

/// Chunk raw request bytes by `byte_block` and compute a [`ContentHash`]
/// per full block — the string-mode (`SymbolKind::Bytes`) analogue of
/// [`compute_request_content_hashes`], for routing HTTP requests that
/// carry text but no tokens. Partial trailing chunks are discarded (a
/// worker only caches a full block); empty if `byte_block` is 0.
pub fn compute_request_byte_content_hashes(bytes: &[u8], byte_block: usize) -> Vec<ContentHash> {
if byte_block == 0 {
tracing::warn!(
"compute_request_byte_content_hashes called with byte_block=0, returning empty"
);
return Vec::new();
}
bytes
.chunks(byte_block)
.filter(|chunk| chunk.len() == byte_block)
.map(compute_byte_content_hash)
.collect()
}

// ---------------------------------------------------------------------------
// SeqEntry: optimizes for the common case (one seq_hash per position+content)
// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -2844,4 +2886,41 @@ mod tests {
assert_eq!(indexer.current_size(), 0);
assert_eq!(indexer.entry_count(), 0);
}

#[test]
fn byte_content_hashes_are_deterministic_and_prefix_stable() {
// Determinism: same bytes → same chain.
let a = compute_request_byte_content_hashes(b"hello world foo", 4);
let b = compute_request_byte_content_hashes(b"hello world foo", 4);
assert_eq!(a, b);

// Full blocks only: 15 bytes / 4 = 3 full blocks, trailing 3 dropped.
assert_eq!(a.len(), 3);

// Prefix stability: a longer request that shares a byte prefix
// produces the SAME leading block hashes — this is the property
// string-mode affinity relies on.
let longer = compute_request_byte_content_hashes(b"hello world foo BAR BAZ", 4);
assert_eq!(&longer[..3], &a[..]);

// A differing byte in the first block changes that block's hash
// (and only shared-prefix blocks stay equal).
let diverged = compute_request_byte_content_hashes(b"Hello world foo", 4);
assert_ne!(diverged[0], a[0]);
assert_eq!(&diverged[1..], &a[1..]);
}

#[test]
fn byte_content_hashes_empty_on_zero_block() {
assert!(compute_request_byte_content_hashes(b"anything", 0).is_empty());
assert!(compute_request_byte_content_hashes(b"", 4).is_empty());
}

/// The token hasher's block_size==0 guard: return empty rather than
/// panicking on chunks(0). Mirrors the byte-mode guard.
#[test]
fn token_content_hashes_empty_on_zero_block() {
assert!(compute_request_content_hashes(&[1, 2, 3], 0).is_empty());
assert!(compute_request_content_hashes(&[], 4).is_empty());
}
}
7 changes: 4 additions & 3 deletions crates/kv_index/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ mod token_tree;

pub use common::{MatchResult, TenantId};
pub use event_tree::{
compute_content_hash, compute_request_content_hashes, ApplyError, ContentHash, OverlapScores,
PositionalIndexer, PruneStats, SequenceHash, StoredBlock, WorkerBlockMap, WorkerId,
WorkerIdExhausted,
chain_prefix_hash, compute_byte_content_hash, compute_content_hash,
compute_request_byte_content_hashes, compute_request_content_hashes, ApplyError, ContentHash,
OverlapScores, PositionalIndexer, PruneStats, SequenceHash, StoredBlock, WorkerBlockMap,
WorkerId, WorkerIdExhausted, XXH3_SEED,
};
pub use path_hash::{hash_node_path, hash_token_path, GLOBAL_EVICTION_HASH};
// Re-export under names matching old tree.rs API for easier migration
Expand Down
49 changes: 49 additions & 0 deletions crates/radix_index/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
[package]
name = "radix-index"
version = "0.1.0"
edition = "2021"
license = "Apache-2.0"
description = "Generic radix membership index service: block-quantized prefix chains, per-holder overlap scoring, pub in / sub out"

[lib]
name = "radix_index"
path = "src/lib.rs"

[[bin]]
name = "radix-index-service"
path = "src/bin/service.rs"

[[bin]]
name = "radix-index-bridge"
path = "src/bin/bridge.rs"

[[bin]]
name = "radix-index-bench"
path = "src/bin/bench.rs"

[[bin]]
name = "radix-index-loadbench"
path = "src/bin/loadbench.rs"

[dependencies]
radix-tree = { path = "../radix_tree" }
xxhash-rust = { version = "0.8", features = ["xxh3"] }
smg-grpc-client = { path = "../grpc_client" }
tonic.workspace = true
tonic-prost.workspace = true
prost.workspace = true
tokio = { workspace = true, features = ["full"] }
tokio-stream = "0.1"
futures.workspace = true
tracing.workspace = true
tracing-subscriber = { workspace = true }
rustc-hash = "2"

[dev-dependencies]
kv-index = { path = "../kv_index" }
rand = { workspace = true }
mock-worker = { path = "../mock_worker" }
portpicker = "0.1"

[build-dependencies]
tonic-prost-build = "0.14.6"
96 changes: 96 additions & 0 deletions crates/radix_index/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# radix-index

A shared radix membership index for cache-aware routing: gateways ask
"which worker already holds the longest prefix of this request?" without
each gateway building and syncing its own tree.

The data structure is SMG `kv_index`'s block-quantized positional
index (a direct import — whether the service should instead get a
ground-up generic radix tree is an open evaluation). This crate wraps
it in a keyspace-partitioned engine, a gRPC surface, and the
client/bridge pieces that feed and query it.
Comment on lines +7 to +11

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Nit: This paragraph describes the pre-rewrite state and contradicts the crate's actual dependency — worth fixing in the same doc-hygiene pass as the R3-DESIGN/VERIFICATION reference cleanup.

Cargo.toml:29 has radix-tree = { path = "../radix_tree" } as a real dependency, and kv_index is only a dev-dependency test oracle. So "the data structure is SMG kv_index's block-quantized positional index (a direct import)" is no longer true, and "whether the service should instead get a ground-up generic radix tree is an open evaluation" describes a question this PR answered — the ground-up tree is what ships.

This is a reader's first paragraph on the service crate, and it currently points them at the wrong data structure.

Suggested change
The data structure is SMG `kv_index`'s block-quantized positional
index (a direct import — whether the service should instead get a
ground-up generic radix tree is an open evaluation). This crate wraps
it in a keyspace-partitioned engine, a gRPC surface, and the
client/bridge pieces that feed and query it.
The data structure is [`radix-tree`](../radix_tree) — a ground-up
generic prefix-membership index with zero SMG dependencies, built as
the replacement for `kv_index`'s block-quantized positional indexer
(which remains only as a dev-dependency test oracle). This crate wraps
it in a keyspace-partitioned engine, a gRPC surface, and the
client/bridge pieces that feed and query it.


## Interface: two verbs

- **Publish** (client-streamed `Update`s, acked): a holder's block-hash
chain changed. Two feeds share the verb:
- **Event feed** — a bridge subscribes to engine KV events
(`SubscribeKvEvents`) and forwards Stored/Removed/Cleared batches,
sequenced per holder with epoch bumps on gap or backend loss.
Eviction is *observed*, so index state tracks engine truth.
- **Placement feed** — a gateway publishes "this request's chain now
(probably) resides on that worker" after each completed request
(`seq=0`, content-idempotent). No engine cooperation needed — this
is the path for engines/modes with no KV event stream. Inferred
state is bounded by idle TTL + per-holder capacity with tail-first
(prefix-closed) eviction.
The first sequenced or Removed-bearing update marks a holder
*event-fed*: placements for it are ignored from then on, so the
precise feed always wins.
- **Subscribe** (bidirectional query stream): content-hash chain in,
per-holder matched-block counts out. The gateway enforces its own
deadline (2 ms in SMG) and falls back to its local policy on a miss —
answers are advisory, never load-bearing for correctness.

`Pull` streams the whole state as synthetic `Update`s; a starting
replica bootstraps from a sibling with it before declaring ready.

## Replication: copy, don't agree

No consensus. Writes are per-holder sequenced (event feed) or
content-idempotent (placement feed), so replicas converge by applying
the same updates in any interleaving. A replica relays each accepted
`Publish` to its `--peers` best-effort; a wedged peer drops relayed
updates rather than wedging ingest, and TTL plus re-placement plus
bootstrap bound the divergence. Gateways stay stupid: one endpoint, no
fan-out, reconnect on failure.

## Keyspaces

State is partitioned by `(model, symbol_kind, block_size)`. TOKENS at
the engine page size is what SMG uses today; BYTES exists for text-mode
(HTTP) feeds that hash normalized bytes instead of token ids.

## Binaries

- `radix-index-service` — the server. Flags:

| flag | default | meaning |
|---|---|---|
| `--bind` | `127.0.0.1` | listen address (set `0.0.0.0` in k8s) |
| `--port` | `40000` | gRPC port |
| `--metrics-port` | off | admin plane: `/metrics`, `/healthz`, `/readyz` |
| `--peers` | none | sibling replicas to relay Publishes to (comma-separated URLs) |
| `--bootstrap-from` | none | sibling to Pull state from before serving |
| `--inferred-ttl-secs` | `180` | idle TTL for placement-fed holders |
| `--event-ttl-secs` | `1800` | liveness backstop for EVENT-fed holders: silence past this soft-retires the holder (a lost departure signal must not leak it); `0` disables |
| `--default-capacity-blocks` | unbounded | RUNAWAY PROTECTION for holders that never sent `Added` — the index truncates only past 2x this value. Leave unbounded or set well above worker KV size: the placement feed carries no removal signal, so an index that races the worker's own eviction under-matches (measured); idle TTL is the freshness bound. |
| `--sweep-interval-secs` | `5` | idle-sweep cadence |
| `--apply-delay-stored-ms` / `--apply-delay-removed-ms` | `0` | staleness injection (experiments only) |

Comment on lines +64 to +70

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Nit: The flag table is missing --event-ttl-secs, and the bridge entry omits its flags.

--event-ttl-secs is in KNOWN_FLAGS and parsed in bin/service.rs:113 with a default of 1800. It's also the silence backstop the PR description calls out as bounding the holder leak when the removal signal is lost — arguably the single most operationally important knob here — but an operator reading this table wouldn't know it exists.

Similarly, radix-index-bridge gets a one-line description with no flag table, so its --block-size default (256) is undocumented; that value must match the gateway's --kv-indexer-block-size or queries silently hit an empty keyspace (see the finding on app_context.rs). Worth a row for --workers, --index, --model, --block-size with the defaults spelled out.

Stops gracefully on SIGTERM/ctrl-c. `/readyz` answers 503 until the
bootstrap pull completes — point the k8s readiness probe at it.

- `radix-index-bridge` — per-fleet event bridge: engine KV event
streams in, index Updates out. Flags: `--workers` (comma-separated
worker URLs), `--index` (service URL), `--model`, `--block-size`
(MUST match the gateway's `--kv-indexer-block-size` — the keyspace
key includes it, and a mismatch silently splits the fleet's state
into two keyspaces; both default to the same shared value).
- `radix-index-bench` — apply/query throughput and memory-per-entry
microbench.

A reference StatefulSet lives in [`deploy/statefulset.yaml`](deploy/statefulset.yaml).

## Gateway side (SMG)

`--kv-indexer-url` + `--kv-indexer-block-size` on the gateway enable
the remote path: a routing-time overlap prefetch (2 ms deadline,
fast-fail while disconnected) feeding the cache-aware policy, and a
placement publish of the prompt⊕output chain after each completed
request. Flag off = every code path byte-identical to local behavior.

## Metrics

`/metrics` (Prometheus text): `radix_index_{keyspaces,holders,event_fed_holders,dropped_holders,blocks}`
gauges and `radix_index_{applies,queries,relay_dropped}_total` counters.
9 changes: 9 additions & 0 deletions crates/radix_index/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("cargo:rerun-if-changed=proto/radix_index.proto");
tonic_prost_build::configure()
.build_server(true)
.build_client(true)
.protoc_arg("--experimental_allow_proto3_optional")
.compile_protos(&["proto/radix_index.proto"], &["proto"])?;
Ok(())
}
Loading
Loading