Decision 0018 - TRACE Logging Architecture & Semantics¶
Date: 08/02/2026 Status: Accepted Scope: Logging / Observability / Diagnostics Applies to: Entire Fontshow codebase
1. Purpose¶
TRACE is the lowest-level observability channel in Fontshow.
It is intended for:
- execution tracing
- raw data inspection
- parsing pipeline diagnostics
- inference reasoning
- internal state transitions
TRACE must not be used for user diagnostics, warnings, or standard debugging output.
2. TRACE Semantic Contract¶
TRACE MUST be used for¶
- external interactions (subprocess / filesystem / tools)
- raw external outputs (bounded)
- parsing pipeline steps
- internal decision paths (not results)
- cache behavior
- inference reasoning
TRACE MUST NOT be used for¶
- user-visible diagnostics
- warnings/errors
- normal DEBUG logging
- formatted summaries
3. TRACE Categories¶
TRACE is divided into selectively activatable categories:
| Category | Meaning |
|---|---|
io |
External interaction (subprocess, OS, filesystem probing) |
raw |
Raw external data (stdout blobs, raw fc-query, etc.) |
parse |
Parsing pipeline internal steps |
infer |
Script/language inference reasoning |
validate |
Schema/semantic validation decisions |
cache |
Cache hit/miss and persistence |
perf |
Optional timing / performance micro-metrics |
flow |
Execution flow, pipeline/stage boundaries, orchestration lifecycle |
latex |
LaTeX generation, formatting, and layout decisions |
Categories are closed and stable identifiers used both in code and configuration. No dynamic categories are allowed.
4. TRACE Activation Model¶
TRACE emission requires two conditions:
- Global log level allows TRACE
- TRACE category is enabled
4.1 Global Level¶
FONTSHOW_LOG_LEVEL=TRACE
If TRACE level is not active, no TRACE is emitted regardless of category settings.
4.2 Category Selector¶
Environment variable:
FONTSHOW_TRACE
Syntax:
all→ enable all categoriesnone→ disable all TRACEcat1,cat2→ enable only listed categories-cat→ exclude categorycat1,cat2,-cat3→ mixed include/exclude
Defaults:
- If TRACE level active and selector unset → behaves as
all - If TRACE level inactive → selector ignored
Unknown categories are ignored.
Examples:
FONTSHOW_LOG_LEVEL=TRACE FONTSHOW_TRACE=all
FONTSHOW_LOG_LEVEL=TRACE FONTSHOW_TRACE=io,parse
FONTSHOW_LOG_LEVEL=TRACE FONTSHOW_TRACE=infer,-raw
FONTSHOW_LOG_LEVEL=TRACE FONTSHOW_TRACE=none
5. Inference Debugging¶
The legacy variable:
FONTSHOW_DEBUG_INFERENCE
has been removed.
Inference diagnostics are now emitted exclusively through:
TRACE category: infer
Example:
FONTSHOW_LOG_LEVEL=TRACE FONTSHOW_TRACE=infer fontshow parse-inventory
6. Structured TRACE Output¶
All TRACE events are structured and include:
extra["trace_category"] = "<category>"
This allows:
- machine filtering
- testing
- post-processing
- future trace exporters
TRACE payload MUST:
- use snake_case field names
- remain deterministic
- avoid unbounded data
7. Human-Readable TRACE Rendering¶
By default, TRACE is structured and optimized for machine consumption.
To force human-readable rendering:
FONTSHOW_TRACE_FORMAT=human
Behavior:
- Formats TRACE messages in readable text form
- Includes
trace_category - Includes selected
extrafields - Preserves existing log formatting style
If unset or set to json (default), structured TRACE is emitted.
8. RAW Category Guardrails¶
The raw category may produce large outputs.
To prevent uncontrolled log volume:
FONTSHOW_TRACE_RAW_MAXLEN=4096
Behavior:
- Raw blobs exceeding limit are truncated
- Additional metadata added:
raw_truncated: true
raw_len: <original_length>
9. Caller Identity Rule¶
TRACE must report the first semantic execution owner, not logging helpers.
Allowed:
- functional helpers representing real execution boundary
e.g.
_run_fc_query
Not allowed:
- logging wrappers or infrastructure functions
10. Performance Contract¶
When TRACE is disabled:
- overhead MUST be negligible
- no expensive computation for TRACE-only values
- no large payload allocation
When TRACE is enabled:
- timing uses lightweight
perf_counter - hot loops MUST gate or aggregate TRACE
- TRACE MUST NOT change program behavior
11. DEBUG Decommission¶
DEBUG is no longer the primary observability channel.
- TRACE is the canonical structured observability layer
- DEBUG may remain for temporary developer-only probes
- No new structured diagnostics should be added to DEBUG
12. Stability Guarantees¶
This TRACE architecture:
- does NOT change CLI behavior
- does NOT affect exit codes
- does NOT emit TRACE unless explicitly enabled
- preserves existing DEBUG / INFO / WARN semantics
- has negligible overhead when disabled
- does not affect determinism or ordering
13. Observability Coverage Goals¶
TRACE SHOULD cover:
- execution lifecycle (
flow) - external calls (
io) - cache behavior (
cache) - inference evidence (
infer) - validation rules (
validate) - timing metrics (
perf) - formatting and generation (
raw,latex)
Coverage MUST remain stable across releases.
14. Future Extensions (Non-binding)¶
Potential evolutions:
- selective TRACE exporters (file, JSONL, analysis tools)
- category-specific rate limiting
- per-module TRACE filters
- structured inference trace viewer
- performance tracing mode
These are outside current scope.
15. Summary¶
TRACE is now:
- structured
- category-selective
- inference-aware
- human-renderable
- stable and deterministic
- suitable for deep observability without affecting runtime behavior