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>