{"messages":[{"content":"You are ranking individual git commits to an open source project.\nCompare these two commits. Decide which commit contributed more.\nReturn ONLY a JSON object: {\"winner\": \"A\" or \"B\", \"ratio\": \"N:M\", \"explanation\": \"...\"}\n\nSide A — contributor: tommy-mor\nSide A — commit message:\n[03cd8f2e] Skip pinned Reddit posts when importing subreddit listings.\n\nCo-authored-by: Cursor \n\nSide A — 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\n\nSide B — contributor: tommy-mor\nSide B — commit message:\n[047b82bd] Remove redundant zero-ratio guard from reducer.\n\nZeros are already rejected at the DSL parser and browser handler;\nthe guard in apply_vote was dead code. The negative clamping stays\nsince add_edge_weight already skips weight-0 edges correctly.\n\nCo-Authored-By: Claude Sonnet 4.6 \n\nSide B — unified diff (full patch):\ndiff --git a/server/src/reducer.rs b/server/src/reducer.rs\nindex 0e36979abe0f051493038ff7e652efc7f7a0ac80..efbf7f67ff24c7a2989102fe62879b2794a27c5f 100644\n--- a/server/src/reducer.rs\n+++ b/server/src/reducer.rs\n@@ -112,11 +112,6 @@ impl GroupState {\n if vote.ratio_right < 0 {\n vote.ratio_right = 0;\n }\n- if vote.ratio_left == 0 || vote.ratio_right == 0 {\n- // Zero on either side produces no valid edge; drop before registering items or pair.\n- return;\n- }\n-\n let a_idx = self.ensure_item(&vote.a);\n let b_idx = self.ensure_item(&vote.b);\n \ndiff --git a/server/tests/basic.rs b/server/tests/basic.rs\nindex 08159f4a7f0850fd165817a4a1af4f31ced2ad76..1748769ccf7196b2d81cf556d5368c7e723f6a4e 100644\n--- a/server/tests/basic.rs\n+++ b/server/tests/basic.rs\n@@ -533,7 +533,7 @@ fn dsl_parse_rejects_zero_zero_vote_ratio() {\n #[test]\n fn reducer_negative_ratio_clamped_to_zero() {\n let _state = ReducerState::default();\n- // GroupState::apply_vote clamps negatives to 0; when either side is 0 the vote is dropped.\n+ // apply_vote clamps negatives to 0; add_edge_weight skips zero-weight edges.\n let mut group = GroupState::new();\n group.apply_vote(slugsocial_server::reducer::VoteData {\n ts: 1,\n@@ -546,10 +546,9 @@ fn reducer_negative_ratio_clamped_to_zero() {\n delegate: Some(\"00000000-0000-0000-0000-000000000000:test:local/test\".to_string()),\n thread_tag: \"t\".to_string(),\n });\n- // Nothing registered: zero-clamped vote is dropped before ensure_item.\n- assert!(group.idx_to_item.is_empty());\n+ // Items and pair are registered; edges are absent because weight 0 is skipped.\n+ assert_eq!(group.idx_to_item.len(), 2);\n assert!(group.edges.is_empty());\n- assert!(group.voted_pairs.is_empty());\n }\n \n \n","role":"user"}],"model":"openai/gpt-5.3-chat"}