Telemetry
trkr records everything it does as OTel-shaped spans in local JSONL. Design principles:
- Vendor-neutral — OTel-shaped data through a thin in-house API; no vendor SDK in core. Export is a future config concern, not an architectural one.
- Local-first — spans append to
.trkr/telemetry/spans.jsonl, one JSON object per line. - One trace per ticket turn — a ticket links its turns via attributes.
- No sampling — head-sampling drops exactly the failures worth replaying. Keep everything.
Span vocabulary
ticket.turn root — ticket, turn, workflow, trigger
├── stage name, from/during/to columns, provider
│ ├── provider.session command, prompt file, exit code, log path
│ └── verification gate (review | ci | acceptance), verdict, findings count
└── gh.call gh operation, exit code — can parent anywhereEvents: column.moved, comment.posted, turn.kickout, turn.plateau (a stage's failing count didn't fall between turns — blocks the ticket early), ticket.blocked, pr.merged, and criterion (one per acceptance criterion or CI check, with pass=true|false).
A stage run that reaches its gate closes a verification span — gate review if the run produced a VERDICT: line (or CRITERION: lines it can infer a verdict from), else gate acceptance. (A checks-green stage parked waiting on pending CI closes its stage span with no verification.) The terminal stage records a second one at gate ci from the linked PR's check rollup, one criterion event per check.
Cross-process trace context
A ticket turn is one trace, but its stages run in separate processes. The root span's identity persists to .trkr/telemetry/context/<issue>.json (traceId, rootSpanId, turn, workflow, trigger, start time) so later stage processes reconstruct and eventually close it. Provider child processes get the context via TRKR_TRACEPARENT / TRKR_TICKET / TRKR_TURN env vars.
Failure replay
The trace is the replay manifest: stage, command, prompt file path, log pointer, findings. turn.kickout and ticket.blocked events carry the span id whose criterion events explain the failure — no separate capture mechanism.
Rotation & retention
Configured under telemetry in .trkr.json:
{ "telemetry": { "retain": "14d", "maxBytes": 10485760 } }spans.jsonl rotates to a gzipped sibling when it exceeds maxBytes (default 10 MiB); rotated files older than retain (default 14d; accepts <n>d|h|m) are pruned.