mirror of
https://github.com/ruvnet/RuView.git
synced 2026-05-17 04:19:13 +00:00
Two real bugs found while pushing the v0.8.0 image to Docker Hub: ## Rust 1.85 -> 1.90 `hnsw_rs 0.3.4` (transitive via wifi-densepose-ruvector -> ruvector-attn-mincut -> hnsw_rs) calls `nbp.is_multiple_of(500_000)`. `is_multiple_of` on unsigned integers was stabilised in Rust 1.87 (rust-lang/rust#128101 — RFC 3565). On 1.85 the compile fails with: error[E0658]: use of unstable library feature `unsigned_is_multiple_of` --> hnsw_rs-0.3.4/src/hnswio.rs:736:20 Pinned to 1.90 for reproducibility — a comment in the Dockerfile flags the 1.87 MSRV requirement so a future downgrade can't quietly break it. ## .gitattributes — force LF on shell scripts + Dockerfile Without a `.gitattributes`, git's default `core.autocrlf=true` on Windows converts shell scripts to CRLF on checkout. `COPY`ing `docker/docker-entrypoint.sh` into a Linux image then preserves CRLF. The shebang line `#!/bin/sh\r\n` causes `exec /app/docker-entrypoint.sh` to fail with: exec /app/docker-entrypoint.sh: no such file or directory The kernel tries to look up an interpreter literally named `/bin/sh\r`, which doesn't exist. Container exits immediately. The first v0.8.0 image push (digest sha256:7957…44fa) suffered exactly this; the re-pushed image (digest sha256:e9f4…d38315) was built on a renormalised tree. The .gitattributes rule forces LF for: - *.sh / *.bash - Dockerfile* - docker/* (covers docker-entrypoint.sh + docker-compose.yml) - scripts/* - `verify` (the proof-replay wrapper — same root cause as if it had landed CRLF in someone's clone) Binary file globs (*.bin, *.wasm, *.rvf, *.pcap, etc.) explicitly marked binary so text-normalisation never touches them. ## CHANGELOG — drop the false `--introspection` flag claim The CHANGELOG entry for v0.8.0 said the introspection endpoints were "off by default, enabled via `--introspection`". That isn't true: `sensing-server --help` has no such flag. The routes are mounted unconditionally in `main.rs`. The per-frame `update()` p99 of 0.041 ms (~24× under D4's 1 ms budget) makes always-on viable; the "off by default" framing came from an earlier draft of ADR-099 that the implementation outgrew. Corrected. ## Verification End-to-end smoke test of the pushed image: docker run -d -p 13000:3000 -e CSI_SOURCE=simulated -e SENSING_BIND_ADDR=0.0.0.0 ruvnet/wifi-densepose:v0.8.0 /health -> {"status":"ok","source":"simulated",...} /api/v1/info -> {"backend":"rust","features":{"ruvector":true,"signal_processing":true,...}} /api/v1/introspection/snapshot -> {"regime":"unknown", "regime_changed":false,"top_k_similarity":[]} (ADR-099 shape exact) /ui/observatory.html -> HTTP 200, 15 KB Published manifest digests: ruvnet/wifi-densepose:v0.8.0 -> sha256:e9f4c5af…d38315 ruvnet/wifi-densepose:latest -> sha256:e9f4c5af…d38315 Co-Authored-By: claude-flow <ruv@ruv.net>
87 lines
3.2 KiB
Text
87 lines
3.2 KiB
Text
# WiFi-DensePose Rust Sensing Server
|
|
# Includes RuVector signal intelligence crates
|
|
# Multi-stage build for minimal final image
|
|
|
|
# Stage 1: Build
|
|
# Rust 1.87+ is required: `hnsw_rs 0.3.4` (transitive via wifi-densepose-ruvector ->
|
|
# ruvector-attn-mincut) uses `u*::is_multiple_of`, stabilised in 1.87. Pinning to a
|
|
# recent stable (1.90) for reproducibility — bump cautiously since reproducible
|
|
# builds rely on this.
|
|
FROM rust:1.90-bookworm AS builder
|
|
|
|
WORKDIR /build
|
|
|
|
# Copy workspace files
|
|
COPY v2/Cargo.toml v2/Cargo.lock ./
|
|
COPY v2/crates/ ./crates/
|
|
|
|
# Copy vendored RuVector crates
|
|
COPY vendor/ruvector/ /build/vendor/ruvector/
|
|
|
|
# Build release binary
|
|
RUN cargo build --release -p wifi-densepose-sensing-server 2>&1 \
|
|
&& strip target/release/sensing-server
|
|
|
|
# Stage 2: Runtime
|
|
FROM debian:bookworm-slim
|
|
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
ca-certificates \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
WORKDIR /app
|
|
|
|
# Copy binary
|
|
COPY --from=builder /build/target/release/sensing-server /app/sensing-server
|
|
|
|
# Copy UI assets
|
|
COPY ui/ /app/ui/
|
|
|
|
# Sanity-check the assets the runtime actually serves (regression guard for
|
|
# #520/#514 — the published image must include the observatory and pose-fusion
|
|
# dashboards, not just the legacy `index.html` set). Build fails if any of
|
|
# these are missing, so a stale image can't be silently pushed.
|
|
RUN set -e; \
|
|
for f in /app/ui/index.html /app/ui/observatory.html /app/ui/pose-fusion.html /app/ui/viz.html; do \
|
|
test -f "$f" || { echo "FATAL: missing UI asset $f"; exit 1; }; \
|
|
done; \
|
|
for d in /app/ui/observatory /app/ui/pose-fusion /app/ui/components /app/ui/services; do \
|
|
test -d "$d" || { echo "FATAL: missing UI directory $d"; exit 1; }; \
|
|
done; \
|
|
test -x /app/sensing-server || { echo "FATAL: /app/sensing-server is not executable"; exit 1; }; \
|
|
echo "image assets OK"
|
|
|
|
# Optional bearer-token auth on /api/v1/*: leave unset for LAN-mode (default),
|
|
# set to enforce `Authorization: Bearer <token>` (see bearer_auth module, #443).
|
|
# docker run -e RUVIEW_API_TOKEN=$(openssl rand -hex 32) ...
|
|
ENV RUVIEW_API_TOKEN=
|
|
|
|
# HTTP API
|
|
EXPOSE 3000
|
|
# WebSocket
|
|
EXPOSE 3001
|
|
# ESP32 UDP
|
|
EXPOSE 5005/udp
|
|
|
|
ENV RUST_LOG=info
|
|
|
|
# CSI_SOURCE controls which data source the sensing server uses at startup.
|
|
# auto — probe UDP port 5005 for an ESP32 first; fall back to simulation (default)
|
|
# esp32 — receive real CSI frames from an ESP32 device over UDP port 5005
|
|
# wifi — use host Wi-Fi RSSI/scan data (Windows netsh; not available in containers)
|
|
# simulated — generate synthetic CSI frames (no hardware required)
|
|
# Override at runtime: docker run -e CSI_SOURCE=esp32 ...
|
|
ENV CSI_SOURCE=auto
|
|
|
|
# MODELS_DIR controls where the server scans for .rvf model files.
|
|
# Mount a host directory here to make models visible to the API:
|
|
# docker run -v /path/to/models:/app/models -e MODELS_DIR=/app/models ...
|
|
ENV MODELS_DIR=data/models
|
|
|
|
COPY docker/docker-entrypoint.sh /app/docker-entrypoint.sh
|
|
|
|
# Exec-form ENTRYPOINT so Docker appends user arguments correctly.
|
|
# Pass flags directly: docker run <image> --source esp32 --tick-ms 500
|
|
# Or use env vars: docker run -e CSI_SOURCE=esp32 <image>
|
|
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
|
CMD []
|