You are a constitutional council ranking individual git commits for ownership allocation. Compare these two commits. Decide which contributed more lasting value to the project. Judge substance, not spectacle: - Prefer correct, lasting design and real bugfixes over churn, formatting, renames, or generated noise. - Prefer clarity and necessity over sheer line count. A small precise change can beat a large diffuse one. - Do not favor a side merely because its patch is longer or noisier. - Weight what the change does for the project, not the contributor's name. Return ONLY a JSON object: {"winner": "A" or "B", "ratio": "N:M", "explanation": "..."} The explanation must cite concrete differences in the patches (1-3 sentences). Side A — contributor: tommy-mor Side A — commit message: [14749a34] Show graph topology with pair suggestions Expose existing connectivity statistics in CLI output so voters can see sparse or disconnected scopes before adding an edge. Co-authored-by: Cursor Side A — unified diff (full patch): diff --git a/cli/src/main.rs b/cli/src/main.rs index 70435b412188a151c5e89e842a5de57f7480ddf2..abb5a55b49f60fe28fbfd4ec02715cb94ea0b4ec 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -397,6 +397,29 @@ fn print_item_response(resp: &ItemResponse) { } } +fn format_connectivity_stats(stats: &ConnectivityStats) -> String { + let density = if stats.pairs_possible == 0 { + 0.0 + } else { + stats.pairs_voted as f64 / stats.pairs_possible as f64 * 100.0 + }; + let component_label = if stats.components == 1 { "component" } else { "components" }; + let connection_status = if stats.comparisons_until_connected == 0 { + "connected".to_string() + } else { + let comparison_label = if stats.comparisons_until_connected == 1 { + "comparison" + } else { + "comparisons" + }; + format!("{} {comparison_label} to connect", stats.comparisons_until_connected) + }; + format!( + "graph: {} items, {}/{} pairs ({density:.1}% density), {} {component_label}, {connection_status}", + stats.items, stats.pairs_voted, stats.pairs_possible, stats.components, + ) +} + fn print_pair_response(resp: &PairResponse) { println!("{} vs {}", resp.left, resp.right); if let Some(b) = &resp.left_body { @@ -413,6 +436,10 @@ fn print_pair_response(resp: &PairResponse) { println!(); println!("threads: {}", resp.threads.iter().map(|t| format!("#{t}")).collect::>().join(" ")); } + if let Some(stats) = &resp.connectivity { + println!(); + println!("{}", format_connectivity_stats(stats)); + } println!(); println!("---"); println!("Before writing your comparison, talk to your human. Ask them about their relationship to these two items — which one has meant more to them, whether their perspective has changed over time, and where they land now. Listen to what they say. Then write a comparison that synthesizes their perspective with your own analysis. The best submissions on slug.social carry both voices — your reasoning and their experience."); @@ -816,6 +843,43 @@ fn write_secret_file(name: &str, contents: &str) -> Result<()> { Ok(()) } +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn connectivity_stats_show_sparse_disconnected_graph() { + let stats = ConnectivityStats { + items: 9, + components: 3, + comparisons_until_connected: 2, + pairs_voted: 8, + pairs_possible: 36, + }; + + assert_eq!( + format_connectivity_stats(&stats), + "graph: 9 items, 8/36 pairs (22.2% density), 3 components, 2 comparisons to connect" + ); + } + + #[test] + fn connectivity_stats_show_connected_graph() { + let stats = ConnectivityStats { + items: 4, + components: 1, + comparisons_until_connected: 0, + pairs_voted: 3, + pairs_possible: 6, + }; + + assert_eq!( + format_connectivity_stats(&stats), + "graph: 4 items, 3/6 pairs (50.0% density), 1 component, connected" + ); + } +} + async fn run_scoped(base: &str, room: &str, sub: ScopedCmd) -> Result<()> { let room = room.trim(); let client = http_client()?; Side B — contributor: tommy-mor Side B — commit message: [65bce99f] sibling groups #130 Side B — unified diff (full patch): diff --git a/server/src/html/garden.rs b/server/src/html/garden.rs index 82c1b4b4f36ea13a906035a1789ba893222b3695..e3c56d124ab7b0fa08c7f9ae736103e6b7cf5862 100644 --- a/server/src/html/garden.rs +++ b/server/src/html/garden.rs @@ -837,7 +837,8 @@ struct SiblingNavGroup { links: Vec, } -/// Siblings under the same parent, grouped like child rankings (components then isolates). +/// Siblings under the same parent: one group per ranking component (ordered list), then one +/// group per isolated unranked sibling (each shows rank `1`, separated like components). #[derive(Debug, Clone)] struct SiblingNavBar { groups: Vec, @@ -890,15 +891,12 @@ fn build_sibling_nav( groups.push(SiblingNavGroup { links }); } } - if !rankings.unranked_items.is_empty() { - let links: Vec = rankings - .unranked_items - .iter() - .map(|u| SiblingNavLink { + for u in &rankings.unranked_items { + groups.push(SiblingNavGroup { + links: vec![SiblingNavLink { path: u.clone().normalized_storage().to_storage_string(), - }) - .collect(); - groups.push(SiblingNavGroup { links }); + }], + }); } let sibling_total: usize = groups.iter().map(|g| g.links.len()).sum(); if sibling_total <= 1 { @@ -1541,6 +1539,29 @@ mod tests { assert_eq!(nav.groups[1].links.len(), 1); } + #[test] + fn sibling_nav_splits_each_unranked_into_its_own_group() { + let mut reduced = ReducerState::default(); + apply_ingest( + &mut reduced, + 1, + "@00000000-0000-0000-0000-000000000000:test:local/test\n\ + ~/topic {topic body}\n\ + ~/topic/a {alpha}\n\ + ~/topic/b {beta}\n\ + ~/topic/c {gamma}\n\ + ~/topic/d {delta}\n\ + {a beats b}\n ~/topic/a 2:1 ~/topic/b\n", + ); + + let model = build_item_page_view_model(&reduced, &ScopeId::Public, "~/topic/a"); + let nav = model.sibling_nav.expect("expected sibling nav"); + assert_eq!(nav.groups.len(), 3); + assert_eq!(nav.groups[0].links.len(), 2); + assert_eq!(nav.groups[1].links.len(), 1); + assert_eq!(nav.groups[2].links.len(), 1); + } + #[test] fn item_page_model_builds_ranked_child_components() { let mut reduced = ReducerState::default();