---
phase: 30-parquet-first-gap-fill-junction-telemetry
plan: 02
subsystem: sidecar
tags: [telemetry, ndjson, junction, rest-ws-handoff, streaming]

requires:
  - phase: 30-01
    provides: Parquet pre-fill function (_parquet_prefill_aion)
provides:
  - _log_junction_telemetry() function for per-symbol REST-to-WS handoff quality metrics
  - _junction_state enrichment with ws_buffer_depth, parquet_coverage, junction_logged_at
  - NDJSON telemetry events written to logs/events.jsonl
affects: [sidecar-startup, status-endpoint, heartbeat-monitoring]

tech-stack:
  added: []
  patterns: [Protocol-typed engine parameter, non-fatal telemetry wrapper]

key-files:
  created:
    - python/opendeviationbar/sidecar/junction_telemetry.py
    - tests/test_sidecar_junction_telemetry.py
  modified:
    - python/opendeviationbar/sidecar/__init__.py

key-decisions:
  - "Used Protocol type (_HasMetrics) instead of Any for engine parameter typing"
  - "NDJSON written directly to logs/events.jsonl (no write_telemetry_event helper exists)"

patterns-established:
  - "Non-fatal telemetry: try/except at top level with specific exception types, log warning on failure"
  - "Inner function pattern: public wrapper catches errors, inner function has testable logic"

requirements-completed: [RESUME-03]

duration: 3min
completed: 2026-03-28
---

# Phase 30 Plan 02: Junction Telemetry Summary

**Per-symbol REST-to-WS handoff quality telemetry with NDJSON logging, \_junction_state enrichment, and /status endpoint visibility**

## Performance

- **Duration:** 3 min
- **Started:** 2026-03-28T08:16:15Z
- **Completed:** 2026-03-28T08:19:29Z
- **Tasks:** 1 (TDD: RED + GREEN)
- **Files modified:** 3

## Accomplishments

- Created junction_telemetry.py with_log_junction_telemetry() that logs per-symbol handoff metrics (rest_last_tid, ws_buffer_depth, parquet_coverage) at INFO level
- Enriches \_junction_state dict for /status endpoint consumption (junction_logged_at, ws_buffer_depth, parquet_coverage fields)
- Writes NDJSON telemetry events to logs/events.jsonl for cross-service correlation
- Wired call site in **init**.py after sync_flush and before engine.start() (non-fatal)
- 6 unit tests covering all behaviors including no_rest_data marking, NDJSON output, and exception safety

## Task Commits

Each task was committed atomically:

1. **Task 1: Junction telemetry logging with TDD** - `0fa165a` (feat)

## Files Created/Modified

- `python/opendeviationbar/sidecar/junction_telemetry.py` - \_log_junction_telemetry() function with_HasMetrics Protocol, NDJSON logging, \_junction_state enrichment
- `python/opendeviationbar/sidecar/__init__.py` - Import and call site after sync_flush (Step 5.5, RESUME-03)
- `tests/test_sidecar_junction_telemetry.py` - 6 unit tests for junction telemetry behaviors

## Decisions Made

- Used Protocol type (\_HasMetrics) instead of Any for engine parameter -- satisfies ruff ANN401 and provides structural typing
- Write NDJSON directly to logs/events.jsonl since write_telemetry_event helper does not exist in the codebase
- Parquet coverage computed as rest_last_tid > resume_tid (simple boolean, captures whether Parquet prefill advanced the TID)

## Deviations from Plan

None - plan executed exactly as written.

## Issues Encountered

None

## User Setup Required

None - no external service configuration required.

## Known Stubs

None - all data paths are wired to live sources.

## Next Phase Readiness

- Junction telemetry is live and will emit metrics on next sidecar restart
- /status endpoint will show junction_logged_at, ws_buffer_depth, parquet_coverage per symbol
- Post-handoff junction_gap_tid_delta (ws_first_tid - rest_last_tid - 1) is already computed by existing main loop code (line 1310) when first WS bar arrives

---

_Phase: 30-parquet-first-gap-fill-junction-telemetry_
_Completed: 2026-03-28_
