fix(fb-32): address PR #122 round 1 review
- config: rename env-silent-ignore test + add file-load negative test asserting ConfigInvalid for negative TOML stale_threshold_days - rag: add 5 boundary unit tests pinning compute_stale mirror equivalence - search: rewrite "Task 6" plan refs in lexical/vector to point at actual function names (mark_stale_in_place / RagPipeline::ask) - cli: dedupe write_config / ingest / backdate_updated_at helpers from wire_search_stale + wire_ask_stale into tests/common/mod.rs - tui: clarify inspect.rs uses same source-of-truth as SearchHit - rag: PackedCitation.stale invariant doc comment - HOTFIXES: log conscious decision on wire-schema required-field expansion (strict-validator concern) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -54,6 +54,10 @@ struct PackedCitation {
|
||||
marker: u32,
|
||||
citation: Citation,
|
||||
indexed_at: OffsetDateTime,
|
||||
/// Pre-stamped by `RagPipeline::ask` against the configured
|
||||
/// `search.stale_threshold_days` before `pack_context` runs;
|
||||
/// this struct just forwards the value into the eventual
|
||||
/// `AnswerCitation` and never recomputes.
|
||||
stale: bool,
|
||||
}
|
||||
|
||||
@@ -942,3 +946,54 @@ mod tests {
|
||||
assert_eq!(left, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// p9-fb-32: boundary tests pinning the local `compute_stale` mirror's
|
||||
/// semantic equivalence to `kebab_app::staleness::compute_stale`. The
|
||||
/// two implementations are intentionally duplicated (dep-boundary rule
|
||||
/// blocks `kebab-rag → kebab-app`); these tests are the contract that
|
||||
/// guards both copies from drifting. Mirrors the test set in
|
||||
/// `crates/kebab-app/src/staleness.rs`.
|
||||
#[cfg(test)]
|
||||
mod compute_stale_mirror_tests {
|
||||
use super::compute_stale;
|
||||
use time::Duration;
|
||||
use time::OffsetDateTime;
|
||||
use time::macros::datetime;
|
||||
|
||||
fn now() -> OffsetDateTime {
|
||||
datetime!(2026-05-09 12:00:00 UTC)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn threshold_zero_always_fresh() {
|
||||
let very_old = datetime!(2020-01-01 00:00:00 UTC);
|
||||
assert!(!compute_stale(very_old, now(), 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn just_under_threshold_is_fresh() {
|
||||
// 29 days, 23h, 59m old — under 30d.
|
||||
let indexed = now() - Duration::days(29) - Duration::hours(23) - Duration::minutes(59);
|
||||
assert!(!compute_stale(indexed, now(), 30));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exactly_threshold_is_fresh() {
|
||||
// strict `>` boundary: exactly 30d old is still fresh.
|
||||
let indexed = now() - Duration::days(30);
|
||||
assert!(!compute_stale(indexed, now(), 30));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_minute_past_threshold_is_stale() {
|
||||
let indexed = now() - Duration::days(30) - Duration::minutes(1);
|
||||
assert!(compute_stale(indexed, now(), 30));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn future_indexed_at_is_fresh() {
|
||||
// clock skew safety: future timestamps must not be stale.
|
||||
let future = now() + Duration::hours(1);
|
||||
assert!(!compute_stale(future, now(), 30));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user