Files
udpscope/CLAUDE.md
T

5.7 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

What this project is

udpscope is a GTK4 oscilloscope-style viewer for a UDPStreamer source. It receives one data source -- a UDPStreamer stream through deps/udpsclient by default, or another registered source kind (see docs/claude/architecture.md) -- buffers it in a large ring (default 200 MB), and draws it with deps/plotter — a figure of up to eight stacked rows sharing one x window. On top of the live view it provides the things a bench scope provides: a trigger with a pre/post event window, a pause that freezes the visible window, cursors, statistical measurements, user-defined math channels built in a node editor, and an export of the visible window to .npy/.csv.

Two documents bound the work and are not interchangeable with this one:

  • SPECS.md is the requirement document — what was asked for.
  • README.md documents what was actually built, including deliberate deviations from the spec and known limitations. Read it before concluding something is a bug.

Three things shape almost every change here, and the linked files expand on each:

  • There are exactly two threads — a producer that owns the data source and the GTK main thread that owns every widget and the GL context — and they share ScopeModel under one mutex. Samples cross through lock-free rings, never through the lock.
  • There is no unit test suite. The only automated check is the application's own headless self-check, driven by environment variables under xvfb-run against a mock source. Extend the probe/dump in src/ui.cpp rather than adding a separate harness.
  • Every source file carries an SPDX MIT header; match it in new files.

Table of contents

The detail lives in docs/claude/. Read the files that touch the area you are editing before you edit it — most of their contents are rules that cost a defect to learn.

Working in the repository

File What it covers
build-and-run.md Configuring and building, the desktop-entry target, the command-line options, and the two vendored dependencies (deps/plotter, deps/udpsclient) including what was changed upstream and why.
verification.md How to run the headless self-check, the two baselines every run is read against (exactly three build warnings; no Gtk-CRITICAL), and the environment variable that schedules each probe.
probe-readings.md The per-line reference for the self-check's output: what every probe and dump line means, the value it must read, and the defect a wrong reading names.

How the application is put together

File What it covers
architecture.md The two threads and what they share; the one BufferStore and the four display modes (Live, Capturing, Held, Waiting); the display clock and stream_at_x0(); the layers to keep straight (SignalInfo → ChannelBuffer → SlotSeries → RowSet); the source plugins.

Invariants worth knowing before editing

File What it covers
invariants-plot-and-layout.md What plot::Figure/plot::Plot can and cannot be asked to do, what a row's contents belong to, the layout editor's overlay children, and the rule that layout must not depend on content.
invariants-readouts-and-cursors.md A readout quotes a stored sample and never a value between two; how the cursors are read back from the plots; the one formatter both panes share.
invariants-data-path.md What rebuilds the buffer and drops history, why decimation at ingest is an average and never a stride, and the two rules the f64 time ring and its cached first stamp impose.
invariants-rendering.md How the renderer maps a visible range onto samples (never the dx() grid), what gather() emits and relative to which origin, why every series needs a real MinMaxPyramid, and why a dense trace is drawn one pixel column at a time.
invariants-trigger-and-pinning.md The event window counted in stream seconds end to end, what pins an axis in each mode, and what each pin is measured from (the snapshot's own stamps, not the request).
invariants-time-axis-and-window.md No plot interaction changes the time scale; apply_time_window() is the only path that does; how the x labels pick their form; what a fit restores.
invariants-measurements.md Why the pane is refreshed on a cadence, why neither pass may read its window raw, how a crossing is counted with hysteresis, and which mean over a split is which.
invariants-math-channels.md A math channel is a channel; the engine runs on the producer thread, so a regression there costs packets and not frames; the node editor's own rules.
invariants-session-and-export.md What a session file persists and in what order, when a save is refused, and when an export is collected.
invariants-gtk-and-chrome.md The GTK signal-signature and dialog-lifetime traps this app has already fallen into, the status bar's two tiers, the six bundled icons and their authoring rules, and how the Mallard manual is opened.