Skip to main content

ralph/queue/validation/
mod.rs

1//! Queue validation facade.
2//!
3//! Responsibilities:
4//! - Expose queue validation entrypoints and warning types.
5//! - Coordinate queue-file checks with dependency, relationship, and parent validators.
6//! - Keep shared validation data structures local to this module tree.
7//!
8//! Not handled here:
9//! - Queue persistence or mutation workflows.
10//! - Config validation or CLI reporting.
11//!
12//! Invariants/assumptions:
13//! - Task IDs are unique within a queue file and across active/done files, except rejected tasks.
14//! - Dependency and blocking graphs must remain acyclic.
15//! - Warnings are non-blocking and may be logged separately by callers.
16
17mod dependency_graph;
18mod parent;
19mod queue_files;
20mod relationships;
21mod shared;
22mod task_fields;
23
24use anyhow::Result;
25
26pub(crate) use task_fields::validate_task_id;
27
28/// Represents a validation issue that doesn't prevent queue operation but should be reported.
29#[derive(Debug, Clone)]
30pub struct ValidationWarning {
31    pub task_id: String,
32    pub message: String,
33}
34
35impl ValidationWarning {
36    /// Log this warning using the standard logging framework.
37    pub fn log(&self) {
38        log::warn!("[{}] {}", self.task_id, self.message);
39    }
40}
41
42/// Log all validation warnings.
43pub fn log_warnings(warnings: &[ValidationWarning]) {
44    for warning in warnings {
45        warning.log();
46    }
47}
48
49/// Result of dependency and relationship validation containing warnings.
50#[derive(Debug, Default)]
51pub struct DependencyValidationResult {
52    pub warnings: Vec<ValidationWarning>,
53}
54
55/// Validate a single queue file.
56pub fn validate_queue(
57    queue: &crate::contracts::QueueFile,
58    id_prefix: &str,
59    id_width: usize,
60) -> Result<()> {
61    queue_files::validate_queue(queue, id_prefix, id_width)
62}
63
64/// Validate active and optional done queues together, returning non-blocking warnings.
65pub fn validate_queue_set(
66    active: &crate::contracts::QueueFile,
67    done: Option<&crate::contracts::QueueFile>,
68    id_prefix: &str,
69    id_width: usize,
70    max_dependency_depth: u8,
71) -> Result<Vec<ValidationWarning>> {
72    queue_files::validate_queue(active, id_prefix, id_width)?;
73    queue_files::validate_done_queue(done, id_prefix, id_width)?;
74    queue_files::validate_cross_file_duplicates(active, done)?;
75
76    let catalog = shared::TaskCatalog::new(active, done);
77    let mut result = DependencyValidationResult::default();
78
79    dependency_graph::validate_dependency_graph(&catalog, max_dependency_depth, &mut result)?;
80    relationships::validate_relationships(&catalog, &mut result)?;
81    parent::validate_parent_ids(&catalog, &mut result)?;
82
83    Ok(result.warnings)
84}
85
86#[cfg(test)]
87mod tests;