Files
MARTe-Integrated-Components/CLAUDE.md
Martino Ferrari 5892251622 docs(e2e-stress): document --stress workflow in CLAUDE.md
Describe the capacity matrix (stress.py axes → stress_run.py → stress_results.json),
its hard/soft gates and PDF Stress Tests section, the run_chain_e2e.sh --stress flag,
and the standalone run_stress.sh wrapper. (Harness files were already tracked.)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-26 09:32:43 +02:00

7.3 KiB

CLAUDE.md

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

Overview

MARTe2 component library providing real-time signal streaming (UDPStreamer DataSource → StreamHub → web/ImGui oscilloscopes) and zero-code-change debugging (DebugService Interface: trace/force/breakpoint via registry-patched broker wrappers). See ARCHITECTURE.md for full detail and Docs/ for per-component references.

Build & Test

Requires MARTe2 and MARTe2-components built externally; env.sh sets MARTe2_DIR, MARTe2_Components_DIR, TARGET=x86-linux, and LD_LIBRARY_PATH (needed both for building and for running anything).

source env.sh

make -f Makefile.gcc core    # all C++ MARTe2 components
make -f Makefile.gcc apps    # StreamHub standalone app
make -f Makefile.gcc test    # build GTest + Integration tests
make -f Makefile.gcc clean

# Run tests (after source env.sh)
./Build/x86-linux/GTest/MainGTest.ex                          # unit tests (UDPStreamer)
./Build/x86-linux/GTest/MainGTest.ex --gtest_filter='Name*'   # single test
./Build/x86-linux/Test/Integration/Integration/IntegrationTests.ex  # DebugService integration tests

# Build a single component (each component dir has its own Makefile.gcc)
make -C Source/Components/DataSources/UDPStreamer -f Makefile.gcc

# Go clients
cd Common/Client/go && go build ./...
cd Client/debugger && go build ./...

# ImGui desktop client (not a MARTe2 component; needs SDL2)
cd Client/streamhub && cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build

# Qt desktop client (not a MARTe2 component; needs Qt5 or Qt6 Widgets + WebSockets)
cd Client/streamhub-qt && cmake -B build && cmake --build build

End-to-end demo scripts (build + launch full stack, see headers for ports/options): ./run_combined_test.sh, ./run_streamhub.sh.

