{"messages":[{"content":"You are a constitutional council ranking individual git commits for ownership allocation.\n\nCompare these two commits. Decide which contributed more lasting value to the project.\n\nJudge substance, not spectacle:\n- Prefer correct, lasting design and real bugfixes over churn, formatting, renames, or generated noise.\n- Prefer clarity and necessity over sheer line count. A small precise change can beat a large diffuse one.\n- Do not favor a side merely because its patch is longer or noisier.\n- Weight what the change does for the project, not the contributor's name.\n\nReturn ONLY a JSON object: {\"winner\": \"A\" or \"B\", \"ratio\": \"N:M\", \"explanation\": \"...\"}\nThe explanation must cite concrete differences in the patches (1-3 sentences).\n\nSide A — contributor: tommy-mor\nSide A — commit message:\n[0366806e] Color rank rows by vote mass within each group, not list position.\n\nMin–max normalization keeps similar scores visually close while still\nusing the full gradient as groups grow and absolute mass dilutes.\n\nCo-authored-by: Cursor \n\nSide A — unified diff (full patch):\ndiff --git a/server/src/html/mod.rs b/server/src/html/mod.rs\nindex a58cbbee3490a08a625cb06df06848c59a615d65..4eff2e19ed4d303ff8e80c1eabd8a15b4990e643 100644\n--- a/server/src/html/mod.rs\n+++ b/server/src/html/mod.rs\n@@ -264,12 +264,19 @@ pub fn scope_theme_style(parent: &ItemId) -> String {\n )\n }\n \n-fn rank_row_style(parent: &ItemId, ordinal: usize, total: usize) -> String {\n- let t = if total <= 1 {\n- 0.0\n- } else {\n- ordinal as f64 / (total - 1) as f64\n- };\n+/// Map vote mass to gradient position using the group's score range, not raw mass or\n+/// list position. Vote mass sums to 1 across the component, so absolute values dilute\n+/// as N grows; min–max within the visible list preserves similar scores → similar colors.\n+fn score_gradient_t(score: f64, min_score: f64, max_score: f64) -> f64 {\n+ let spread = max_score - min_score;\n+ if spread < 1e-9 {\n+ return 0.5;\n+ }\n+ ((max_score - score) / spread).clamp(0.0, 1.0)\n+}\n+\n+fn rank_row_style(parent: &ItemId, score: f64, min_score: f64, max_score: f64) -> String {\n+ let t = score_gradient_t(score, min_score, max_score);\n let base_hue = scope_base_hue(parent);\n let hue = (base_hue + 118.0 * t) % 360.0;\n let lightness = 0.74 - 0.34 * t;\n@@ -295,14 +302,15 @@ fn rank_list(\n highlighted: &HashSet,\n tree: &GlobalTree,\n ) -> Markup {\n- let group_len = items.len();\n+ let min_score = items.iter().map(|r| r.score).fold(f64::INFINITY, f64::min);\n+ let max_score = items.iter().map(|r| r.score).fold(f64::NEG_INFINITY, f64::max);\n html! {\n @if !items.is_empty() {\n h3 class=\"rank-heading muted small\" { (label) }\n ol class=\"rank-list\" {\n @for (i, r) in items.iter().enumerate() {\n @let href = item_href(&r.item);\n- @let style = rank_row_style(parent, i, group_len);\n+ @let style = rank_row_style(parent, r.score, min_score, max_score);\n @let class = rank_row_class(&r.item, highlighted);\n li class=(class)\n data-rank-item=(r.item.as_str())\n@@ -517,19 +525,37 @@ pub async fn browse(State(state): State, uri: Uri) -> impl IntoRespons\n \n #[cfg(test)]\n mod tests {\n- use super::{rank_row_style, SORTER_UI_JS};\n+ use super::{rank_row_style, score_gradient_t, SORTER_UI_JS};\n use crate::path_types::ItemId;\n \n #[test]\n- fn rank_row_style_gradients_per_group_not_globally() {\n+ fn score_gradient_t_uses_group_range_not_absolute_mass() {\n+ assert!((score_gradient_t(0.12, 0.08, 0.12) - 0.0).abs() < 1e-9);\n+ assert!((score_gradient_t(0.08, 0.08, 0.12) - 1.0).abs() < 1e-9);\n+ // Raw 12% mass would map near the dark end globally; within this group it's the top.\n+ assert!(score_gradient_t(0.12, 0.08, 0.12) < score_gradient_t(0.12, 0.0, 1.0));\n+ }\n+\n+ #[test]\n+ fn score_gradient_t_similar_scores_similar_t() {\n+ let a = score_gradient_t(0.41, 0.20, 0.60);\n+ let b = score_gradient_t(0.40, 0.20, 0.60);\n+ assert!((a - b).abs() < 0.05);\n+ assert!((a - score_gradient_t(0.60, 0.20, 0.60)).abs() > 0.3);\n+ }\n+\n+ #[test]\n+ fn score_gradient_t_tied_scores_neutral() {\n+ assert!((score_gradient_t(0.25, 0.25, 0.25) - 0.5).abs() < 1e-9);\n+ }\n+\n+ #[test]\n+ fn rank_row_style_same_inputs_same_color() {\n let parent = ItemId::opaque(\"test-scope\");\n- let first_in_four = rank_row_style(&parent, 0, 4);\n- let last_in_four = rank_row_style(&parent, 3, 4);\n- let first_in_two = rank_row_style(&parent, 0, 2);\n- let last_in_two = rank_row_style(&parent, 1, 2);\n- assert_eq!(first_in_four, first_in_two);\n- assert_eq!(last_in_four, last_in_two);\n- assert_ne!(first_in_four, last_in_four);\n+ assert_eq!(\n+ rank_row_style(&parent, 0.33, 0.20, 0.60),\n+ rank_row_style(&parent, 0.33, 0.20, 0.60),\n+ );\n }\n \n #[test]\n\n\nSide B — contributor: tommy-mor\nSide B — commit message:\n[03cd8f2e] Skip pinned Reddit posts when importing subreddit listings.\n\nCo-authored-by: Cursor \n\nSide B — unified diff (full patch):\ndiff --git a/server/src/reddit.rs b/server/src/reddit.rs\nindex f409764c1e1f36216f1b08107043c2eab905694c..fa5577f8ee0a8c53ff4dbec988a90a5d2fc3cdee 100644\n--- a/server/src/reddit.rs\n+++ b/server/src/reddit.rs\n@@ -661,6 +661,7 @@ pub fn map_children_url(id: &ItemId, api_base: &str) -> String {\n /// Parse a subreddit listing payload into `(child_id, child_payload)` entries.\n /// Each child id is the post's permalink under `reddit.com/…`, and the payload\n /// is the raw `{kind, data}` listing element (persisted per child).\n+/// Pinned / stickied posts are skipped.\n fn parse_children(_parent: &ItemId, payload: &Value) -> Vec<(ItemId, Value)> {\n let mut out = Vec::new();\n let children = match payload.pointer(\"/data/children\").and_then(|c| c.as_array()) {\n@@ -668,6 +669,9 @@ fn parse_children(_parent: &ItemId, payload: &Value) -> Vec<(ItemId, Value)> {\n None => return out,\n };\n for child in children {\n+ if child_is_pinned(child) {\n+ continue;\n+ }\n let permalink = match child.pointer(\"/data/permalink\").and_then(|p| p.as_str()) {\n Some(p) if !p.is_empty() => p,\n _ => continue,\n@@ -680,6 +684,15 @@ fn parse_children(_parent: &ItemId, payload: &Value) -> Vec<(ItemId, Value)> {\n out\n }\n \n+fn child_is_pinned(child: &Value) -> bool {\n+ let data = match child.get(\"data\") {\n+ Some(d) => d,\n+ None => return false,\n+ };\n+ data.get(\"stickied\").and_then(|v| v.as_bool()) == Some(true)\n+ || data.get(\"pinned\").and_then(|v| v.as_bool()) == Some(true)\n+}\n+\n fn parse_reddit_view(id: &ItemId, v: &Value) -> Option {\n let segments: Vec<&str> = id.as_str().split('/').collect();\n \n@@ -853,4 +866,46 @@ mod tests {\n Some(\"http://v3.redgifs.com/watch/impossibleprestigioushedgehog\")\n );\n }\n+\n+ #[test]\n+ fn parse_children_skips_pinned_posts() {\n+ let payload = serde_json::json!({\n+ \"kind\": \"Listing\",\n+ \"data\": {\n+ \"children\": [\n+ {\n+ \"kind\": \"t3\",\n+ \"data\": {\n+ \"title\": \"Official rules (pinned)\",\n+ \"permalink\": \"/r/rust/comments/pin/official_rules/\",\n+ \"stickied\": true\n+ }\n+ },\n+ {\n+ \"kind\": \"t3\",\n+ \"data\": {\n+ \"title\": \"Also pinned via pinned field\",\n+ \"permalink\": \"/r/rust/comments/pin2/also_pinned/\",\n+ \"pinned\": true\n+ }\n+ },\n+ {\n+ \"kind\": \"t3\",\n+ \"data\": {\n+ \"title\": \"Normal post\",\n+ \"permalink\": \"/r/rust/comments/aaa/normal_post/\",\n+ \"stickied\": false\n+ }\n+ }\n+ ]\n+ }\n+ });\n+ let parent = ItemId::from_url(\"https://reddit.com/r/rust\").unwrap();\n+ let children = parse_children(&parent, &payload);\n+ assert_eq!(children.len(), 1);\n+ assert_eq!(\n+ children[0].0.as_str(),\n+ \"https://reddit.com/r/rust/comments/aaa\"\n+ );\n+ }\n }\n","role":"user"}],"model":"openai/gpt-chat-latest"}