perf(ingest,cli): derive archive bounds from the monthly file index — probe_window drain retired
probe_window drained a source's entire close column just to learn its first and last bar timestamp; both live callers (open_real_source and campaign_window_ms on the campaign trunk) now resolve through aura-ingest's new archive_extent(): list the symbol's SYM_YYYY_MM.m1 files, load only the boundary months via the existing loader seam, and walk across gap months forward/backward — O(2 file loads) typical instead of O(archive). Empty-window refusal semantics are unchanged (pinned). Two characterization tests captured the resolved windows against the OLD implementation over the synthetic per-test archive and stay green unchanged after the swap. Measured: the probe itself drops 366ms -> 13ms (~28x) on the full 2014-2026 GER40 archive; end-to-end command wall-clock moves only ~2-3% because the sim loop dominates — the fix removes an O(archive-size) term, not the dominant cost. closes #252
This commit is contained in:
@@ -5694,6 +5694,141 @@ fn shipped_r_sma_example_reproduces_the_builtin_grade() {
|
||||
assert!(stdout.contains("\"n_trades\":3"), "{stdout}");
|
||||
}
|
||||
|
||||
/// Characterization pin (#252, byte-identity anchor before `probe_window`'s
|
||||
/// internals swap from a full-window drain to `aura_ingest::archive_extent`'s
|
||||
/// boundary-month derivation). Captured against the PRE-#252 drain-based code
|
||||
/// over `fresh_project_with_data`'s hermetic two-symbol synthetic archive
|
||||
/// (SYMA spans 2024-01..08, SYMB 2024-03..06, weekday 08:00-16:00 UTC bars):
|
||||
/// the resolved `campaign_window_ms(full_window)` span persists verbatim into
|
||||
/// the generated campaign document's `data.windows[0]`, exactly like the
|
||||
/// sibling `generalize_without_explicit_window_resolves_the_intersection_of_all_symbols`
|
||||
/// probe. Three cases: SYMA's and SYMB's full (no-window) spans, and an
|
||||
/// explicit `--from`/`--to` sub-window straddling three month files
|
||||
/// (2024-03-15..2024-05-15, so `filter_files` alone would load 3 files under
|
||||
/// the old drain). The first bar of each captured span carries a known -1ms
|
||||
/// float round-trip artifact (the synthetic fixture's Delphi-`TDateTime`
|
||||
/// pack/unpack in `data-server`'s own record format, not a `probe_window` bug)
|
||||
/// — this test does not explain it, only pins it exactly, since the
|
||||
/// post-swap code must reproduce the identical bytes (same underlying decoder,
|
||||
/// only fewer files touched to reach them).
|
||||
#[test]
|
||||
fn probe_window_resolves_the_pinned_span_before_the_252_swap() {
|
||||
let (cwd, _g) = fresh_project_with_data();
|
||||
let fixture = format!("{}/examples/r_sma.json", env!("CARGO_MANIFEST_DIR"));
|
||||
let window_of = |name: &str| -> (i64, i64) {
|
||||
let dir = cwd.join("runs").join("campaigns");
|
||||
let path = std::fs::read_dir(&dir)
|
||||
.expect("campaigns dir exists after a run")
|
||||
.filter_map(|e| e.ok())
|
||||
.map(|e| e.path())
|
||||
.find(|p| {
|
||||
let doc: serde_json::Value =
|
||||
serde_json::from_str(&std::fs::read_to_string(p).expect("read campaign doc"))
|
||||
.expect("campaign doc parses as JSON");
|
||||
doc["name"].as_str() == Some(name)
|
||||
})
|
||||
.unwrap_or_else(|| panic!("no campaign document named {name:?} in {}", dir.display()));
|
||||
let doc: serde_json::Value =
|
||||
serde_json::from_str(&std::fs::read_to_string(&path).expect("read campaign doc"))
|
||||
.expect("campaign doc parses as JSON");
|
||||
let w = &doc["data"]["windows"][0];
|
||||
(
|
||||
w["from_ms"].as_i64().expect("from_ms is an integer"),
|
||||
w["to_ms"].as_i64().expect("to_ms is an integer"),
|
||||
)
|
||||
};
|
||||
let sweep = |symbol: &str, name: &str, from: Option<&str>, to: Option<&str>| {
|
||||
let mut args = vec![
|
||||
"sweep", fixture.as_str(), "--real", symbol,
|
||||
"--axis", "sma_signal.fast.length=3", "--axis", "sma_signal.slow.length=12",
|
||||
"--name", name,
|
||||
];
|
||||
if let Some(f) = from {
|
||||
args.push("--from");
|
||||
args.push(f);
|
||||
}
|
||||
if let Some(t) = to {
|
||||
args.push("--to");
|
||||
args.push(t);
|
||||
}
|
||||
let out = std::process::Command::new(env!("CARGO_BIN_EXE_aura"))
|
||||
.args(&args)
|
||||
.current_dir(&cwd)
|
||||
.output()
|
||||
.expect("spawn aura sweep");
|
||||
assert_eq!(
|
||||
out.status.code(), Some(0),
|
||||
"window-probe sweep {name:?} must run to exit 0: {}",
|
||||
String::from_utf8_lossy(&out.stderr)
|
||||
);
|
||||
};
|
||||
|
||||
sweep("SYMA", "probe-252-no-window-syma", None, None);
|
||||
assert_eq!(
|
||||
window_of("probe-252-no-window-syma"),
|
||||
(1_704_095_999_999, 1_725_033_540_000),
|
||||
"SYMA's full (no-window) resolved span"
|
||||
);
|
||||
|
||||
sweep("SYMB", "probe-252-no-window-symb", None, None);
|
||||
assert_eq!(
|
||||
window_of("probe-252-no-window-symb"),
|
||||
(1_709_279_999_999, 1_719_590_340_000),
|
||||
"SYMB's full (no-window) resolved span"
|
||||
);
|
||||
|
||||
// 2024-03-15 00:00 UTC .. 2024-05-15 00:00 UTC: straddles the March, April,
|
||||
// and May files (three boundary months under the old file-range drain).
|
||||
sweep("SYMA", "probe-252-straddle", Some("1710460800000"), Some("1715731200000"));
|
||||
assert_eq!(
|
||||
window_of("probe-252-straddle"),
|
||||
(1_710_489_599_999, 1_715_702_340_000),
|
||||
"explicit sub-window straddling month boundaries, clipped to the archive's actual bars"
|
||||
);
|
||||
}
|
||||
|
||||
/// Characterization pin (#252, hostless zero-bar case): a window that falls
|
||||
/// entirely on a weekend inside a COVERED month (2024-03-02/03, both inside
|
||||
/// SYMA's Jan-Aug 2024 span, weekday-only bars) still refuses with the SAME
|
||||
/// exit-1 "no data ... in the requested window" message `probe_window`'s
|
||||
/// drain-based emptiness check raises today — `archive_extent` must reach the
|
||||
/// identical conclusion by finding zero matching months in range, not by
|
||||
/// draining a stream, and the refusal wording is part of what must not move
|
||||
/// (mirrors `run_real_empty_window_refusal_names_the_window_not_the_symbol`,
|
||||
/// hostless here since the property (an empty resolved sub-window still
|
||||
/// refuses) needs no full archive, only a covered-but-empty range).
|
||||
#[test]
|
||||
fn probe_window_still_refuses_a_hostless_zero_bar_window() {
|
||||
let (cwd, _g) = fresh_project_with_data();
|
||||
let fixture = format!("{}/examples/r_sma.json", env!("CARGO_MANIFEST_DIR"));
|
||||
let out = std::process::Command::new(env!("CARGO_BIN_EXE_aura"))
|
||||
.args([
|
||||
"sweep", &fixture, "--real", "SYMA",
|
||||
"--axis", "sma_signal.fast.length=3", "--axis", "sma_signal.slow.length=12",
|
||||
"--name", "probe-252-zero-bars",
|
||||
"--from", "1709337600000", // 2024-03-02 00:00 UTC (Saturday)
|
||||
"--to", "1709424000000", // 2024-03-03 00:00 UTC (Sunday)
|
||||
])
|
||||
.current_dir(&cwd)
|
||||
.output()
|
||||
.expect("spawn aura sweep");
|
||||
assert_eq!(
|
||||
out.status.code(), Some(1),
|
||||
"a zero-bar window inside covered archive months still refuses with exit 1: stderr={}",
|
||||
String::from_utf8_lossy(&out.stderr)
|
||||
);
|
||||
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||
assert!(
|
||||
stderr.contains("no data") && stderr.contains("window"),
|
||||
"must name the empty window, not a missing symbol: {stderr}"
|
||||
);
|
||||
assert!(
|
||||
!cwd.join("runs").join("campaigns").exists()
|
||||
|| std::fs::read_dir(cwd.join("runs").join("campaigns")).unwrap().count() == 0,
|
||||
"a refused zero-bar window must not register a generated campaign document"
|
||||
);
|
||||
}
|
||||
|
||||
/// `aura run` on the shipped closed r-meanrev example (#159 cut 3) actually loads
|
||||
/// and grades through the real, separately-linked `aura` binary — not merely
|
||||
/// in-process, as `r_meanrev_example_loaded_runs_identically_to_the_carved_signal`
|
||||
|
||||
Reference in New Issue
Block a user