constitution · epochs · watch · epoch 3

comparison

c_cf0a514b261a (tommy-mor) vs c_b3cb2762569d (tommy-mor)

download prompt · raw event · cmp_4ae3a177515e01

council reasoning

~x-ai/grok-latest · winner B · 12:1 · permalink

B ports the full Reddit graph parser into the live server (parser.rs, parser_action, parser_render), wires ParseQuery through the UI/API/JS with live morphing, tab-completion, and integration tests—adding lasting product capability. A only deletes a few lines of already-dead zero-ratio guard code and tweaks one test assertion.

sides

A — c_cf0a514b261a (tommy-mor)

message

[047b82bd] Remove redundant zero-ratio guard from reducer.

Zeros are already rejected at the DSL parser and browser handler;
the guard in apply_vote was dead code. The negative clamping stays
since add_edge_weight already skips weight-0 edges correctly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

diff preview

diff --git a/server/src/reducer.rs b/server/src/reducer.rs
index 0e36979abe0f051493038ff7e652efc7f7a0ac80..efbf7f67ff24c7a2989102fe62879b2794a27c5f 100644
--- a/server/src/reducer.rs
+++ b/server/src/reducer.rs
@@ -112,11 +112,6 @@ impl GroupState {
         if vote.ratio_right < 0 {
             vote.ratio_right = 0;
         }
-        if vote.ratio_left == 0 || vote.ratio_right == 0 {
-            // Zero on either side produces no valid edge; drop before registering items or pair.
-            return;
-        }
-
         let a_idx = self.ensure_item(&vote.a);
         let b_idx = self.ensure_item(&vote.b);
 
diff --git a/server/tests/basic.rs b/server/tests/basic.rs
index 08159f4a7f0850fd165817a4a1af4f31ced2ad76..1748769ccf7196b2d81cf556d5368c7e723f6a4e 100644
--- a/server/tests/basic.rs
+++ b/server/tests/basic.rs
@@ -533,7 +533,7 @@ fn dsl_parse_rejects_zero_zero_vote_ratio() {
 #[test]
 fn reducer_negative_ratio_clamped_to_zero() {
     let _state = ReducerState::default();
-    // GroupState::apply_vote clamps negatives to 0; when either side is 0 the vote is dropped.
+    // apply_vote clamps negatives to 0; add_edge_weight skips zero-weight edges.
     let mut group = GroupState::new();
     group.apply_vote(slugsocial_server::reducer::VoteData {
         ts: 1,
@@ -546,10 +546,9 @@ fn reducer_negative_ratio_clamped_to_zero() {
         delegate: Some("00000000-0000-0000-0000-000000000000:test:local/test".to_string()),
         thread_tag: "t".to_string(),
     });
-    // Nothing registered: zero-clamped vote is dropped before ensure_item.
-    assert!(group.idx_to_item.is_empty());
+    // Items and pair are registered; edges are absent because weight 0 is skipped.
+    assert_eq!(group.idx_to_item.len(), 2);
     assert!(group.edges.is_empty());
-    assert!(group.voted_pairs.is_empty());
 }
 
 

download full diff A

B — c_b3cb2762569d (tommy-mor)

message

[604a14ad] nice

diff preview

diff --git a/.gitignore b/.gitignore
index 16de5edb7185b04ef5bc64512814d7dfe2c1f50c..73e8f22cf0d39c706e7cdce5e39f1903a0f9181b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,5 @@
 /.lsp/
 *.swp
 .DS_Store
+data/
+repomix-output.xml
diff --git a/legacy/parser.rs b/legacy/parser.rs
deleted file mode 100644
index 2b87b974f8d1dd93bee35681d87668a94e4ef349..0000000000000000000000000000000000000000
--- a/legacy/parser.rs
+++ /dev/null
@@ -1,1808 +0,0 @@
-use std::collections::HashMap;
-use std::rc::Rc;
-use std::cell::RefCell;
-use crate::ui::action::UIAction;
-use crate::ui::types::{Suggestion, GuideOption, ScrollingSuggestion};
-
-// --- Core Abstractions ---
-
-/// Unique identifier for nodes in the graph
-type NodeId = &'static str;
-
-/// Pattern matching for edges
-#[derive(Debug, Clone)]
-pub enum EdgePattern {
-    /// Matches exact literal string
-    Literal(&'static str),
-    
-    /// Matches any prefix of a string and suggests the full string
-    /// e.g., PrefixOf("reddit.com") matches "r", "re", "red", "reddit", "reddit.com"
-    PrefixOf(&'static str),
-    
-    /// Captures a variable segment (e.g., subreddit name, username)
-    Variable(&'static str),
-    
-    /// Matches any string (wildcard)
-    Any,
-}
-
-impl EdgePattern {
-    /// Try to match this pattern against input, return (consumed_chars, captured_value)
-    fn matches(&self, input: &str) -> Option<(usize, Option<String>)> {
-        match self {
-            EdgePattern::Literal(lit) => {
-                if input.starts_with(lit) {
-                    Some((lit.len(), None))
-                } else {
-                    None
-                }
-            }
-            EdgePattern::PrefixOf(target) => {
-                // Check if input is a prefix of target
-                if target.starts_with(input) && !input.is_empty() {
-                    // It's a valid prefix
-                    Some((input.len(), None))
-                } else if input.starts_with(target) {
-                    // Full match
-                    Some((target.len(), None))
-                } else {
-                    None
-                }
-            }
-            EdgePattern::Variable(var_name) => {
-                // Consume until next '/' or end of string
-                let end = input.find('/').unwrap_or(input.len());
-                if end > 0 {
-                    let captured = input[..end].to_string();
-                    // Validate based on variable type
-                    if is_valid_variable(var_name, &captured) {
-                        Some((end, Some(captured)))
-                    } else {
-                        None
-                    }
-                } else {
-                    None
-                }
-            }
-            EdgePattern::Any => {
-                // Match everything until next '/' or end
-                let end = input.find('/').unwrap_or(input.len());
-                if end > 0 {
-                    Some((end, Some(input[..end].to_string())))
-                } else {
-                    None
-                }
-            }
-        }
-    }
-    
-    /// Get the completion suggestion for this pattern
-    fn completion(&self, partial: &str) -> Option<String> {
-        match self {
-            EdgePattern::PrefixOf(target) => {
-                if target.starts_with(partial) && partial != *target {
-                    Some(target.to_string())
-                } else {
-                    None
-                }
-            }
-            _ => None,
-        }
-    }
-}
-
-/// Edge in the graph
-pub struct Edge {
-    pattern: EdgePattern,
-    target: NodeId,
-    /// Optional description for autocomplete
-    description: Option<&'static str>,
-}
-
-/// Handler function for generating UI actions
-type Handler = Box<dyn Fn(&str, &str, &HashMap<String, String>) -> UIAction>;
-
-/// Node in the graph
-pub struct Node {
-    #[allow(dead_code)]
-    id: NodeId,
-    edges: Vec<Edge>,
-    handler: Option<Handler>,
-}
-
-/// The composable parser graph
-pub struct Graph {
-    nodes: HashMap<NodeId, Rc<RefCell<Node>>>,
-    root: NodeId,
-}
-
-// --- Graph Builder (Fluent API) ---
-
-pub struct GraphBuilder {
-    nodes: HashMap<NodeId, Rc<RefCell<Node>>>,
-    current_node: Option<NodeId>,
-    root: NodeId,
-}
-
-impl GraphBuilder {
-    pub fn new() -> Self {
-        let mut nodes = HashMap::new();
-        let root_node = Rc::new(RefCell::new(Node {
-            id: "root",
-            edges: Vec::new(),
-            handler: None,
-        }));
-        nodes.insert("root", root_node);
-        
-        GraphBuilder {
-            nodes,
-            current_node: Some("root"),
-            root: "root",
-        }
-    }
-    
-    /// Select a node to add edges to
-    pub fn at(mut self, node_id: NodeId) -> Self {
-        // Create node if it doesn't exist
-        if !self.nodes.contains_key(node_id) {
-            let node = Rc::new(RefCell::new(Node {
-                id: node_id,
-                edges: Vec::new(),
-                handler: None,
-            }));
-            self.nodes.insert(node_id, node);
-        }
-        self.current_node = Some(node_id);
-        self
-    }
-    
-    /// Add an edge from the current node
-    pub fn edge(self, pattern: EdgePattern, target: NodeId) -> Self {
-        self.edge_with_desc(pattern, target, None)
-    }
-    
-    /// Add an edge with description
-    pub fn edge_with_desc(mut self, pattern: EdgePattern, target: NodeId, desc: Option<&'static str>) -> Self {
-        let current = self.current_node.expect("No current node selected");
-        
-        // Create target node if it doesn't exist
-        if !self.nodes.contains_key(target) {
-            let node = Rc::new(RefCell::new(Node {
-                id: target,
-                edges: Vec::new(),
-                handler: None,
-            }));
-            self.nodes.insert(target, node);
-        }
-        
-        // Add edge to current node
-        if let Some(node) = self.nodes.get(current) {
-            node.borrow_mut().edges.push(Edge {
-                pattern,
-                target,
-                description: desc,
-            });
-        }
-        
-        self
-    }
-    
-    /// Set handler for current node
-    pub fn handler<F>(self, handler: F) -> Self 
-    where 
-        F: Fn(&str, &str, &HashMap<String, String>) -> UIAction + 'static
-    {
-        let current = self.current_node.expect("No current node selected");
-        if let Some(node) = self.nodes.get(current) {
-            node.borrow_mut().handler = Some(Box::new(handler));
-        }
-        self
-    }
-    
-    /// Build the final graph
-    pub fn build(self) -> Graph {
-        Graph {
-            nodes: self.nodes,
-            root: self.root,
-        }
-    }
-}
-
-// --- Parser Implementation ---
-
-impl Graph {
-    pub fn parse(&self, input: &str) -> UIAction {
-        let normalized = input.trim().to_lowercase();
-        let mut state = ParserState {
-            input: &normalized,
-            cursor: 0,
-            current_node_id: self.root,
-            context: HashMap::new(),
-            original_query: input.to_string(),
-            current_prefix: String::new(),
-        };
-        
-        self.parse_recursive(&mut state)
-    }
-    
-    fn parse_recursive(&self, state: &mut ParserState) -> UIAction {
-        let node = self.nodes.get(state.current_node_id)
-            .expect("Node not found in graph");
-        let node_ref = node.borrow();
-        
-        // If we've consumed all input, check for handler or suggestions
-        if state.cursor >= state.input.len() {
-            if let Some(handler) = &node_ref.handler {
-                return handler(&state.original_query, &state.current_prefix, &state.context);
-            }
-            
-            // No handler, try to suggest based on available edges
-            return self.suggest_from_edges(&node_ref, state);
-        }
-        
-        let remaining = &state.input[state.cursor..];
-        
-        // Try to match each edge
-        for edge in &node_ref.edges {
-            if let Some((consumed, captured)) = edge.pattern.matches(remaining) {
-                // Save state for potential backtracking
-                let saved_cursor = state.cursor;
-                let saved_node = state.current_node_id;
-                let saved_prefix = state.current_prefix.clone();
-                
-                // Update state
-                state.cursor += consumed;
-                state.current_node_id = edge.target;
-                state.current_prefix.push_str(&remaining[..consumed]);
-                
-                // Store captured variable if any
-                if let Some(value) = captured {
-                    if let EdgePattern::Variable(var_name) = &edge.pattern {
-                        state.context.insert(var_name.to_string(), value);
-                    }
-                }
-                
-                // Check if this is a partial match that needs completion
-                if state.cursor == state.input.len() {
-                    if let Some(completion_suffix) = edge.pattern.completion(remaining) {
-                        // Use the current_prefix plus the completion suffix
-                        let full_completion = format!("{}{}", 
-                            state.current_prefix, 
-                            completion_suffix.strip_prefix(remaining).unwrap_or(&completion_suffix)
-                        );
-                        return UIAction::suggest(
-                            state.original_query.clone(),
-                            Some(Suggestion {
-                                text: full_completion.clone(),
-                                completion: full_completion,
-                                description: edge.description.map(|d| d.to_string()),
-                                score: 1.0,
-                            })
-                        );
-                    }
-                }
-                
-                // Continue parsing from the target node
-                let result = self.parse_recursive(state);
-                
-                // If we got a valid response, return it
-                if !matches!(result, UIAction::ShowError(_)) {
-                    return result;
-                }
-                
-                // Otherwise, restore state and try next edge
-                state.cursor = saved_cursor;
-                state.current_node_id = saved_node;
-                state.current_prefix = saved_prefix;
-            }
-        }
-        
-        // No edges matched - try to provide suggestions
-        self.suggest_from_edges(&node_ref, state)
-    }
-    
-    fn suggest_from_edges(&self, node: &Node, state: &ParserState) -> UIAction {
-        let remaining = &state.input[state.cursor..];
-        
-        // Find edges that could match with more input
-        for edge in &node.edges {
-            match &edge.pattern {
-                EdgePattern::PrefixOf(target) => {
-                    if target.starts_with(remaining) && !remaining.is_empty() {
-                        // Use current_prefix instead of rebuilding from input
-                        let full_completion = format!("{}{}", state.current_prefix, target);
-                        return UIAction::suggest(
-                            state.original_query.clone(),
-                            Some(Suggestion {
-                                text: full_completion.clone(),
-                                completion: full_completion,
-                                description: edge.description.map(|d| d.to_string()),
-                                score: 1.0,
-                            })
-                        );
-                    }
-                }
-                EdgePattern::Literal(lit) => {
-             

… preview truncated; 152,463 characters omitted

download full diff B

Hardlinks — judgments / attempts / prompt

prompt download

judgments

attempts

Prompt text is loaded only by the download route.