Skip to content

Commit eecdef4

Browse files
committed
update issue-to-pr to check issue body
1 parent 180fd7c commit eecdef4

2 files changed

Lines changed: 128 additions & 2 deletions

File tree

.claude/skills/issue-to-pr/SKILL.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ Extract issue number and flags from arguments:
3636
### 2. Fetch Issue
3737

3838
```bash
39-
gh issue view <number> --json title,body,labels,assignees
39+
gh issue view <number> --json title,body,labels,assignees,comments
4040
```
4141

42-
Present issue summary to user.
42+
Present issue summary to user. **Also review all comments** — contributors and maintainers may have posted clarifications, corrections, additional context, or design decisions that refine or override parts of the original issue body. Incorporate relevant comment content when writing the plan.
4343

4444
### 3. Verify Issue Has Passed check-issue
4545

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
//! Detect problems that have no reduction path connecting them to the main graph.
2+
//!
3+
//! Finds:
4+
//! 1. Completely isolated problem types (no reductions in or out)
5+
//! 2. Disconnected components (groups not reachable from the largest component)
6+
//!
7+
//! Run with: `cargo run --example detect_isolated_problems`
8+
9+
use problemreductions::rules::ReductionGraph;
10+
use std::collections::{BTreeMap, BTreeSet, VecDeque};
11+
12+
fn main() {
13+
let graph = ReductionGraph::new();
14+
15+
let mut types = graph.problem_types();
16+
types.sort();
17+
18+
// Build undirected adjacency at the problem-type level
19+
let mut adj: BTreeMap<&str, BTreeSet<&str>> = BTreeMap::new();
20+
for &name in &types {
21+
adj.entry(name).or_default();
22+
for edge in graph.outgoing_reductions(name) {
23+
adj.entry(name).or_default().insert(edge.target_name);
24+
adj.entry(edge.target_name).or_default().insert(name);
25+
}
26+
}
27+
28+
// Find connected components via BFS
29+
let mut visited: BTreeSet<&str> = BTreeSet::new();
30+
let mut components: Vec<Vec<&str>> = Vec::new();
31+
32+
for &name in &types {
33+
if visited.contains(name) {
34+
continue;
35+
}
36+
let mut component = Vec::new();
37+
let mut queue = VecDeque::new();
38+
queue.push_back(name);
39+
visited.insert(name);
40+
41+
while let Some(current) = queue.pop_front() {
42+
component.push(current);
43+
if let Some(neighbors) = adj.get(current) {
44+
for &neighbor in neighbors {
45+
if visited.insert(neighbor) {
46+
queue.push_back(neighbor);
47+
}
48+
}
49+
}
50+
}
51+
component.sort();
52+
components.push(component);
53+
}
54+
55+
// Sort components by size (largest first)
56+
components.sort_by(|a, b| b.len().cmp(&a.len()));
57+
58+
// Identify isolated types (no edges at all)
59+
let isolated: Vec<&str> = types
60+
.iter()
61+
.copied()
62+
.filter(|name| adj.get(name).is_some_and(|n| n.is_empty()))
63+
.collect();
64+
65+
// Report
66+
println!("Reduction Graph Connectivity Report");
67+
println!("====================================");
68+
println!("Total problem types: {}", types.len());
69+
println!("Total reductions: {}", graph.num_reductions());
70+
println!("Connected components: {}", components.len());
71+
println!();
72+
73+
if !isolated.is_empty() {
74+
println!(
75+
"Isolated problems ({}) — no reductions in or out:",
76+
isolated.len()
77+
);
78+
for name in &isolated {
79+
let num_variants = graph.variants_for(name).len();
80+
println!(" {name} ({num_variants} variant(s))");
81+
}
82+
println!();
83+
}
84+
85+
if components.len() > 1 {
86+
println!("Disconnected components:");
87+
for (i, comp) in components.iter().enumerate() {
88+
let marker = if i == 0 { " (main)" } else { "" };
89+
println!("\n Component {}{marker} — {} types:", i + 1, comp.len());
90+
for name in comp {
91+
let num_variants = graph.variants_for(name).len();
92+
let out_count = graph.outgoing_reductions(name).len();
93+
let in_count = graph.incoming_reductions(name).len();
94+
println!(" {name} ({num_variants} variant(s), {out_count} out, {in_count} in)");
95+
}
96+
}
97+
} else {
98+
println!("All problem types with reductions are in a single connected component.");
99+
}
100+
101+
// Also report at the variant level
102+
println!();
103+
println!("Variant-level detail for isolated problems:");
104+
for name in &isolated {
105+
let variants = graph.variants_for(name);
106+
for v in &variants {
107+
let label = if v.is_empty() {
108+
name.to_string()
109+
} else {
110+
let parts: Vec<String> =
111+
v.iter().map(|(k, val)| format!("{k}: {val}")).collect();
112+
format!("{name} {{{}}}", parts.join(", "))
113+
};
114+
if let Some(c) = graph.variant_complexity(name, v) {
115+
println!(" {label} complexity: {c}");
116+
} else {
117+
println!(" {label}");
118+
}
119+
}
120+
}
121+
122+
// Exit with non-zero if there are isolated types or multiple components
123+
if !isolated.is_empty() || components.len() > 1 {
124+
std::process::exit(1);
125+
}
126+
}

0 commit comments

Comments
 (0)