Symptom (Brock, 2026-08-06): running the test repeatedly, ping comes back essentially flat around 60ms and jitter around 9, run after run. Download/upload look accurate and vary normally.
Ruled out by reading the code
measureLatency() in js/speedtest.js is correct: 10 sequential real fetch() round-trips, no caching (cache: 'no-store' + cache-busting query param), median for ping, mean-abs-diff for jitter. Nothing hardcoded or mocked client-side.
TestController::ping() is a bare empty 200 with no-store headers — no DB, no storage, no work. Nothing on the server side of the app can be injecting a fixed delay.
So the app's own code isn't fabricating these numbers — a fixed ~60ms is being added to every single request somewhere in the path between the browser and TestController::ping(), and it's consistent enough that jitter (variance between consecutive pings) stays near a floor too instead of reflecting real network variance.
Where to look
Real per-request overhead that would look exactly like this if it isn't being amortized away:
No connection reuse — if each of the 10 /ping fetches opens a fresh TCP+TLS handshake instead of reusing keep-alive, that's your fixed floor right there. Check response headers / a packet capture for whether it's one connection or ten.
A proxy hop doing per-request inspection — OPNsense nginx is the only door (per NETWORK.md); if Suricata/CrowdSec or nginx buffering is in the request path with per-request processing cost, that reads as a floor added to every hit, not organic jitter.
Nextcloud middleware overhead — session/auth checks running on every request even though the route is #[NoAdminRequired] #[NoCSRFRequired].
Verification path for whoever picks this up
Compare time curl (or repeated curl -w '%{time_total}\n') against /apps/speedtest/ping:
from a LAN box straight to srv:80 (bypasses OPNsense/nginx entirely)
through the normal public path (https://cloud.bawnet.io/apps/speedtest/ping or wherever it's mounted)
If (1) is near-zero and (2) sits at ~60ms, the fixed cost is in the firewall/proxy hop, not in Nextcloud or the app. If both show it, it's inside Nextcloud/PHP.
Blocks ops/features#33's "verify against the existing librespeed numbers before retiring anything" checklist item — the numbers can't be trusted for that comparison until this is understood.
**Symptom (Brock, 2026-08-06):** running the test repeatedly, ping comes back essentially flat around 60ms and jitter around 9, run after run. Download/upload look accurate and vary normally.
## Ruled out by reading the code
- `measureLatency()` in `js/speedtest.js` is correct: 10 sequential real `fetch()` round-trips, no caching (`cache: 'no-store'` + cache-busting query param), median for ping, mean-abs-diff for jitter. Nothing hardcoded or mocked client-side.
- `TestController::ping()` is a bare empty 200 with no-store headers — no DB, no storage, no work. Nothing on the server side of the app can be injecting a fixed delay.
So the app's own code isn't fabricating these numbers — a fixed ~60ms is being added to every single request somewhere in the path between the browser and `TestController::ping()`, and it's consistent enough that jitter (variance between consecutive pings) stays near a floor too instead of reflecting real network variance.
## Where to look
Real per-request overhead that would look exactly like this if it isn't being amortized away:
- **No connection reuse** — if each of the 10 `/ping` fetches opens a fresh TCP+TLS handshake instead of reusing keep-alive, that's your fixed floor right there. Check response headers / a packet capture for whether it's one connection or ten.
- **A proxy hop doing per-request inspection** — OPNsense nginx is the only door (per NETWORK.md); if Suricata/CrowdSec or nginx buffering is in the request path with per-request processing cost, that reads as a floor added to every hit, not organic jitter.
- **Nextcloud middleware overhead** — session/auth checks running on every request even though the route is `#[NoAdminRequired] #[NoCSRFRequired]`.
## Verification path for whoever picks this up
Compare `time curl` (or repeated `curl -w '%{time_total}\n'`) against `/apps/speedtest/ping`:
1. from a LAN box straight to `srv:80` (bypasses OPNsense/nginx entirely)
2. through the normal public path (`https://cloud.bawnet.io/apps/speedtest/ping` or wherever it's mounted)
If (1) is near-zero and (2) sits at ~60ms, the fixed cost is in the firewall/proxy hop, not in Nextcloud or the app. If both show it, it's inside Nextcloud/PHP.
Blocks ops/features#33's "verify against the existing librespeed numbers before retiring anything" checklist item — the numbers can't be trusted for that comparison until this is understood.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
🐄 PERSONAL SOVEREIGN NODE • ZERO-TRUST ARCHITECTURE · timezone: RSO-Standard-Time · complaints → @neon
Symptom (Brock, 2026-08-06): running the test repeatedly, ping comes back essentially flat around 60ms and jitter around 9, run after run. Download/upload look accurate and vary normally.
Ruled out by reading the code
measureLatency()injs/speedtest.jsis correct: 10 sequential realfetch()round-trips, no caching (cache: 'no-store'+ cache-busting query param), median for ping, mean-abs-diff for jitter. Nothing hardcoded or mocked client-side.TestController::ping()is a bare empty 200 with no-store headers — no DB, no storage, no work. Nothing on the server side of the app can be injecting a fixed delay.So the app's own code isn't fabricating these numbers — a fixed ~60ms is being added to every single request somewhere in the path between the browser and
TestController::ping(), and it's consistent enough that jitter (variance between consecutive pings) stays near a floor too instead of reflecting real network variance.Where to look
Real per-request overhead that would look exactly like this if it isn't being amortized away:
/pingfetches opens a fresh TCP+TLS handshake instead of reusing keep-alive, that's your fixed floor right there. Check response headers / a packet capture for whether it's one connection or ten.#[NoAdminRequired] #[NoCSRFRequired].Verification path for whoever picks this up
Compare
time curl(or repeatedcurl -w '%{time_total}\n') against/apps/speedtest/ping:srv:80(bypasses OPNsense/nginx entirely)https://cloud.bawnet.io/apps/speedtest/pingor wherever it's mounted)If (1) is near-zero and (2) sits at ~60ms, the fixed cost is in the firewall/proxy hop, not in Nextcloud or the app. If both show it, it's inside Nextcloud/PHP.
Blocks ops/features#33's "verify against the existing librespeed numbers before retiring anything" checklist item — the numbers can't be trusted for that comparison until this is understood.