# AGENT.md Working notes for an AI agent (or a new contributor) in this repository. **Read [CLAUDE.md](CLAUDE.md) first, then the `docs/claude/` file that covers the area you are touching** — this page is the fast path into it, not a replacement. `SPECS.md` is what was asked for; `README.md` is what was built, deviations and limitations included; when the two disagree, README explains why. ## Build ```sh git submodule update --init --recursive # deps/plotter is a submodule cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo cmake --build build # the app cmake --build build --target test-ui # round-trips every .ui through blueprint-compiler cmake --build build --target test-help # yelp-check over help/C/org.udpscope.app/ ./build/udpscope --server 127.0.0.1 --port 8000 ``` A clean build emits **exactly one warning** (`-Woverlength-strings` on the generated GResource `.c`). Two is a regression. ## Verify There is **no unit test suite**. The check is the app's own headless self-check against a mock source; add a probe rather than a harness: ```sh python3 tools/mock_udpstreamer.py --port 8000 --duration 120 & xvfb-run -a env UDPSCOPE_EXIT_AFTER_MS=16000 UDPSCOPE_ENABLE_ALL_MS=1000 \ UDPSCOPE_PROBE__MS=3000 ./build/udpscope --server 127.0.0.1 --port 8000 ``` Two baselines every run is read against: **`gtk warnings: 0`** in the exit dump (a `Gtk-CRITICAL` is a defect, not noise) and the single build warning above. The probes, their env vars and the value each line must read are in [docs/claude/probe-readings.md](docs/claude/probe-readings.md); how a run is compared with the previous one is in [docs/claude/verification.md](docs/claude/verification.md). For UI work, drive the real surface: the app under `xvfb-run` plus `xdotool`/`import` for pointer and pixel checks (see `tmp/`-free examples in the probe sources), not only internal state reads. ## Hard rules - **SPDX MIT header on every source file**, in the format the existing files use. - **Two threads only**: a producer owning the data source and the GTK main thread owning every widget and the GL context. They share `ScopeModel` under **one mutex**; samples cross through lock-free rings, never through the lock. - **A view never acquires.** Scope windows, full-screen and the layout editor are arrangements of views over the one acquisition; they must not plan buffers, epochs or sources of their own. - **Layout must not depend on content** (docs/claude/invariants-plot-and-layout.md). - **Documentation moves with the code.** A behaviour change updates the matching `docs/claude/invariants-*.md`, `README.md`, the Mallard page under `help/C/org.udpscope.app/`, and the probe reading in `docs/claude/probe-readings.md` — the probe baselines are read as tests. - **`deps/plotter` is a submodule and has its own history**: commit there first, then commit the pin in this repository. Never edit its files without committing them both sides. - No new dependencies, no generated-file edits, no silent changes to `SPECS.md` semantics: a deliberate deviation is written into `README.md` under "Deviations from the spec". ## Commits Subject: `: `, lowercase, imperative, no trailing period (`layout editor: …`, `docs: …`, `plot: …`). The body explains *why* (the defect it fixes, the trade-off it takes), not a restatement of the diff. Keep each commit one coherent change; probes, docs and the code they describe travel together.