Skip to main content

ski/
trace.rs

1//! Opt-in stderr diagnostics for the fail-open hot paths.
2//!
3//! `hook`/`observe`/`session-start` swallow every error by design (README:
4//! "fail-open everywhere") so a ranking problem never blocks a prompt. That
5//! contract has a cost: when injection silently stops, there is normally
6//! nothing to debug with — the hook just goes quiet forever with no trace of
7//! why. [`debug`] prints the swallowed error to stderr, but only when
8//! `SKI_DEBUG` is set, so the default (quiet) behavior is unchanged and a
9//! user who suspects something is wrong has a way to find out what.
10
11/// Whether `SKI_DEBUG` is set (any value, including empty).
12pub fn enabled() -> bool {
13    std::env::var_os("SKI_DEBUG").is_some()
14}
15
16/// Print `ski: {context}: {err}` to stderr iff `SKI_DEBUG` is set. No-op
17/// otherwise. `context` should read as a fragment ("hook decide failed").
18pub fn debug(context: &str, err: &impl std::fmt::Display) {
19    if enabled() {
20        eprintln!("ski: {context}: {err}");
21    }
22}
23
24#[cfg(test)]
25mod tests {
26    use super::*;
27
28    #[test]
29    fn enabled_reflects_env_var() {
30        // SKI_DEBUG is read at call time with no caching, so tests can toggle
31        // it freely — but other tests run in the same process may also read/
32        // write it, so only assert the presence check itself is correct given
33        // an explicit value, not the ambient default.
34        std::env::set_var("SKI_DEBUG", "1");
35        assert!(enabled());
36        std::env::remove_var("SKI_DEBUG");
37        assert!(!enabled());
38    }
39}