Tracker sweep + executor robustness: net-R chain, archive inventory, std::grid, per-cell fault isolation (12 issues) #270

Merged
claude merged 25 commits from worktree-boss-tracker-sweep-258 into main 2026-07-14 17:12:58 +02:00
Showing only changes of commit 5b70bd60a5 - Show all commits
+50
View File
@@ -2740,6 +2740,8 @@ struct DataCmd {
enum DataCommand {
/// Report a symbol's monthly file-index coverage (span + interior gaps).
Coverage(DataCoverageCmd),
/// List the archive's known symbols, sorted, one per line.
List,
}
#[derive(Args)]
@@ -3674,9 +3676,37 @@ fn dispatch_nodes_new(a: NodesNewCmd) {
fn dispatch_data(cmd: DataCmd, env: &project::Env) {
match cmd.command {
DataCommand::Coverage(a) => dispatch_data_coverage(a, env),
DataCommand::List => dispatch_data_list(env),
}
}
/// `aura data list` (#264 cut 2): print the archive's known symbols, sorted
/// ascending, one per line — the discovery step before `aura data coverage`
/// or scoping a campaign's instrument matrix. Resolves the archive root
/// through the normal project path ([`dispatch_data_coverage`]'s
/// `Env::data_path`), then reuses `DataServer`'s own symbol index
/// (`DataServer::symbols()`, already sorted) rather than re-deriving a
/// directory scan. An empty or absent archive is informational absence, not a
/// fault: a `no symbols` prose line, exit 0 (the verb corpus's established
/// empty-result register — cf. `runs family`'s unknown-id empty exit 0).
fn dispatch_data_list(env: &project::Env) {
let data_path = std::path::PathBuf::from(env.data_path());
let server = aura_ingest::DataServer::new(&data_path);
for line in data_list_report(&server.symbols()) {
println!("{line}");
}
}
/// Pure: render `symbols` (already sorted by `DataServer::symbols()`) as one
/// line per symbol, or a single `no symbols` line when the archive is empty
/// or absent — informational absence, never a fault (#264).
fn data_list_report(symbols: &[std::sync::Arc<str>]) -> Vec<String> {
if symbols.is_empty() {
return vec!["no symbols".to_string()];
}
symbols.iter().map(|s| s.to_string()).collect()
}
/// `aura data coverage <SYMBOL>` (#264 cut 1): print the archive's month
/// coverage for `SYMBOL` — the Copper failure mode (files present at both
/// ends of a window while an interior month is missing, so a first/last-bounds
@@ -4203,6 +4233,26 @@ mod tests {
);
}
/// An empty (or absent) archive is informational absence, not a fault
/// (#264): `data_list_report` returns the single `no symbols` prose line
/// rather than an empty `Vec`, so the caller's exit-0 println always has
/// something to say.
#[test]
fn data_list_report_of_an_empty_archive_is_a_no_symbols_line() {
let symbols: Vec<std::sync::Arc<str>> = vec![];
assert_eq!(data_list_report(&symbols), vec!["no symbols".to_string()]);
}
/// A non-empty archive renders one line per symbol, in the order handed
/// in (`DataServer::symbols()` already sorts) — no `no symbols` line
/// mixed in (#264).
#[test]
fn data_list_report_of_a_populated_archive_is_one_line_per_symbol() {
let symbols: Vec<std::sync::Arc<str>> =
vec![std::sync::Arc::from("SYMA"), std::sync::Arc::from("SYMB")];
assert_eq!(data_list_report(&symbols), vec!["SYMA".to_string(), "SYMB".to_string()]);
}
/// Disjoint archives (no shared instant across all listed symbols) refuse
/// rather than silently pooling a floor over different periods per
/// instrument (#213); the error names each symbol next to its own span,