9.6 KiB
quic_ecs_dt — Project Guide for Claude
What & why
Source repo for "QUIC + ECS as Complementary Transport and Runtime Substrates for Industrial Digital Twins" — UCAmI 2026 (Plantevin & Francillette, UQAC). Third paper in a sequence; the first two are at IEEE SWC 2026:
plantevin2026ecs— ECS as runtime substrate for industrial DT (200k assets @ 114 Hz on Pi 5).plantevin2026quic— QUIC partial reliability for DT sensor streams (94% P99 reduction vs TCP at 5% loss).
UCAmI hypothesis (the composition question): prior work shows ECS and QUIC each work as substrates independently. Does integrating real QUIC traffic into a Bevy ECS ingest path introduce coupling that degrades either one's claimed properties? The paper argues no, and measures it.
Architecture
Three-tier QUIC ↔ ECS bridge, headless Bevy runtime:
| Tier | QUIC primitive | Use case | Channel cap |
|---|---|---|---|
| T1 | Unreliable datagrams (RFC 9221) | High-freq ephemeral telemetry; drops OK | 1024, lossy backpressure |
| T2 | Unidirectional streams | Ordered threshold events; reliable | 512, fully drained |
| T3 | Bidirectional streams | Actuator commands w/ ACK | 256, fully drained |
QUIC server runs on a dedicated OS thread with a Tokio multi-thread runtime; pushes decoded QuicMessage (UUID + stream_id + f64 + ts + seq) into tokio::sync::mpsc per tier; Bevy IngestSystem drains in PreUpdate. Pattern is in substrate/src/transport/ecs.rs.
Target hardware: CM5 (BCM2712, Cortex-A76, 4 GB) as DT runtime; M4 Max as traffic generator; 1 Gbps direct Ethernet. Both rigs are in hand.
Repo map
quic_ecs_dt/
├── paper/ Quarto + LNCS source — single index.qmd, refs in references.bib
├── substrate/ Rust crate: Bevy 0.18 + Quinn 0.11 + rustls 0.23 + Tokio
│ └── src/
│ ├── main.rs App::new, MinimalPlugins, EcsQuicTransportPlugin
│ ├── config.rs figment chain: defaults → config.toml → APP_* env
│ └── transport/
│ ├── mod.rs QuicMessage struct
│ ├── ecs.rs Plugin: tokio thread + 3 mpsc + PreUpdate ingest
│ └── server.rs run_substrate_server (EMPTY STUB)
├── simulator/ Rust crate: stub today; will be Quinn client + Bevy sensor generators
├── data/ (created by M6) loopback/, two_machine/ — raw CSVs committed, *_processed ignored
├── Cargo.toml workspace
└── Makefile render, preview, build, build-cm5, deploy-cm5
Status
| Area | State |
|---|---|
AppConfig figment loader (defaults → TOML → env) |
Done — substrate/src/config.rs:42 |
| 3-tier MPSC bridge scaffolding (Tokio thread + Bevy plugin) | Done — substrate/src/transport/ecs.rs |
QuicMessage struct (no codec yet) |
Defined — substrate/src/transport/mod.rs:4 |
| Quinn server (accept loop, demux, decode) | Empty stub — substrate/src/transport/server.rs:4 |
| TLS / self-signed cert | Done (M1) — certs/server.{crt,key} via make certs, gitignored |
Wire codec for QuicMessage (38 B fixed LE) |
Done (M1) — substrate/src/transport/mod.rs:35; 4 unit tests passing |
tracing-subscriber init w/ RUST_LOG |
Done (M1) — substrate/src/main.rs:8-12 |
ECS components (RawSensorData) + 5 systems (Ingest/Sim/Export/FaultInjection/Diagnostics) |
Missing — placeholder at substrate/src/transport/ecs.rs:26 |
| VictoriaMetrics + Grafana export | Missing |
| Simulator (Quinn client + sensor generators) | Hello, world! — simulator/src/main.rs |
config.toml at repo root |
Done (M1) — config.toml; loaded by substrate/src/main.rs:9 |
| Benchmark harness (sweep + CSV writer) | Missing |
| CM5 cross-compile / deploy | Wired in Makefile:30; not exercised |
cargo run -p substrate boots, prints the loaded config, and idles on the (still-empty) Quinn server. MinimalPlugins busy-loops the ECS schedule by default — expected, will gate to tick_rate_hz in M4.
Roadmap
Each milestone has one verification gate. Update Status here as we go.
- M1 — Wire codec & root config. ✅ Done 2026-05-04. Hand-rolled little-endian codec on
QuicMessage(38 B fixed: 16 UUID + 2 stream_id + 8 f64 + 8 ts_us + 4 seq) with roundtrip + layout + length-error tests;config.tomlat repo root; dev TLS viamake certs; structuredtracing-subscriberinit readsRUST_LOG(defaultinfo). - M2 — Quinn server + self-signed TLS. Fill substrate/src/transport/server.rs:
Endpoint::server, accept loop, demux T1=datagrams / T2=uni / T3=bi, push into matchingmpsc::Sender. Usercgenfor a dev cert at boot. Verify: a Quinn smoke client connects, server logs handshake. - M3 — Simulator client. Replace simulator/src/main.rs with a Bevy app: Quinn client, N synthetic devices, configurable per-tier rates. Verify: end-to-end loopback drains messages on all three tiers.
- M4 — ECS world. Define
RawSensorDataand the 5 systems the paper names (FaultInjectionSystem,IngestSystem,SimulationSystem,ExportSystem,DiagnosticsSystem). WireIngestSysteminto the existingPreUpdateslot. Verify: with 10k simulated devices, entity count stabilizes;DiagnosticsSystemlogs steady tick rate. - M5 — Observability (VictoriaMetrics + Grafana). Substrate exposes Prometheus-format
/metrics(usemetrics+metrics-exporter-prometheus): tick rate, RSS, per-tier P50/P99/P999, channel depth, drop count. Commit a Grafana dashboard JSON. Verify:curl :PORT/metricsreturns labeled samples; dashboard renders against VM. - M6 — Benchmark harness. Sweep
entity_count ∈ {10k, 50k, 100k, 200k}×loss_rate ∈ {0%, 1%, 5%}with 2k warmup + 5k measurement ticks. Loss viatc netemor in-app injection. Writesdata/loopback/final_table.csv. Verify: one full sweep on M4 Max produces a CSV the Quarto figures consume. - M7 — CM5 cross-compile & deploy. Exercise Makefile:30 (
build-cm5,deploy-cm5); set realCM5_HOST. Verify: binary runs on CM5 with a feed from M4 Max over 1 Gbps Ethernet. - M8 — Two-machine run + paper render. Sweep with simulator on M4 Max → substrate on CM5; populate
data/two_machine/final_table.csv;make renderproduces a PDF. Update §Evaluation prose to reflect actual numbers. Current paper figures (241 Hz, 64 µs / 15.8 ms P99, 2.6 µs jitter, 1.02 MB/1k, R²=0.9999) are aspirational placeholders — they may move and the conclusions may shift; that's expected.
Conventions
- Rust: edition 2024; workspace at root with
simulator+substrate;opt-level=1dev,opt-level=3for deps. - Pinned crates: Bevy 0.18, Quinn 0.11, rustls 0.23, Tokio 1 (full), figment 0.10 (toml + env), uuid 1.23 (v4), serde 1.
- Config:
figmentchain — defaults in substrate/src/config.rs:25 →config.toml→ envAPP_*(double-underscore for nesting, e.g.APP_NETWORK__SERVER_PORT=9000). - Bevy: headless —
MinimalPluginsonly; do not pull rendering plugins. - Tokio↔Bevy: keep the dedicated-thread + mpsc pattern in substrate/src/transport/ecs.rs:49; do not block the ECS schedule on async work.
- Paper: Quarto + LNCS template (paper/_extensions/template.tex, paper/_quarto.yml). Never commit
llncs.clsorsplncs04.bst— CTAN licensing; download per README.md:25-34. - Data: raw CSVs under
data/are committed;*_processed.csvis gitignored. Paper figures consumedata/loopback/final_table.csvanddata/two_machine/final_table.csv. - Build artifacts:
target/,paper/_output/,paper/figures/,paper/.quarto/,paper/index.texall gitignored.
Run / verify
make certs # generate certs/server.{crt,key} (ECDSA P-256, SAN: localhost/cm5.local/127.0.0.1/::1)
make build # cargo build --release (native, depends on certs)
make build-cm5 # aarch64 cross-build for the CM5 (depends on certs)
make deploy-cm5 # scp to $CM5_HOST (set in env or override Makefile var)
make render # build the paper PDF
make preview # live-reload paper preview at :4848
make clean # cargo clean + drop generated paper outputs
certs/ is gitignored; make build regenerates the dev cert if missing. From the repo root: cargo run -p substrate boots, prints the loaded AppConfig, and idles. config.toml and cert paths are resolved relative to the cwd — always launch from the repo root.
Key references
- Prior self-citations:
plantevin2026ecs,plantevin2026quic(both IEEE SWC 2026, "to appear"). - QUIC: RFC 9000 (core), RFC 9221 (unreliable datagrams).
- DT foundations: Tao et al. 2019; Grieves & Vickers 2017; Minerva et al. 2020.
- ECS: Nystrom 2014, Game Programming Patterns.
- Mixed-reliability transport: Peeck et al. (W2RP for DDS).
- DT sync metrics: Çakır et al. 2023 (Twin Alignment Ratio); Bellavista et al. 2023 (ODTE).
- Industrial QUIC/IIoT: Fernández et al. 2021; Boeding et al. 2025.
- Full bibliography: paper/references.bib.