Streaming-chain E2E suite (Test/E2E/chain/): ./run_chain_e2e.sh [--skip-build] [--only <id>] [--cpp-coverage] [--stress] drives the full chain per scenario (scenarios.py) — generates typed/shaped input + both cfgs, runs MARTe2+StreamHub, records via the Go chain-client (live/zoom/window/trigger), and validates the recorded waveform against an analytic/fed oracle (validate_waveform.py: fidelity gates correctness, sine shape-fit is a gross-sanity gate + tracked metric pending Phase-A timestamp calibration). It then runs the unit suites + coverage (collect.py: C++ GTest, Go, Python; --cpp-coverage does an instrumented --coverage rebuild, captures with lcov restricted to Source/*+Test/*, then restores the clean build), consolidates everything into report_data.json with per-field progression/regression vs the previous run and trend plots (report_build.py, history in Build/x86-linux/E2E/chain/history.jsonl), and compiles a Typst PDF (E2E_Report.typ). A --stress flag additionally runs the capacity matrix (stress.py declarative axes → stress_run.py orchestrator → stress_results.json): it sweeps signal size (into the multi-fragment >64 KB regime), signal count, source count, WS-client count, subscriber fan-out, and zoom request-rate one axis at a time, gating survival + liveness (hard) and peak RSS + zoom-p95 latency (soft), and embeds a Stress Tests section (per-case table + per-axis scaling curves, with regression vs the previous run) into the PDF. Standalone: ./run_stress.sh [--skip-build] [--only <id>] [--axis <axis>]. Python framework unit tests: python3 -m unittest tests_py (in Test/E2E/chain/).

Build output goes to Build/x86-linux/ (shared libs per component, .ex executables).

Architecture

Two independent data paths:

  1. Streaming path: UDPStreamer DataSource serialises signals each RT cycle to UDPS binary packets (UDP 44500, unicast/multicast) → StreamHub (Source/Applications/StreamHub/, headless C++ app: ring buffers, LTTB decimation, trigger FSM) → WebSocket 8090 → browser (Client/udpstreamer, Go), native ImGui client (Client/streamhub), or native Qt client (Client/streamhub-qt).
  2. Debug path: DebugService patches the ClassRegistryDatabase at Initialise() so subsequent ConfigureApplication() instantiates DebugBrokerWrapper<T> around all MemoryMap*Broker types — no application changes. RT hot path goes through DebugServiceI (abstract singleton in DebugServiceI.h) for forcing/tracing/breakpoints. Exposes TCP 8080 (text commands), UDP 8081 (trace telemetry), works with TcpLogger on 8082. Web UI: Client/debugger (Go).

Shared wire format: Common/UDP/UDPSProtocol.h defines the UDPS binary protocol (17-byte packed header, 136-byte signal descriptors, little-endian). It is deliberately MARTe2-free so it's shared by C++ producers (UDPStreamer, DebugService), the C++ consumer (Source/Components/Interfaces/UDPStream/UDPSClient), and the Go decoder (Common/Client/go/udpsprotocol). Changes to the protocol must be mirrored across all of these, plus the JS client parsers.

StreamHub WebSocket protocol: JSON text frames for commands/events, binary frames for data pushes — spec in ARCHITECTURE.md §6. The Go hub (Client/udpstreamer) and C++ StreamHub implement the identical protocol; both clients (browser JS and ImGui) must stay compatible with both.

StreamHub History: HistoryWriter (Source/Applications/StreamHub/HistoryWriter.{h,cpp}) provides disk-backed circular storage of signal data. Each signal is stored in a separate .shist binary file with a 64-byte header and pre-allocated circular data region of (float64 time, float64 value) pairs. Configured via a +History block in the StreamHub config with keys: Directory (required), DurationHours (default 1), Decimation (default 1), FlushIntervalSec (default 5), MinDiskFreeMB (default 500). WS commands: historyInfo (returns metadata), historyZoom (reads time range from disk). Both the web SPA (Client/udpstreamer/static/app.js) and ImGui client support history zoom queries alongside in-memory ring zoom.

Conventions

  • No STL in MARTe2 components (Source/Components/): use MARTe2 types (StreamString, FastPollingMutexSem, fixed arrays). STL/C++17 is fine in Client/streamhub/ and Source/Applications/StreamHub/ follows MARTe2 style but links MARTe2 core.
  • FastPollingMutexSem on RT hot paths (never OS mutexes).
  • Each component dir has Makefile.gcc (wrapper), Makefile.inc (sources/includes), and depends.x86-linux/dependsRaw.x86-linux (generated dependency files).
  • EUPL v1.1 license headers on C++ sources.

Qt client (Client/streamhub-qt/): native Widgets oscilloscope, feature/UX-equivalent to the ImGui client, speaking the identical StreamHub WebSocket protocol. CMake autodetects Qt6 (preferred) or Qt5 (find_package(QT NAMES Qt6 Qt5 ...) then Qt${QT_VERSION_MAJOR}:: targets) for old-Linux back-compat. It reuses ../streamhub/Protocol.{h,cpp} and SignalBuffer.h verbatim (framework-free C++17); those structs have members named signals, which collide with Qt's signals/slots/emit macros, so the build sets QT_NO_KEYWORDS and all Qt classes use Q_SIGNALS:/Q_SLOTS:/Q_EMIT. Single GUI thread (QWebSocket signals arrive on the GUI thread, no locks); a 60 Hz QTimer drives repaint. Plotting is custom QPainter (no QtCharts/QCustomPlot) for ImPlot parity and zero extra deps. Run: ./build/StreamHubQtClient --host HOST --port 8090 (long -- options; single-dash -host is misparsed as clustered short flags).