Skip to content

Commit ce3c597

Browse files
fix(ci): complete Ast import removal in verification/mod.rs and cargo fmt across crate (#44)
## Summary Closes the remaining Rust CI red on `main` after #43 (steamworks 0.12.2 → 0.13.1): - **`coverage` job** was still failing with `error: unused import: Ast` at `src/verification/mod.rs:81`. The fix-up commit `9435baa` removed the same import from `src/verification/z3_integration.rs` but missed this second occurrence. Removed. - **`test` job** was exit-1-ing on `cargo fmt --check`. Ran `cargo fmt --all` across the crate — 12 files reformatted, no semantic change (struct-literal expansion + use-ordering). The `security` job was cancelled by an Actions runner shutdown signal during the `cargo-outdated` install — looks transient, not code-related, and should pass on rerun. ## Test plan - [ ] `cargo fmt --all -- --check` clean. - [ ] `cargo build --features z3-verify` succeeds. - [ ] `coverage`, `test`, and `security` Rust CI jobs go green on this branch.
1 parent 97acc95 commit ce3c597

13 files changed

Lines changed: 342 additions & 210 deletions

File tree

.github/workflows/hypatia-scan.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ jobs:
7979
echo "- Medium: $MEDIUM" >> $GITHUB_STEP_SUMMARY
8080
8181
- name: Upload findings artifact
82-
uses: actions/upload-artifact@65c79d7f54e76e4e3c7a8f34db0f4ac8b515c478 # v4
82+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
8383
with:
8484
name: hypatia-findings
8585
path: hypatia-findings.json

benches/proof_of_work_bench.rs

Lines changed: 92 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,50 @@ use proof_of_work::{BoardState, GoalCondition, Level, LogicPiece};
1717
/// Create a populated board with assumptions, gates, goals, and wires.
1818
fn populated_board() -> BoardState {
1919
let pieces = vec![
20-
LogicPiece::Assumption { formula: "P".into(), position: (2, 5) },
21-
LogicPiece::Assumption { formula: "Q".into(), position: (2, 3) },
22-
LogicPiece::Assumption { formula: "R".into(), position: (1, 7) },
23-
LogicPiece::Goal { formula: "S".into(), position: (15, 5) },
24-
LogicPiece::Goal { formula: "T".into(), position: (15, 10) },
20+
LogicPiece::Assumption {
21+
formula: "P".into(),
22+
position: (2, 5),
23+
},
24+
LogicPiece::Assumption {
25+
formula: "Q".into(),
26+
position: (2, 3),
27+
},
28+
LogicPiece::Assumption {
29+
formula: "R".into(),
30+
position: (1, 7),
31+
},
32+
LogicPiece::Goal {
33+
formula: "S".into(),
34+
position: (15, 5),
35+
},
36+
LogicPiece::Goal {
37+
formula: "T".into(),
38+
position: (15, 10),
39+
},
2540
LogicPiece::AndIntro { position: (5, 4) },
2641
LogicPiece::OrIntro { position: (8, 6) },
2742
LogicPiece::ImpliesIntro { position: (10, 4) },
2843
LogicPiece::NotIntro { position: (12, 8) },
29-
LogicPiece::Wire { from: (3, 5), to: (5, 4) },
30-
LogicPiece::Wire { from: (3, 3), to: (5, 4) },
31-
LogicPiece::Wire { from: (6, 4), to: (8, 6) },
32-
LogicPiece::Wire { from: (9, 6), to: (10, 4) },
33-
LogicPiece::Wire { from: (11, 4), to: (15, 5) },
44+
LogicPiece::Wire {
45+
from: (3, 5),
46+
to: (5, 4),
47+
},
48+
LogicPiece::Wire {
49+
from: (3, 3),
50+
to: (5, 4),
51+
},
52+
LogicPiece::Wire {
53+
from: (6, 4),
54+
to: (8, 6),
55+
},
56+
LogicPiece::Wire {
57+
from: (9, 6),
58+
to: (10, 4),
59+
},
60+
LogicPiece::Wire {
61+
from: (11, 4),
62+
to: (15, 5),
63+
},
3464
];
3565
BoardState::with_pieces(20, 20, pieces)
3666
}
@@ -43,17 +73,28 @@ fn verifiable_level() -> Level {
4373
description: "P AND Q implies R".into(),
4474
theorem: "(assert (=> (and P Q) R))".into(),
4575
initial_state: BoardState::new(10, 10),
46-
goal_state: GoalCondition::ProveFormula { formula: "R".into() },
76+
goal_state: GoalCondition::ProveFormula {
77+
formula: "R".into(),
78+
},
4779
}
4880
}
4981

