Skip to content

feat(cm): traceroute burst capture (#196)#252

Merged
itsDNNS merged 26 commits intomainfrom
feat/196-traceroute-burst-capture
Mar 17, 2026
Merged

feat(cm): traceroute burst capture (#196)#252
itsDNNS merged 26 commits intomainfrom
feat/196-traceroute-burst-capture

Conversation

@itsDNNS
Copy link
Owner

@itsDNNS itsDNNS commented Mar 17, 2026

Summary

Adds event-triggered and manual traceroute to the Connection Monitor module (Phase 2, #196).

  • New setuid C helper binary (docsight-traceroute-helper) with privilege dropping
  • TracerouteProbe Python wrapper with partial-result support on timeout
  • TracerouteTrigger fires on outage/packet_loss events with 5-min cooldown
  • New API: POST manual traceroute, GET trace history, GET trace detail
  • Trace history UI in Connection Monitor detail tab
  • Demo mode traces for testing
  • i18n in all 4 languages (EN/DE/FR/ES)

Test plan

  • Unit tests for TracerouteProbe (10 tests)
  • Unit tests for TracerouteTrigger (10 tests)
  • Unit tests for trace storage (11 tests)
  • Unit tests for trace routes (8 tests)
  • C helper compiles with -Wall -Werror
  • Full test suite passes
  • i18n validation passes
  • Docker build succeeds
  • Manual test: Run Traceroute button in UI
  • Demo mode shows sample traces

itsDNNS added 26 commits March 17, 2026 11:05
Design spec for Connection Monitor Phase 2: event-triggered and manual
traceroute capture with hop-level evidence. Reviewed through 4 internal
rounds + 2 external rounds (18 issues found and resolved).
17 tasks in 7 chunks, TDD throughout. Reviewed through 2 internal
rounds + 3 codex rounds. Key iterations: storage CRUD implementations,
demo migration path in config_bp.py, honest DNS timeout contract.
Security fixes from code review:
- Check seteuid(getuid()) return value, exit on failure
- Add privilege drop to --check path (was missing)
The test_capture_entries_in_timeline test was date-dependent: it queried
for 2026-03-16 but save_execution uses utc_now() for created_at, which
produces today's date. This passed on 03-16 but fails on any other day.
Use uPlot.setData() for in-place updates when chart structure hasn't
changed, instead of destroying and recreating. This preserves zoom
state and prevents scroll jumps during the 10-second refresh cycle.
Show a "Reset Zoom" button in the top-right corner of the chart when
zoomed in. Also add a native tooltip ("Drag to zoom, double-click to
reset") on hover so users discover the zoom feature.
The setData() approach kept stale plugin closures (loss markers, tooltip
labels) across refreshes. Switch back to destroy/recreate but save and
restore _zoomRange across the cycle so zoom state is preserved without
stale closure bugs.
Pin container min-height before chart destroy, release via
requestAnimationFrame after recreate. Prevents DOM reflow from
shifting scroll position during the 10s auto-refresh cycle.
Replace hardcoded yMax=200ms with dynamic scaling that adapts to the
actual data range. Snaps to zone boundaries with ~20-30% headroom so
the graph uses its full height instead of showing mostly whitespace.
Fixes graph disappearing on all-timeout samples (dataMax=0) and
overly tight scaling at low latencies. 40ms floor keeps the green
threshold zone visible with breathing room for typical 5-20ms values.
@itsDNNS itsDNNS merged commit 0dbd432 into main Mar 17, 2026
2 checks passed
@itsDNNS itsDNNS deleted the feat/196-traceroute-burst-capture branch March 17, 2026 12:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant