constitution · epochs · watch · epoch 3

comparison

c_4772ee88dbe3 (tommy-mor) vs c_2dc96aace098 (tommy-mor)

download prompt · raw event · cmp_42fa10bb28f1b1

council reasoning

~anthropic/claude-sonnet-latest · winner B · 8:2 · permalink

Side B delivers a substantive architectural change (offloading Reddit JSON payloads to a RocksDB-backed entity store, streaming event log replay to cut startup RAM) with tests validating persistence and replay correctness, despite noisy vendored Cargo.lock churn. Side A mostly removes a demo feature and adds a settlement worker/cache that duplicates ranking logic without clear necessity, offering less lasting architectural value relative to its complexity.

~x-ai/grok-latest · winner A · 2:1 · permalink

Side A delivers lasting core design: a settlement worker that batches vote appends + ranking recompute off the request path, plus a ranked_items_cached fast path that lets ranking_panel/home use read locks instead of write locks, while cleanly excising the demo-counter scaffolding. Side B’s entity offload and streaming replay are real scalability wins, but most of the patch is a large newly-vendored durable crate (docs, examples, proptests, lockfile noise) whose full surface is only lightly used by EntityStore.

openai/gpt-chat-latest · winner A · 3:2 · permalink

Side A introduces substantive architectural improvements to the running server: it adds a settlement worker that batches vote persistence and ranking recomputation, introduces cached ranking reads (`ranked_items_cached`) so HTTP handlers can use read locks instead of write locks, and removes an obsolete demo counter feature. Side B adds a large new `durable` workspace crate and streams event-log replay while moving raw entity payloads into RocksDB, but much of the patch is dependency, documentation, examples, and vendored infrastructure, making the immediately integrated project impact less concentrated than A's core runtime and concurrency improvements.

sides

A — c_4772ee88dbe3 (tommy-mor)

message

[07715165] nice

diff preview

