Skip to content

Commit d10af84

Browse files
Merge pull request #73 from PromptExecution/feat/workspace-core-updates-20260503-134158
feat: checkpoint workspace core updates
2 parents 63e3200 + 5a44339 commit d10af84

76 files changed

Lines changed: 2108 additions & 1196 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

crates/arc-kit-au/src/badge.rs

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,7 @@ impl From<&EvidenceChain> for ProvenanceBadge {
6565
let critical_missing: Vec<_> = missing
6666
.iter()
6767
.filter(|m| {
68-
**m == "source_document"
69-
|| **m == "classification"
70-
|| **m == "extracted_rows"
68+
**m == "source_document" || **m == "classification" || **m == "extracted_rows"
7169
})
7270
.map(|s| s.to_string())
7371
.collect();
@@ -86,8 +84,8 @@ impl From<&EvidenceChain> for ProvenanceBadge {
8684

8785
#[cfg(test)]
8886
mod tests {
89-
use crate::node::Confidence;
9087
use super::*;
88+
use crate::node::Confidence;
9189
use crate::node::{EvidenceNode, NodeId, NodeType, SourceDoc};
9290
use chrono::TimeZone;
9391
use chrono::Utc;
@@ -146,18 +144,16 @@ mod tests {
146144
source_document: NodeId::new(NodeType::SourceDoc, "abc"),
147145
extraction_confidence: Confidence::from(0.95),
148146
})],
149-
classifications: vec![EvidenceNode::Classification(
150-
crate::node::Classification {
151-
tx_id: "tx_1".to_string(),
152-
category: "Meals".to_string(),
153-
sub_category: None,
154-
confidence: Confidence::from(0.92),
155-
rule_used: None,
156-
actor: "operator".to_string(),
157-
classified_at: Utc.with_ymd_and_hms(2024, 2, 1, 11, 0, 0).unwrap(),
158-
note: None,
159-
},
160-
)],
147+
classifications: vec![EvidenceNode::Classification(crate::node::Classification {
148+
tx_id: "tx_1".to_string(),
149+
category: "Meals".to_string(),
150+
sub_category: None,
151+
confidence: Confidence::from(0.92),
152+
rule_used: None,
153+
actor: "operator".to_string(),
154+
classified_at: Utc.with_ymd_and_hms(2024, 2, 1, 11, 0, 0).unwrap(),
155+
note: None,
156+
})],
161157
proposals: vec![],
162158
approvals: vec![EvidenceNode::OperatorApproval(
163159
crate::node::OperatorApproval {
@@ -204,18 +200,16 @@ mod tests {
204200
tx_id: "tx_3".to_string(),
205201
source_documents: vec![],
206202
extracted_rows: vec![],
207-
classifications: vec![EvidenceNode::Classification(
208-
crate::node::Classification {
209-
tx_id: "tx_3".to_string(),
210-
category: "Meals".to_string(),
211-
sub_category: None,
212-
confidence: Confidence::from(0.92),
213-
rule_used: None,
214-
actor: "operator".to_string(),
215-
classified_at: Utc.with_ymd_and_hms(2024, 2, 1, 11, 0, 0).unwrap(),
216-
note: None,
217-
},
218-
)],
203+
classifications: vec![EvidenceNode::Classification(crate::node::Classification {
204+
tx_id: "tx_3".to_string(),
205+
category: "Meals".to_string(),
206+
sub_category: None,
207+
confidence: Confidence::from(0.92),
208+
rule_used: None,
209+
actor: "operator".to_string(),
210+
classified_at: Utc.with_ymd_and_hms(2024, 2, 1, 11, 0, 0).unwrap(),
211+
note: None,
212+
})],
219213
proposals: vec![],
220214
approvals: vec![EvidenceNode::OperatorApproval(
221215
crate::node::OperatorApproval {

crates/arc-kit-au/src/builder.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
//! Provides a fluent API for building evidence chains from ingest,
44
//! classify, approve, and export operations.
55
6-
76
use crate::edge::EdgeType;
87
use crate::graph::EvidenceGraph;
98
use crate::node::{
@@ -76,7 +75,8 @@ impl<'a> EvidenceBuilder<'a> {
7675
pub fn ensure_proposal(&mut self, proposal: ModelProposal) -> NodeId {
7776
let prop_id = proposal.node_id();
7877
let tx_id = NodeId::new(NodeType::Transaction, &proposal.tx_id);
79-
self.graph.ensure_node(EvidenceNode::ModelProposal(proposal));
78+
self.graph
79+
.ensure_node(EvidenceNode::ModelProposal(proposal));
8080
self.graph
8181
.ensure_edge(tx_id, prop_id.clone(), EdgeType::ProposedBy);
8282
prop_id
@@ -98,16 +98,16 @@ impl<'a> EvidenceBuilder<'a> {
9898
let wb_id = wb_row.node_id();
9999
let tx_id = NodeId::new(NodeType::Transaction, &wb_row.tx_id);
100100
self.graph.ensure_node(EvidenceNode::WorkbookRow(wb_row));
101-
self.graph.ensure_edge(tx_id, wb_id.clone(), EdgeType::ExportedTo);
101+
self.graph
102+
.ensure_edge(tx_id, wb_id.clone(), EdgeType::ExportedTo);
102103
wb_id
103104
}
104105

105106
/// Idempotent: ensure a validation issue node with ValidatedAs edge.
106107
pub fn ensure_validation_issue(&mut self, issue: ValidationIssue) -> NodeId {
107108
let vi_id = issue.node_id();
108109
let tx_id = NodeId::new(NodeType::Transaction, &issue.tx_id);
109-
self.graph
110-
.ensure_node(EvidenceNode::ValidationIssue(issue));
110+
self.graph.ensure_node(EvidenceNode::ValidationIssue(issue));
111111
self.graph
112112
.ensure_edge(tx_id, vi_id.clone(), EdgeType::ValidatedAs);
113113
vi_id
@@ -133,8 +133,8 @@ impl<'a> EvidenceBuilder<'a> {
133133

134134
#[cfg(test)]
135135
mod tests {
136-
use crate::node::Confidence;
137136
use super::*;
137+
use crate::node::Confidence;
138138
use chrono::{TimeZone, Utc};
139139
use rust_decimal::Decimal;
140140

crates/arc-kit-au/src/edge.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,18 @@ pub struct EvidenceEdge {
5656

5757
impl EvidenceEdge {
5858
pub fn new(from: NodeId, to: NodeId, edge_type: EdgeType) -> Self {
59-
Self { from, to, edge_type }
59+
Self {
60+
from,
61+
to,
62+
edge_type,
63+
}
6064
}
6165
}
6266

6367
/// Edge traversal utilities.
6468
pub trait EdgeTraversal {
6569
/// Find all edges of a specific type from a node.
66-
fn edges_of_type<'a>(
67-
&'a self,
68-
from: &'a NodeId,
69-
edge_type: EdgeType,
70-
) -> Vec<&'a EvidenceEdge>;
70+
fn edges_of_type<'a>(&'a self, from: &'a NodeId, edge_type: EdgeType) -> Vec<&'a EvidenceEdge>;
7171

7272
/// Find all incoming edges to a node.
7373
fn incoming_edges<'a>(&'a self, to: &'a NodeId) -> Vec<&'a EvidenceEdge>;

crates/arc-kit-au/src/graph.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,18 @@ impl EvidenceGraph {
104104

105105
/// Get all nodes of a specific type.
106106
pub fn nodes_of_type(&self, node_type: NodeType) -> Vec<&EvidenceNode> {
107-
self.nodes.iter().filter(|n| n.node_type() == node_type).collect()
107+
self.nodes
108+
.iter()
109+
.filter(|n| n.node_type() == node_type)
110+
.collect()
108111
}
109112

110113
/// Get all edges of a specific type.
111114
pub fn edges_of_type(&self, edge_type: EdgeType) -> Vec<&EvidenceEdge> {
112-
self.edges.iter().filter(|e| e.edge_type == edge_type).collect()
115+
self.edges
116+
.iter()
117+
.filter(|e| e.edge_type == edge_type)
118+
.collect()
113119
}
114120

115121
/// Find all outgoing edges from a node.
@@ -358,9 +364,7 @@ mod tests {
358364
let tx = test_tx();
359365
let doc_id = graph.add_node(EvidenceNode::SourceDoc(doc)).unwrap();
360366
let tx_id = graph.add_node(EvidenceNode::Transaction(tx)).unwrap();
361-
graph
362-
.add_edge(doc_id, tx_id, EdgeType::Produces)
363-
.unwrap();
367+
graph.add_edge(doc_id, tx_id, EdgeType::Produces).unwrap();
364368

365369
let json = graph.to_json().unwrap();
366370
let restored = EvidenceGraph::from_json(&json).unwrap();

crates/arc-kit-au/src/lib.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,20 @@
2525
//! assert!(restored.is_empty());
2626
//! ```
2727
28-
pub mod node;
28+
pub mod badge;
29+
pub mod builder;
2930
pub mod edge;
3031
pub mod graph;
31-
pub mod builder;
32-
pub mod trace;
3332
pub mod missing;
34-
pub mod badge;
33+
pub mod node;
3534
pub mod store;
35+
pub mod trace;
3636

37-
pub use node::{Confidence, EvidenceNode, NodeId, NodeType};
38-
pub use edge::{EvidenceEdge, EdgeType};
39-
pub use graph::{EvidenceGraph, WorkQueueSummary};
37+
pub use badge::ProvenanceBadge;
4038
pub use builder::EvidenceBuilder;
41-
pub use trace::{EvidenceChain, EvidenceTracer};
39+
pub use edge::{EdgeType, EvidenceEdge};
40+
pub use graph::{EvidenceGraph, WorkQueueSummary};
4241
pub use missing::{MissingElement, ProvenanceGap, ProvenanceScanner};
43-
pub use badge::ProvenanceBadge;
42+
pub use node::{Confidence, EvidenceNode, NodeId, NodeType};
4443
pub use store::EvidenceStore;
44+
pub use trace::{EvidenceChain, EvidenceTracer};

crates/arc-kit-au/src/missing.rs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,7 @@ impl ProvenanceScanner for EvidenceGraph {
7676

7777
// Check incoming edges for source rows
7878
let incoming = self.incoming_edges(&tx_node_id);
79-
let has_rows = incoming
80-
.iter()
81-
.any(|e| e.edge_type == EdgeType::Produces);
79+
let has_rows = incoming.iter().any(|e| e.edge_type == EdgeType::Produces);
8280

8381
if has_rows {
8482
// Check if rows have source documents
@@ -156,9 +154,9 @@ impl ProvenanceScanner for EvidenceGraph {
156154

157155
#[cfg(test)]
158156
mod tests {
159-
use crate::node::Confidence;
160157
use super::*;
161158
use crate::builder::EvidenceBuilder;
159+
use crate::node::Confidence;
162160
use crate::node::{Classification, ExtractedRow, NodeId, SourceDoc, Transaction};
163161
use chrono::TimeZone;
164162
use chrono::Utc;
@@ -228,9 +226,7 @@ mod tests {
228226
// build_full_chain doesn't create approvals or exports, so those will be gaps
229227
let gaps = graph.find_missing_provenance();
230228
assert_eq!(gaps.len(), 1);
231-
assert!(gaps[0]
232-
.missing
233-
.contains(&MissingElement::OperatorApproval));
229+
assert!(gaps[0].missing.contains(&MissingElement::OperatorApproval));
234230
assert!(gaps[0].missing.contains(&MissingElement::WorkbookExport));
235231
// But source and classification should be present
236232
assert!(!gaps[0].missing.contains(&MissingElement::SourceDocument));
@@ -254,12 +250,8 @@ mod tests {
254250

255251
let gaps = graph.find_missing_provenance();
256252
assert_eq!(gaps.len(), 1);
257-
assert!(gaps[0]
258-
.missing
259-
.contains(&MissingElement::Classification));
260-
assert!(gaps[0]
261-
.missing
262-
.contains(&MissingElement::OperatorApproval));
253+
assert!(gaps[0].missing.contains(&MissingElement::Classification));
254+
assert!(gaps[0].missing.contains(&MissingElement::OperatorApproval));
263255
assert!(gaps[0].missing.contains(&MissingElement::WorkbookExport));
264256
}
265257

@@ -293,11 +285,17 @@ mod tests {
293285

294286
#[test]
295287
fn missing_element_display_format() {
296-
assert_eq!(MissingElement::SourceDocument.to_string(), "source_document");
288+
assert_eq!(
289+
MissingElement::SourceDocument.to_string(),
290+
"source_document"
291+
);
297292
assert_eq!(
298293
MissingElement::OperatorApproval.to_string(),
299294
"operator_approval"
300295
);
301-
assert_eq!(MissingElement::WorkbookExport.to_string(), "workbook_export");
296+
assert_eq!(
297+
MissingElement::WorkbookExport.to_string(),
298+
"workbook_export"
299+
);
302300
}
303301
}

crates/arc-kit-au/src/store.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,9 @@ impl EvidenceStore {
113113

114114
#[cfg(test)]
115115
mod tests {
116-
use crate::node::Confidence;
117116
use super::*;
118117
use crate::builder::EvidenceBuilder;
118+
use crate::node::Confidence;
119119
use crate::node::{Classification, ExtractedRow, SourceDoc, Transaction};
120120
use chrono::TimeZone;
121121
use chrono::Utc;

crates/arc-kit-au/src/trace.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,9 @@ impl EvidenceTracer for EvidenceGraph {
158158

159159
#[cfg(test)]
160160
mod tests {
161-
use crate::node::Confidence;
162161
use super::*;
163162
use crate::builder::EvidenceBuilder;
163+
use crate::node::Confidence;
164164
use crate::node::{Classification, ExtractedRow, OperatorApproval, SourceDoc, Transaction};
165165
use chrono::TimeZone;
166166
use chrono::Utc;

crates/b00t-iface/src/core/governance.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,11 @@ impl GovernancePolicy {
7171
/// Solver-friendly encoding as a serializable constraint set.
7272
pub fn to_constraints(&self) -> GovernanceConstraints {
7373
GovernanceConstraints {
74-
allowed_starters: self.allowed_starters.iter().map(|r| r.to_string()).collect(),
74+
allowed_starters: self
75+
.allowed_starters
76+
.iter()
77+
.map(|r| r.to_string())
78+
.collect(),
7579
max_ttl_secs: self.max_ttl.as_secs(),
7680
auto_restart: self.auto_restart,
7781
crash_budget: self.crash_budget,

crates/b00t-iface/src/core/machine.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@
3636
//! ```
3737
3838
use super::surface::{AuditRecord, MaintenanceAction};
39-
use std::time::Duration;
4039
use std::fmt;
40+
use std::time::Duration;
4141

4242
/// The finite set of states a surface machine can be in.
4343
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -114,7 +114,11 @@ impl SurfaceMachine {
114114
}
115115

116116
/// Attempt a transition. Returns the trigger label if valid.
117-
pub fn transition(&mut self, to: MachineState, elapsed: Duration) -> Result<&'static str, String> {
117+
pub fn transition(
118+
&mut self,
119+
to: MachineState,
120+
elapsed: Duration,
121+
) -> Result<&'static str, String> {
118122
let trigger = valid_transition(self.state, to)
119123
.ok_or_else(|| format!("invalid transition: {} → {}", self.state, to))?;
120124

@@ -130,7 +134,11 @@ impl SurfaceMachine {
130134
}
131135

132136
/// Process a maintenance action and transition accordingly.
133-
pub fn apply_maintenance(&mut self, action: &MaintenanceAction, elapsed: Duration) -> Result<(), String> {
137+
pub fn apply_maintenance(
138+
&mut self,
139+
action: &MaintenanceAction,
140+
elapsed: Duration,
141+
) -> Result<(), String> {
134142
match action {
135143
MaintenanceAction::NoOp => {
136144
self.transition(MachineState::Healthy, elapsed)?;
@@ -163,18 +171,24 @@ mod tests {
163171
#[test]
164172
fn valid_lifecycle() {
165173
let mut m = SurfaceMachine::new("test");
166-
m.transition(MachineState::Ready, Duration::from_millis(10)).unwrap();
167-
m.transition(MachineState::Running, Duration::from_millis(50)).unwrap();
168-
m.apply_maintenance(&MaintenanceAction::NoOp, Duration::from_millis(5)).unwrap();
169-
m.transition(MachineState::Terminated, Duration::from_millis(20)).unwrap();
174+
m.transition(MachineState::Ready, Duration::from_millis(10))
175+
.unwrap();
176+
m.transition(MachineState::Running, Duration::from_millis(50))
177+
.unwrap();
178+
m.apply_maintenance(&MaintenanceAction::NoOp, Duration::from_millis(5))
179+
.unwrap();
180+
m.transition(MachineState::Terminated, Duration::from_millis(20))
181+
.unwrap();
170182
assert!(m.is_terminal());
171183
assert_eq!(m.transitions.len(), 4);
172184
}
173185

174186
#[test]
175187
fn invalid_transition_fails() {
176188
let mut m = SurfaceMachine::new("test");
177-
let err = m.transition(MachineState::Running, Duration::ZERO).unwrap_err();
189+
let err = m
190+
.transition(MachineState::Running, Duration::ZERO)
191+
.unwrap_err();
178192
assert!(err.contains("invalid transition"));
179193
}
180194

@@ -203,7 +217,8 @@ mod tests {
203217
let mut m = SurfaceMachine::new("test");
204218
m.transition(MachineState::Ready, Duration::ZERO).unwrap();
205219
m.transition(MachineState::Running, Duration::ZERO).unwrap();
206-
m.apply_maintenance(&MaintenanceAction::Restart, Duration::ZERO).unwrap();
220+
m.apply_maintenance(&MaintenanceAction::Restart, Duration::ZERO)
221+
.unwrap();
207222
assert_eq!(m.crash_count, 1);
208223
assert_eq!(m.state, MachineState::Ready);
209224
}

0 commit comments

Comments
 (0)