Expand description
Decision-trace channel for XFA observability.
This module is part of M1 (Observability Foundation). It exists so that
XFA fidelity debugging can record why the engine made a particular
layout decision, separate from what the resulting layout looks like
(the latter is captured by crate::ir).
§Design constraints
- Off by default. No global state. The trace channel is enabled
only inside a
with_sinkscope. When no sink is installed,emitis a single thread-local read returning aNoneand compiles to a small handful of instructions. - No new dependencies. Plain Rust,
stdonly. Notracingorserdeinvolvement at this layer. - Frozen vocabulary.
PhaseandReasonare enums with stable string tags; renames are breaking and require a taxonomy bump (see migration policy in source comments). - Determinism-friendly. Events are accumulated in insertion order
inside a
RecordingSink, with noHashMap/HashSetinvolvement.
§Out of scope (M1 v1)
- Wiring trace emit calls from the engine’s hot phases (bind, occur, presence, paginate, suppress) into production layout code paths. v1 ships the taxonomy, the sink trait, and demonstration emit sites under tests. Engine wiring lands in a follow-up wave that is allowed to perturb existing call sites.
- Streaming output to disk, file rotation, or telemetry. The diff CLI
in
xfa-test-runnerreads the in-memoryRecordingSinkevents serialised once at the end of a run. - JSON/Serde derives. Output is via the small
to_canonical_jsonhelpers below.
Modules§
- sites
- Named emit helpers for the five M1.6 hot phases.
Structs§
- Noop
Sink - A no-op sink. Default when no sink is installed.
- Recording
Sink - A simple recording sink that accumulates events in insertion order.
- Trace
Event - One trace event.
Enums§
- Phase
- The phase in which a trace event was emitted.
- Reason
- The reason behind a trace event — a closed vocabulary of decision codes.
Traits§
- Sink
- Implemented by anything that wants to receive trace events.
Functions§
- clear_
global_ sink - Clear the global sink slot.
- emit
- Emit one event to the current thread-local sink, if any, and then to
the global sink, if any. Cheap when neither is installed: one
thread-local read, one atomic-protected lock read, and two
Option::is_somechecks. - emit_
simple - Convenience: emit a
Phase + Reasonevent with no extra fields. - events_
to_ canonical_ json - Render a slice of events to canonical JSON (alphabetical keys, fixed ordering, two-space indent).
- set_
global_ sink - Install a
Send + Syncsink in the cross-thread global slot. - with_
global_ sink - Install
sinkin the global slot for the duration off, then restore the previous global sink. Emits from any thread (including worker threadsfspawns) reach this sink. Single-thread callers should prefer the cheaperwith_sinkAPI. - with_
sink - Install
sinkfor the duration off, then restore the previous sink.