Files
udpscope/CLAUDE.md
T
Martino FerrariandClaude Opus 4.6 a7702acb63 docs: CLAUDE.md is a goal and a table of contents, so a context pays for what it reads
The file was 1967 lines and is auto-loaded into every context, so every
session paid for the whole of it to reach one invariant. It now carries the
project's goal, the three facts that are always relevant, and a table of
contents; the body is fourteen files under docs/claude/ reached by link
rather than by import, so nothing is loaded until it is asked for.

The content is moved verbatim -- the only edits are each file's own header
and the cross-references that became cross-file ("see the invariant below"
is now a link to the file that owns it).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-10-07 01:49:28 +02:00

64 lines
5.5 KiB
Markdown

# 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
UDP stream with `deps/udpsclient`, 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 UDP client 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](docs/claude/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](docs/claude/verification.md) | How to run the headless self-check, the **two baselines every run is read against** (exactly five build warnings; no `Gtk-CRITICAL`), and the environment variable that schedules each probe. |
| [probe-readings.md](docs/claude/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](docs/claude/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`). |
### Invariants worth knowing before editing
| File | What it covers |
| --- | --- |
| [invariants-plot-and-layout.md](docs/claude/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](docs/claude/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](docs/claude/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](docs/claude/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](docs/claude/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](docs/claude/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](docs/claude/invariants-measurements.md) | Why the pane is refreshed on a cadence, why neither pass may read its window raw, and how a crossing is counted with hysteresis. |
| [invariants-math-channels.md](docs/claude/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](docs/claude/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](docs/claude/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 the help pages. |