5082
/// Pieces that form a valid proof for the verifiable level (AND gate adjacent to
5183
/// both assumptions and the goal).
5284
fn valid_proof_pieces() -> Vec<LogicPiece> {
5385
vec![
54-
LogicPiece::Assumption { formula: "P".into(), position: (2, 5) },
55-
LogicPiece::Assumption { formula: "Q".into(), position: (2, 3) },
56-
LogicPiece::Goal { formula: "R".into(), position: (5, 4) },
86+
LogicPiece::Assumption {
87+
formula: "P".into(),
88+
position: (2, 5),
89+
},
90+
LogicPiece::Assumption {
91+
formula: "Q".into(),
92+
position: (2, 3),
93+
},
94+
LogicPiece::Goal {
95+
formula: "R".into(),
96+
position: (5, 4),
97+
},
5798
LogicPiece::AndIntro { position: (3, 4) },
5899
]
59100
}
@@ -154,10 +195,19 @@ fn bench_validate_board(c: &mut Criterion) {
154195
fn bench_validate_piece_placement(c: &mut Criterion) {
155196
let board = populated_board();
156197
let pieces = [
157-
LogicPiece::Assumption { formula: "X".into(), position: (0, 0) },
158-
LogicPiece::Wire { from: (3, 3), to: (7, 7) },
198+
LogicPiece::Assumption {
199+
formula: "X".into(),
200+
position: (0, 0),
201+
},
202+
LogicPiece::Wire {
203+
from: (3, 3),
204+
to: (7, 7),
205+
},
159206
LogicPiece::AndIntro { position: (99, 99) }, // out of bounds
160-
LogicPiece::Goal { formula: "".into(), position: (4, 4) }, // empty formula
207+
LogicPiece::Goal {
208+
formula: "".into(),
209+
position: (4, 4),
210+
}, // empty formula
161211
];
162212

163213
c.bench_function("validate_piece_placement_4_pieces", |b| {
@@ -178,9 +228,7 @@ fn bench_is_ready_for_verification(c: &mut Criterion) {
178228
let board = populated_board();
179229

180230
c.bench_function("is_ready_for_verification", |b| {
181-
b.iter(|| {
182-
black_box(validation::is_ready_for_verification(&board))
183-
});
231+
b.iter(|| black_box(validation::is_ready_for_verification(&board)));
184232
});
185233
}
186234

@@ -253,9 +301,18 @@ fn bench_verify_level_solution(c: &mut Criterion) {
253301
fn bench_verify_level_solution_invalid(c: &mut Criterion) {
254302
let level = verifiable_level();
255303
let pieces = vec![
256-
LogicPiece::Assumption { formula: "P".into(), position: (0, 0) },
257-
LogicPiece::Assumption { formula: "Q".into(), position: (0, 19) },
258-
LogicPiece::Goal { formula: "R".into(), position: (19, 19) },
304+
LogicPiece::Assumption {
305+
formula: "P".into(),
306+
position: (0, 0),
307+
},
308+
LogicPiece::Assumption {
309+
formula: "Q".into(),
310+
position: (0, 19),
311+
},
312+
LogicPiece::Goal {
313+
formula: "R".into(),
314+
position: (19, 19),
315+
},
259316
LogicPiece::AndIntro { position: (10, 10) }, // too far from everything
260317
];
261318

@@ -272,11 +329,20 @@ fn bench_verify_level_solution_invalid(c: &mut Criterion) {
272329
/// Benchmark serialization of a LogicPiece to SMT format.
273330
fn bench_piece_to_smt(c: &mut Criterion) {
274331
let pieces = [
275-
LogicPiece::Assumption { formula: "P".into(), position: (2, 5) },
276-
LogicPiece::Goal { formula: "Q".into(), position: (8, 4) },
332+
LogicPiece::Assumption {
333+
formula: "P".into(),
334+
position: (2, 5),
335+
},
336+
LogicPiece::Goal {
337+
formula: "Q".into(),
338+
position: (8, 4),
339+
},
277340
LogicPiece::AndIntro { position: (5, 5) },
278341
LogicPiece::ImpliesIntro { position: (3, 3) },
279-
LogicPiece::ForallIntro { position: (1, 1), variable: "x".into() },
342+
LogicPiece::ForallIntro {
343+
position: (1, 1),
344+
variable: "x".into(),
345+
},
280346
];
281347

282348
c.bench_function("piece_to_smt_5_pieces", |b| {

src/editor/ui.rs

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
use bevy::prelude::*;
55
use bevy_egui::{egui, EguiContexts};
66

7-
use super::{EditorEntity, EditorPieceType, EditorState, EditorTool, SaveLevelEvent, TestLevelEvent};
7+
use super::{
8+
EditorEntity, EditorPieceType, EditorState, EditorTool, SaveLevelEvent, TestLevelEvent,
9+
};
810
use crate::game::{GoalCondition, LogicPiece};
911
use crate::levels::LevelPackManager;
1012
use crate::states::GameState;
@@ -124,10 +126,7 @@ pub fn editor_ui_system(
124126

125127
for piece_type in piece_types {
126128
let selected = editor.selected_piece == Some(piece_type);
127-
if ui
128-
.selectable_label(selected, piece_type.name())
129-
.clicked()
130-
{
129+
if ui.selectable_label(selected, piece_type.name()).clicked() {
131130
editor.selected_piece = Some(piece_type);
132131
editor.tool = EditorTool::Place;
133132
}
@@ -173,10 +172,7 @@ pub fn editor_ui_system(
173172
ui.separator();
174173

175174
ui.label("Name:");
176-
if ui
177-
.text_edit_singleline(&mut editor.level.name)
178-
.changed()
179-
{
175+
if ui.text_edit_singleline(&mut editor.level.name).changed() {
180176
editor.dirty = true;
181177
}
182178

@@ -191,10 +187,7 @@ pub fn editor_ui_system(
191187

192188
ui.add_space(5.0);
193189
ui.label("Theorem (SMT-LIB2):");
194-
if ui
195-
.text_edit_singleline(&mut editor.level.theorem)
196-
.changed()
197-
{
190+
if ui.text_edit_singleline(&mut editor.level.theorem).changed() {
198191
editor.dirty = true;
199192
}
200193

@@ -207,14 +200,20 @@ pub fn editor_ui_system(
207200

208201
ui.horizontal(|ui| {
209202
ui.label("Width:");
210-
if ui.add(egui::DragValue::new(&mut width).range(3..=20)).changed() {
203+
if ui
204+
.add(egui::DragValue::new(&mut width).range(3..=20))
205+
.changed()
206+
{
211207
editor.set_grid_size(width as u32, height as u32);
212208
}
213209
});
214210

215211
ui.horizontal(|ui| {
216212
ui.label("Height:");
217-
if ui.add(egui::DragValue::new(&mut height).range(3..=20)).changed() {
213+
if ui
214+
.add(egui::DragValue::new(&mut height).range(3..=20))
215+
.changed()
216+
{
218217
editor.set_grid_size(width as u32, height as u32);
219218
}
220219
});
@@ -396,10 +395,7 @@ pub fn editor_input_system(
396395
}
397396

398397
/// Spawn editor grid visualization
399-
pub fn spawn_editor_grid(
400-
mut commands: Commands,
401-
editor: Res<EditorState>,
402-
) {
398+
pub fn spawn_editor_grid(mut commands: Commands, editor: Res<EditorState>) {
403399
let half_width = editor.grid_width as f32 / 2.0;
404400
let half_height = editor.grid_height as f32 / 2.0;
405401

src/game/validation.rs

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,20 @@ use super::{BoardState, GoalCondition, Level, LogicPiece};
1010
#[derive(Debug, Clone, PartialEq, Eq)]
1111
pub enum ValidationError {
1212
/// Piece is placed outside board boundaries.
13-
OutOfBounds { x: u32, y: u32, max_x: u32, max_y: u32 },
13+
OutOfBounds {
14+
x: u32,
15+
y: u32,
16+
max_x: u32,
17+
max_y: u32,
18+
},
1419
/// Two pieces occupy the same position.
1520
OverlappingPieces { position: (u32, u32) },
1621
/// Wire endpoints are invalid.
17-
InvalidWire { from: (u32, u32), to: (u32, u32), reason: String },
22+
InvalidWire {
23+
from: (u32, u32),
24+
to: (u32, u32),
25+
reason: String,
26+
},
1827
/// No goals defined on the board.
1928
NoGoals,
2029
/// No assumptions defined on the board.
@@ -62,7 +71,10 @@ impl ValidationResult {
6271
}
6372

6473
/// Validate a piece placement on the board.
65-
pub fn validate_piece_placement(board: &BoardState, piece: &LogicPiece) -> Result<(), ValidationError> {
74+
pub fn validate_piece_placement(
75+
board: &BoardState,
76+
piece: &LogicPiece,
77+
) -> Result<(), ValidationError> {
6678
let (x, y) = piece.position();
6779

6880
// Check bounds
@@ -118,7 +130,11 @@ pub fn validate_piece_placement(board: &BoardState, piece: &LogicPiece) -> Resul
118130
});
119131
}
120132
// Basic formula validation: must start with alphanumeric or parenthesis
121-
if !formula.chars().next().map_or(false, |c| c.is_alphanumeric() || c == '(') {
133+
if !formula
134+
.chars()
135+
.next()
136+
.map_or(false, |c| c.is_alphanumeric() || c == '(')
137+
{
122138
return Err(ValidationError::InvalidFormula {
123139
formula: formula.clone(),
124140
reason: "Formula must start with identifier or parenthesis".to_string(),
@@ -161,8 +177,14 @@ pub fn validate_board(board: &BoardState) -> ValidationResult {
161177
}
162178

163179
// Check for at least one assumption and one goal
164-
let has_assumptions = board.pieces.iter().any(|p| matches!(p, LogicPiece::Assumption { .. }));
165-
let has_goals = board.pieces.iter().any(|p| matches!(p, LogicPiece::Goal { .. }));
180+
let has_assumptions = board
181+
.pieces
182+
.iter()
183+
.any(|p| matches!(p, LogicPiece::Assumption { .. }));
184+
let has_goals = board
185+
.pieces
186+
.iter()
187+
.any(|p| matches!(p, LogicPiece::Goal { .. }));
166188

167189
if !has_assumptions {
168190
errors.push(ValidationError::NoAssumptions);
@@ -221,7 +243,10 @@ pub fn validate_level(level: &Level) -> ValidationResult {
221243
match &level.goal_state {
222244
GoalCondition::ConnectNodes { start, end } => {
223245
if start.0 >= level.initial_state.width || start.1 >= level.initial_state.height {
224-
warnings.push(format!("Goal start node {:?} is outside board bounds", start));
246+
warnings.push(format!(
247+
"Goal start node {:?} is outside board bounds",
248+
start
249+
));
225250
}
226251
if end.0 >= level.initial_state.width || end.1 >= level.initial_state.height {
227252
warnings.push(format!("Goal end node {:?} is outside board bounds", end));
@@ -296,11 +321,16 @@ mod tests {
296321
#[test]
297322
fn test_out_of_bounds() {
298323
let mut board = make_test_board();
299-
board.pieces.push(LogicPiece::OrIntro { position: (15, 15) });
324+
board
325+
.pieces
326+
.push(LogicPiece::OrIntro { position: (15, 15) });
300327

301328
let result = validate_board(&board);
302329
assert!(!result.is_valid);
303-
assert!(result.errors.iter().any(|e| matches!(e, ValidationError::OutOfBounds { .. })));
330+
assert!(result
331+
.errors
332+
.iter()
333+
.any(|e| matches!(e, ValidationError::OutOfBounds { .. })));
304334
}
305335

306336
#[test]
@@ -310,7 +340,10 @@ mod tests {
310340

311341
let result = validate_board(&board);
312342
assert!(!result.is_valid);
313-
assert!(result.errors.iter().any(|e| matches!(e, ValidationError::OverlappingPieces { .. })));
343+
assert!(result
344+
.errors
345+
.iter()
346+
.any(|e| matches!(e, ValidationError::OverlappingPieces { .. })));
314347
}
315348

316349
#[test]
@@ -326,7 +359,10 @@ mod tests {
326359

327360
let result = validate_board(&board);
328361
assert!(!result.is_valid);
329-
assert!(result.errors.iter().any(|e| matches!(e, ValidationError::NoAssumptions)));
362+
assert!(result
363+
.errors
364+
.iter()
365+
.any(|e| matches!(e, ValidationError::NoAssumptions)));
330366
}
331367

332368
#[test]

0 commit comments

Comments
 (0)