diff --git a/server/src/api/ui_html.rs b/server/src/api/ui_html.rs
index c3c62a76f424010d77a6090c84dd0b82098f573e..da2536112faea313352624cf2ce0ddd0ab3377c1 100644
--- a/server/src/api/ui_html.rs
+++ b/server/src/api/ui_html.rs
@@ -6,7 +6,7 @@ use axum::{
 use std::collections::HashMap;
 
 use crate::{
-    html::{demo_counter_panel, js_string_literal, ranking_panel, JsBuilder},
+    html::{js_string_literal, ranking_panel, JsBuilder},
     parser::parse_reddit_url,
     parser_render::parser_panel_morph,
     state::AppState,
@@ -35,13 +35,6 @@ pub async fn post_ui_html(
     };
 
     match action {
-        HtmlUiAction::BumpDemoCounter => {
-            let count = state.bump_demo_counter().await;
-            let panel = demo_counter_panel(count, state.event_log.path().to_string_lossy().as_ref());
-            JsBuilder::new()
-                .morph_selector("#demo-counter-panel", panel)
-                .into_response()
-        }
         HtmlUiAction::RecordVote {
             a,
             b,
@@ -54,8 +47,8 @@ pub async fn post_ui_html(
             {
                 return ui_js_warn(&e).into_response();
             }
-            let mut group = state.group.write().await;
-            let panel = ranking_panel(&mut group);
+            let group = state.group.read().await;
+            let panel = ranking_panel(&group);
             JsBuilder::new()
                 .morph_selector("#ranking-panel", panel)
                 .into_response()
@@ -87,20 +80,6 @@ mod tests {
         assert!(matches!(err, HtmlUiParseError::MissingRpc));
     }
 
-    #[test]
-    fn bump_action_deserializes() {
-        let template = serde_json::json!({ "action": "bump_demo_counter" });
-        let mut form = HashMap::new();
-        form.insert(
-            UI_RPC_FIELD.to_string(),
-            serde_json::to_string(&template).unwrap(),
-        );
-        assert_eq!(
-            parse_html_ui_from_form(&form).unwrap(),
-            HtmlUiAction::BumpDemoCounter
-        );
-    }
-
     #[test]
     fn record_vote_action_deserializes() {
         let template = serde_json::json!({
diff --git a/server/src/events.rs b/server/src/events.rs
index b969242534e184d4f0a689543a479670b08a18df..eff80aef0257f706d2341f666e63d6a3d921bf6e 100644
--- a/server/src/events.rs
+++ b/server/src/events.rs
@@ -5,8 +5,6 @@ use serde::{Deserialize, Serialize};
 pub enum Event {
     /// Page view recorded (path → counter in views.json).
     ViewRecorded { path: String, ts: i64 },
-    /// Demo counter bump from `POST /ui` (persisted in the single JSONL log).
-    DemoCounterBumped { ts: i64, value: u64 },
     /// Pairwise comparison vote (replayed into [`crate::reducer::GroupState`] on boot).
     VoteRecorded {
         ts: i64,
diff --git a/server/src/html/mod.rs b/server/src/html/mod.rs
index 5b1d0b5a887d89e7e80796aa7a6c8ed5baaf2782..d69ed962b5c8625bc83c933b1825f2cc1d0868e2 100644
--- a/server/src/html/mod.rs
+++ b/server/src/html/mod.rs
@@ -13,7 +13,7 @@ use crate::{
     form_template::template_json_compact,
     parser_action::ParserAction,
     parser_render::parser_panel,
-    ranking::ranked_items,
+    ranking::ranked_items_cached,
     reducer::GroupState,
     state::AppState,
     ui_action::UI_RPC_FIELD,
@@ -199,10 +199,8 @@ fn layout(title: &str, body: Markup, views: u64, theme: &str, theme_next: &str)
     }
 }
 
-pub fn ranking_panel(group: &mut GroupState) -> Markup {
-    const MAX_ITERS: usize = 10_000;
-    const TOL: f64 = 1e-8;
-    let items = ranked_items(group, MAX_ITERS, TOL);
+pub fn ranking_panel(group: &GroupState) -> Markup {
+    let items = ranked_items_cached(group);
     html! {
         section id="ranking-panel" class="demo-panel" {
             h2 { "Ranking" }
@@ -260,35 +258,6 @@ pub fn vote_panel() -> Markup {
 }
 
 
-pub fn demo_counter_panel(count: u64, event_log_path: &str) -> Markup {
-    let rpc = template_json_compact(&serde_json::json!({ "action": "bump_demo_counter" }))
-        .expect("rpc json");
-    html! {
-        section id="demo-counter-panel" class="demo-panel" {
-            h1 { "sorter2" }
-            p class="muted" {
-                "Pairwise ranking scaffold — votes persist to JSONL and replay on boot."
-            }
-            p class="demo-count" {
-                strong { "Counter: " }
-                span id="demo-count-value" { (count) }
-            }
-            p class="muted small" {
-                "Event log: " code { (event_log_path) }
-            }
-            form method="post" action="/ui" id="demo-bump-form" {
-                input type="hidden" name=(UI_RPC_FIELD) value=(rpc);
-                button type="submit" class="btn-primary" { "Bump (POST /ui → eval JS)" }
-            }
-            p class="muted small" {
-                "Uses hidden "
-                code { "__rpc__" }
-                " JSON + Idiomorph morph — no full page reload."
-            }
-        }
-    }
-}
-
 pub async fn home(
     State(state): State<AppState>,
     jar: CookieJar,
@@ -297,16 +266,15 @@ pub async fn home(
     let path = uri.path().to_string();
     state.views.increment(path.clone());
     let views = state.views.get_views(&path);
-    let count = *state.demo_counter.read().await;
     let theme = theme_from_jar(&jar);
     let theme_next = theme_next_from_uri(&uri);
-    let mut group = state.group.write().await;
+    let group = state.group.read().await;
     let empty_action = ParserAction::suggest(String::new(), None);
     let body = html! {
+        h1 { "sorter2" }
         (parser_panel("", &empty_action))
         (vote_panel())
-        (ranking_panel(&mut group))
-        (demo_counter_panel(count, state.event_log.path().to_string_lossy().as_ref()))
+        (ranking_panel(&group))
     };
     layout("sorter2", body, views, theme, &theme_next)
 }
diff --git a/server/src/lib.rs b/server/src/lib.rs
index 6716c5b282e7980a7a0f03d63ad8b25eda61cc55..fa423640d598f4ba97a5885d228e78d7b97f7a22 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -9,6 +9,7 @@ pub mod parser_render;
 pub mod path_types;
 pub mod ranking;
 pub mod reducer;
+pub mod settlement;
 pub mod state;
 pub mod ui_action;
 pub mod views;
diff --git a/server/src/ranking.rs b/server/src/ranking.rs
index 89d3280126a8d8f841721ce8cb63ff735d68752a..2d706762792ba9239bb3f1c2e4974a2fde908013 100644
--- a/server/src/ranking.rs
+++ b/server/src/ranking.rs
@@ -91,6 +91,11 @@ pub fn compute_group_ranking(group: &mut GroupState, max_iters: usize, tol: f64)
 
 pub fn ranked_items(group: &mut GroupState, max_iters: usize, tol: f64) -> Vec<RankedItem> {
     compute_group_ranking(group, max_iters, tol);
+    ranked_items_cached(group)
+}
+
+/// Read cached scores without recomputing (HTTP fast path).
+pub fn ranked_items_cached(group: &GroupState) -> Vec<RankedItem> {
     let mut items: Vec<RankedItem> = group
         .idx_to_item
         .iter()
@@ -105,7 +110,12 @@ pub fn ranked_items(group: &mut GroupState, max_iters: usize, tol: f64) -> Vec<R
     items
 }
 
-fn compute_scores_from_edges(n: usize, edges: impl Iterator<Item = ((usize, usize), f64)>, max_iters: usize, tol: f64) -> Vec<f64> {
+pub fn compute_scores_from_edges(
+    n: usize,
+    edges: impl Iterator<Item = ((usize, usize), f64)>,
+    max_iters: usize,
+    tol: f64,
+) -> Vec<f64> {
     if n == 0 {
         return vec![];
     }
diff --git a/server/src/settlement.rs b/server/src/settlement.rs
new file mode 100644
index 0000000000000000000000000000000000000000..1f722ceaea62cda22c28ab71551f259fbf049b81
--- /dev/null
+++ b/server/src/settlement.rs
@@ -0,0 +1,114 @@
+use std::sync::Arc;
+
+use tokio::sync::{mpsc, oneshot, RwLock};
+
+use crate::{
+    event_log::EventLog,
+    events::Event,
+    ranking::compute_scores_from_edges,
+    reducer::{GroupState, VoteData},
+};
+
+const MAX_ITERS: usize = 10_000;
+const TOL: f64 = 1e-8;
+
+pub struct SettlementCommand {
+    pub vote: VoteData,
+    pub event: Event,
+    pub reply: oneshot::Sender<Result<(), String>>,
+}
+
+#[derive(Clone)]
+pub struct SettlementClient {
+    tx: mpsc::Sender<SettlementCommand>,
+}
+
+impl SettlementClient {
+    pub fn spawn(group: Arc<RwLock<GroupState>>, event_log: Arc<EventLog>) -> Self {
+        let (tx, rx) = mpsc::channel(64);
+        tokio::spawn(settlement_worker(rx, group, event_log));
+        Self { tx }
+    }
+
+    pub async fn record_vote(&self, vote: VoteData, event: Event) -> Result<(), String> {
+        let (reply, rx) = oneshot::channel();
+        self.tx
+            .send(SettlementCommand {
+                vote,
+                event,
+                reply,
+            })
+            .await
+            .map_err(|_| "settlement worker stopped".to_string())?;
+        rx.await
+            .map_err(|_| "settlement worker stopped".to_string())?
+    }
+}
+
+async fn settlement_worker(
+    mut rx: mpsc::Receiver<SettlementCommand>,
+    group: Arc<RwLock<GroupState>>,
+    event_log: Arc<EventLog>,
+) {
+    while let Some(first) = rx.recv().await {
+        let mut batch = vec![first];
+        while let Ok(more) = rx.try_recv() {
+            batch.push(more);
+        }
+
+        let mut disk_err: Option<String> = None;
+        for cmd in &batch {
+            if let Err(e) = event_log.append(&cmd.event).await {
+                disk_err = Some(e.to_string());
+                break;
+            }
+        }
+
+        if let Some(err) = disk_err {
+            for cmd in batch {
+                let _ = cmd.reply.send(Err(err.clone()));
+            }
+            continue;
+        }
+
+        let (edges, n) = {
+            let mut w = group.write().await;
+            for cmd in &batch {
+                w.apply_vote(cmd.vote.clone());
+            }
+            (w.edges.clone(), w.idx_to_item.len())
+        };
+
+        let new_scores = compute_scores_from_edges(
+            n,
+            edges.iter().map(|(&k, &v)| (k, v)),
+            MAX_ITERS,
+            TOL,
+        );
+
+        {
+            let mut w = group.write().await;
+            w.cached_scores = new_scores;
+            w.dirty = false;
+        }
+
+        for cmd in batch {
+            let _ = cmd.reply.send(Ok(()));
+        }
+    }
+}
+
+/// Compute ranking cache from current in-memory edges (startup replay only).
+pub fn warm_ranking_cache(group: &mut GroupState) {
+    if !group.dirty {
+        return;
+    }
+    let n = group.idx_to_item.len();
+    group.cached_scores = compute_scores_from_edges(
+        n,
+        group.edges.iter().map(|(&k, &v)| (k, v)),
+        MAX_ITERS,
+        TOL,
+    );
+    group.dirty = false;
+}
diff --git a/server/src/state.rs b/server/src/state.rs
index 8ec9902e2ecc31cf8208f7ad6365891dc5537eed..1922541a4064c2de1df2d993a461cae783320e05 100644
--- a/server/src/state.rs
+++ b/server/src/state.rs
@@ -6,6 +6,7 @@ use crate::{
     event_log::EventLog,
     events::Event,
     reducer::{GroupState, VoteData},
+    settlement::{warm_ranking_cache, SettlementClient},
     views::ViewStore,
 };
 
@@ -38,8 +39,8 @@ pub struct AppState {
     pub cfg: Arc<AppConfig>,
     pub event_log: Arc<EventLog>,
     pub views: ViewStore,
-    pub demo_counter: Arc<RwLock<u64>>,
     pub group: Arc<RwLock<GroupState>>,
+    settlement: SettlementClient,
 }
 
 impl AppState {
@@ -48,14 +49,10 @@ impl AppState {
         let views_path = format!("{}/views.json", cfg.data_dir);
         let views = ViewStore::new(&views_path);
 
-        let mut demo_counter: u64 = 0;
         let mut group = GroupState::new();
         if let Ok((events, _)) = event_log.load_all().await {
             for ev in events {
                 match ev {
-                    Event::DemoCounterBumped { value, .. } => {
-                        demo_counter = demo_counter.max(value);
-                    }
                     Event::VoteRecorded {
                         ts,
                         a,
@@ -74,30 +71,20 @@ impl AppState {
             }
         }
 
+       

… preview truncated; 6,096 characters omitted

download full diff A

B — c_2dc96aace098 (tommy-mor)

message

[285b64d4] Offload Reddit payloads to RocksDB and stream event log replay.

Vendor durable as a workspace crate, store entity JSON in entity_db instead
of GlobalTree, and replay events.jsonl one line at a time to cut startup RAM.

Co-authored-by: Cursor <cursoragent@cursor.com>

diff preview

diff --git a/Cargo.lock b/Cargo.lock
index e55d87f32ab32064686431c7082ef8c9ca872d63..8fc09f9ac978bd7ccf57f177989057b606677db8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -11,6 +11,18 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "anes"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
+
+[[package]]
+name = "anstyle"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
+
 [[package]]
 name = "anyhow"
 version = "1.0.102"
@@ -56,6 +68,12 @@ version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
 
+[[package]]
+name = "autocfg"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
+
 [[package]]
 name = "axum"
 version = "0.7.9"
@@ -153,6 +171,75 @@ version = "0.22.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
 
+[[package]]
+name = "bincode"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "bindgen"
+version = "0.65.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5"
+dependencies = [
+ "bitflags 1.3.2",
+ "cexpr",
+ "clang-sys",
+ "lazy_static",
+ "lazycell",
+ "peeking_take_while",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash 1.1.0",
+ "shlex",
+ "syn",
+]
+
+[[package]]
+name = "bindgen"
+version = "0.72.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
+dependencies = [
+ "bitflags 2.11.1",
+ "cexpr",
+ "clang-sys",
+ "itertools 0.13.0",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash 2.1.2",
+ "shlex",
+ "syn",
+]
+
+[[package]]
+name = "bit-set"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
+dependencies = [
+ "bit-vec",
+]
+
+[[package]]
+name = "bit-vec"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
 [[package]]
 name = "bitflags"
 version = "2.11.1"
@@ -171,6 +258,22 @@ version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
 
+[[package]]
+name = "bzip2-sys"
+version = "0.1.13+1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
+
+[[package]]
+name = "cast"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
+
 [[package]]
 name = "cc"
 version = "1.2.62"
@@ -178,15 +281,89 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98"
 dependencies = [
  "find-msvc-tools",
+ "jobserver",
+ "libc",
  "shlex",
 ]
 
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom",
+]
+
 [[package]]
 name = "cfg-if"
 version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
 
+[[package]]
+name = "ciborium"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
+dependencies = [
+ "ciborium-io",
+ "ciborium-ll",
+ "serde",
+]
+
+[[package]]
+name = "ciborium-io"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
+
+[[package]]
+name = "ciborium-ll"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
+dependencies = [
+ "ciborium-io",
+ "half",
+]
+
+[[package]]
+name = "clang-sys"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
+[[package]]
+name = "clap"
+version = "4.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
+dependencies = [
+ "clap_builder",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
+dependencies = [
+ "anstyle",
+ "clap_lex",
+]
+
+[[package]]
+name = "clap_lex"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
+
 [[package]]
 name = "cookie"
 version = "0.18.1"
@@ -224,6 +401,73 @@ version = "0.8.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
+[[package]]
+name = "criterion"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
+dependencies = [
+ "anes",
+ "cast",
+ "ciborium",
+ "clap",
+ "criterion-plot",
+ "is-terminal",
+ "itertools 0.10.5",
+ "num-traits",
+ "once_cell",
+ "oorandom",
+ "plotters",
+ "rayon",
+ "regex",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "tinytemplate",
+ "walkdir",
+]
+
+[[package]]
+name = "criterion-plot"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
+dependencies = [
+ "cast",
+ "itertools 0.10.5",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+
+[[package]]
+name = "crunchy"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
+
 [[package]]
 name = "deranged"
 version = "0.5.8"
@@ -250,6 +494,25 @@ version = "0.15.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
 
+[[package]]
+name = "durable"
+version = "0.1.0"
+dependencies = [
+ "bincode",
+ "criterion",
+ "proptest",
+ "rocksdb",
+ "serde",
+ "tempfile",
+ "thiserror",
+]
+
+[[package]]
+name = "either"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
+
 [[package]]
 name = "encoding_rs"
 version = "0.8.35"
@@ -373,6 +636,18 @@ dependencies = [
  "wasi",
 ]
 
+[[package]]
+name = "getrandom"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi 5.3.0",
+ "wasip2",
+]
+
 [[package]]
 name = "getrandom"
 version = "0.4.2"
@@ -381,11 +656,17 @@ checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
 dependencies = [
  "cfg-if",
  "libc",
- "r-efi",
+ "r-efi 6.0.0",
  "wasip2",
  "wasip3",
 ]
 
+[[package]]
+name = "glob"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
+
 [[package]]
 name = "h2"
 version = "0.4.14"
@@ -405,6 +686,17 @@ dependencies = [
  "tracing",
 ]
 
+[[package]]
+name = "half"
+version = "2.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
+dependencies = [
+ "cfg-if",
+ "crunchy",
+ "zerocopy",
+]
+
 [[package]]
 name = "hashbrown"
 version = "0.15.5"
@@ -426,6 +718,12 @@ version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
+[[package]]
+name = "hermit-abi"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
+
 [[package]]
 name = "http"
 version = "1.4.1"
@@ -676,12 +974,51 @@ version = "2.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
 
+[[package]]
+name = "is-terminal"
+version = "0.4.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "itertools"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
 [[package]]
 name = "itoa"
 version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
 
+[[package]]
+name = "jobserver"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
+dependencies = [
+ "getrandom 0.3.4",
+ "libc",
+]
+
 [[package]]
 name = "js-sys"
 version = "0.3.99"
@@ -700,6 +1037,12 @@ version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
 
+[[package]]
+name = "lazycell"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+
 [[package]]
 name = "leb128fmt"
 version = "0.1.0"
@@ -712,6 +

… preview truncated; 197,635 characters omitted

download full diff B

Hardlinks — judgments / attempts / prompt

prompt download

judgments

attempts

Prompt text is loaded only by the download route.