fix(cli): empty --real window refuses naming the window, not the symbol

probe_window's two empty-result exits now route through a distinct
no_data_in_window refusal (requested bounds + archive path); its callers
have already proven the symbol present via has_symbol, so the old
"no local data for symbol" reuse misattributed a window fact to symbol
absence. The genuinely-unknown-symbol message and exit codes stay.

closes #242
This commit is contained in:
2026-07-12 18:51:41 +02:00
parent 394ac5e0ae
commit 1605205fc2
+23 -4
View File
@@ -564,6 +564,22 @@ fn no_real_data(symbol: &str, env: &project::Env) -> ! {
std::process::exit(1)
}
/// Empty-in-window refusal — stderr + exit(1). Distinct from `no_real_data`:
/// used only inside `probe_window`, whose callers have already proven the
/// symbol present via `has_symbol` — an empty probe result there is a fact
/// about the requested `--from`/`--to` window, not about symbol absence, so
/// it must not reuse the symbol-absence message (#242).
fn no_data_in_window(symbol: &str, from_ms: Option<i64>, to_ms: Option<i64>, env: &project::Env) -> ! {
let bound = |b: Option<i64>| b.map_or_else(|| "unbounded".to_string(), |v| v.to_string());
eprintln!(
"aura: no data for symbol '{symbol}' in the requested window [{}, {}] at {}",
bound(from_ms),
bound(to_ms),
env.data_path()
);
std::process::exit(1)
}
/// Resolve the per-instrument pip from the recorded geometry sidecar, or refuse
/// (stderr + exit 1) when the symbol has no recorded geometry — the single home of
/// the guessed-pip refusal, shared by `open_real_source` and `from_choice`. Reads
@@ -588,8 +604,10 @@ fn pip_or_refuse(
/// Probe the full data window: open a single-pass probe source through the
/// shared opener, drain it for the first/last timestamp, and return
/// `(first, last)`. Refuses (via `no_real_data`) when the symbol/window yields
/// no source or no bars. Shared by `open_real_source` (which needs the manifest
/// `(first, last)`. Refuses (via `no_data_in_window`) when the symbol/window
/// yields no source or no bars — callers have already proven the symbol
/// present, so an empty result here is a window fact, not symbol absence.
/// Shared by `open_real_source` (which needs the manifest
/// window from a probe separate from the run sources) and
/// `DataSource::full_window`. The probe drains the CLOSE column regardless of
/// the strategy's binding: the bounds are field-independent (every archived bar
@@ -603,10 +621,11 @@ fn probe_window(
env: &project::Env,
) -> (Timestamp, Timestamp) {
let mut probe = aura_ingest::open_columns(server, symbol, from_ms, to_ms, &[aura_ingest::M1Field::Close])
.unwrap_or_else(|| no_real_data(symbol, env))
.unwrap_or_else(|| no_data_in_window(symbol, from_ms, to_ms, env))
.pop()
.expect("open_columns yields one source per requested field");
let first = aura_engine::Source::peek(probe.as_ref()).unwrap_or_else(|| no_real_data(symbol, env));
let first =
aura_engine::Source::peek(probe.as_ref()).unwrap_or_else(|| no_data_in_window(symbol, from_ms, to_ms, env));
let mut last = first;
while let Some((t, _)) = aura_engine::Source::next(&mut *probe) {
last = t;