{"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[65bce99f] sibling groups #130\n\nSide A — unified diff (full patch):\ndiff --git a/server/src/html/garden.rs b/server/src/html/garden.rs\nindex 82c1b4b4f36ea13a906035a1789ba893222b3695..e3c56d124ab7b0fa08c7f9ae736103e6b7cf5862 100644\n--- a/server/src/html/garden.rs\n+++ b/server/src/html/garden.rs\n@@ -837,7 +837,8 @@ struct SiblingNavGroup {\n links: Vec,\n }\n \n-/// Siblings under the same parent, grouped like child rankings (components then isolates).\n+/// Siblings under the same parent: one group per ranking component (ordered list), then one\n+/// group per isolated unranked sibling (each shows rank `1`, separated like components).\n #[derive(Debug, Clone)]\n struct SiblingNavBar {\n groups: Vec,\n@@ -890,15 +891,12 @@ fn build_sibling_nav(\n groups.push(SiblingNavGroup { links });\n }\n }\n- if !rankings.unranked_items.is_empty() {\n- let links: Vec = rankings\n- .unranked_items\n- .iter()\n- .map(|u| SiblingNavLink {\n+ for u in &rankings.unranked_items {\n+ groups.push(SiblingNavGroup {\n+ links: vec![SiblingNavLink {\n path: u.clone().normalized_storage().to_storage_string(),\n- })\n- .collect();\n- groups.push(SiblingNavGroup { links });\n+ }],\n+ });\n }\n let sibling_total: usize = groups.iter().map(|g| g.links.len()).sum();\n if sibling_total <= 1 {\n@@ -1541,6 +1539,29 @@ mod tests {\n assert_eq!(nav.groups[1].links.len(), 1);\n }\n \n+ #[test]\n+ fn sibling_nav_splits_each_unranked_into_its_own_group() {\n+ let mut reduced = ReducerState::default();\n+ apply_ingest(\n+ &mut reduced,\n+ 1,\n+ \"@00000000-0000-0000-0000-000000000000:test:local/test\\n\\\n+ ~/topic {topic body}\\n\\\n+ ~/topic/a {alpha}\\n\\\n+ ~/topic/b {beta}\\n\\\n+ ~/topic/c {gamma}\\n\\\n+ ~/topic/d {delta}\\n\\\n+ {a beats b}\\n ~/topic/a 2:1 ~/topic/b\\n\",\n+ );\n+\n+ let model = build_item_page_view_model(&reduced, &ScopeId::Public, \"~/topic/a\");\n+ let nav = model.sibling_nav.expect(\"expected sibling nav\");\n+ assert_eq!(nav.groups.len(), 3);\n+ assert_eq!(nav.groups[0].links.len(), 2);\n+ assert_eq!(nav.groups[1].links.len(), 1);\n+ assert_eq!(nav.groups[2].links.len(), 1);\n+ }\n+\n #[test]\n fn item_page_model_builds_ranked_child_components() {\n let mut reduced = ReducerState::default();\n\n\nSide B — contributor: tommy-mor\nSide B — commit message:\n[9e3d989b] Add test that 25 spanning-tree votes with perfect ratios sort the alphabet.\n\nDemonstrates rank centrality recovers the true order from a random connected\ncomparison graph when each vote encodes item strength as (idx+1).\n\nCo-authored-by: Cursor \n\nSide B — unified diff (full patch):\ndiff --git a/server/src/ranking.rs b/server/src/ranking.rs\nindex c9b4d5d89d2f22cf53a5b43eb979e19a11bc89a1..93cb4c9f5887a1e598cdc9d648751055f618adcc 100644\n--- a/server/src/ranking.rs\n+++ b/server/src/ranking.rs\n@@ -369,6 +369,48 @@ mod tests {\n assert_eq!(comp1, vec![\"c\", \"d\"]);\n }\n \n+ /// A random spanning tree over 26 items needs only n−1 = 25 pairwise votes.\n+ /// When each vote uses the \"perfect\" ratio (strength left : strength right =\n+ /// (idx_left+1) : (idx_right+1)), rank centrality recovers the true order.\n+ /// See `rank-eric.py` (Eric's demo of Negahban–Oh–Shah rank centrality).\n+ #[test]\n+ fn twenty_five_random_votes_perfect_ratios_sort_alphabet() {\n+ use rand::seq::SliceRandom;\n+\n+ const N: usize = 26;\n+ let letters: Vec = (0..N).map(|i| char::from(b'a' + i as u8)).collect();\n+\n+ let mut rng = rand::thread_rng();\n+ let mut perm: Vec = (0..N).collect();\n+ perm.shuffle(&mut rng);\n+\n+ let mut g = mk_group();\n+ for k in 1..N {\n+ let i = *perm[..k].choose(&mut rng).unwrap();\n+ let j = perm[k];\n+ let (a, b) = (letters[i], letters[j]);\n+ g.apply_vote(vote(\n+ k as i64,\n+ &a.to_string(),\n+ &b.to_string(),\n+ (i + 1) as i32,\n+ (j + 1) as i32,\n+ ));\n+ }\n+\n+ let ranked = ranked_items(&g);\n+ assert_eq!(ranked.len(), N);\n+ for (rank, item) in ranked.iter().enumerate() {\n+ let expected = char::from(b'a' + (N - 1 - rank) as u8);\n+ assert_eq!(\n+ item.item.as_str(),\n+ expected.to_string(),\n+ \"rank {rank}: expected '{expected}', got '{}'\",\n+ item.item.as_str()\n+ );\n+ }\n+ }\n+\n #[test]\n fn subset_ranking_ranks_within_component_only() {\n let mut g = mk_group();\n","role":"user"}],"model":"openai/gpt-chat-latest"}