1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
//! Stderr tracing for the post-turn extraction boundary (spec packet-54 open
//! question).
//!
//! Until this slice there was zero visibility into the only path that writes
//! memory — no log, no receipt, no counter — and two reviews were misled by the
//! rendered `memory learned ·` line as a result. This module is the durable
//! win: a one-line stderr trace at the `run_extraction` boundary, off by
//! default so production logs nothing. Two ways to turn it on: the
//! `SAYA_EXTRACTION_TRACE` env var, or `--verbose`, which seeds the same gate
//! at startup (see [`enable`]).
//!
//! What is logged — and what is not — is documented on [`trace_extraction`].
use OnceLock;
/// Whether the boundary trace prints. Seeded either by [`enable`] (from
/// `--verbose`, before any turn runs) or lazily from the environment.
static ENABLED: = new;
/// Turns the trace on for this process, whatever the environment says.
///
/// Called once at startup when `--verbose` is passed. Seeding the gate is what
/// makes that flag reachable here: the alternative — threading a `verbose:
/// bool` through `run_prompt_with_sink` → `run_prompt_with_inputs`, every test
/// that calls it, and `RuntimeConfig` — is a lot of plumbing for one boolean,
/// and mutating the environment instead is `unsafe` under edition 2024. A
/// later `get_or_init` sees the value already set and does not consult the
/// environment, so the flag wins over an unset variable and agrees with a set
/// one.
pub
/// Traces one post-turn extraction boundary event to stderr when
/// `SAYA_EXTRACTION_TRACE` is set (any non-empty value).
///
/// Logged:
/// - the outcome token (`ok` / `failed` / `timed_out` / `gate_declined`),
/// - the number of objects in the turn's object table,
/// - the count of proposals persisted (when extraction ran), and
/// - on error the `ExtractionRunnerError` display string (a category + short
/// message, not user data).
///
/// Never logged: the raw model response. It may contain user data (rows,
/// prompts), so it is excluded by construction — `run_extraction` does not
/// surface it here, and this trace does not print it even when enabled.
///
/// Two triggers, one gate. `SAYA_EXTRACTION_TRACE` matches the existing
/// debug-knob pattern in this crate (`SAYA_HISTORY`, `SAYA_STATE_DB`,
/// `SAYA_SESSION_DIR`) and is safe to leave set in a shell while debugging a
/// "memory didn't record" report. `--verbose` seeds the same gate at startup
/// via [`enable`], which is what a user reaches for first and what that flag
/// previously did not do — it was declared and read nowhere. Off by default,
/// so production logs nothing.
pub