Each invariant records what went wrong rather than only the rule: a port hit that lost its node, a hit test at the identity view that asserts nothing, a `Delete` that must not fall through to the selected node, and a column pitch too narrow for a wire's own tread. The warning baseline drops to four.
64 lines
5.5 KiB
Markdown
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 four 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. |
|