README.md describes an earlier version of NetWatch. Fourteen concrete claims contradict the code on main at fbfe1df, and TODO.md describes a branch state that no longer exists. All eight REPO_POLICIES-required README sections are present, so this is purely about content accuracy.
Factually wrong
#
README says
Code actually does
1
line 92: "HEAD requests"
src/main.js:365method: "GET". Gateway detector likewise src/main.js:176. The app's own footer (src/main.js:663) correctly says GET, so the running UI contradicts the README. Line 151 repeats the error.
2
lines 52-54: "zero-dependency SPA ... no backend required"
A Go backend exists: 15 files under backend/, chi server, zstd report storage, its own Dockerfile.backend and CI step.
3
line 119: "2s update interval"
src/main.js:11updateInterval: 3000. UI default is also 3s (src/main.js:610).
4
lines 93-94: "1-second timeout; anything over 1000ms is unreachable"
src/main.js:16-21: requestTimeout = 2900ms, maxLatency = 2900ms. The 1000ms figure is graphMaxLatency — the chart Y-axis ceiling, a different constant. The README conflates the two.
5
line 77: "22 WAN hosts"
26. Count src/main.js:34-104.
6
lines 78-80: "7 S3 regional endpoints"
8 — Singapore (src/main.js:63-66) is omitted from the list.
These do not exist. No storage.googleapis.com entry anywhere in src/main.js. Entirely phantom.
8
—
6 Hetzner endpoints (src/main.js:79-103) and plain Google (:44) are undocumented.
9
line 61: "CONFIG: Frozen configuration object"
No Object.freeze anywhere; src/main.js:1202 mutates CONFIG.updateInterval at runtime.
10
line 120: "green (HEALTHY) or red (DEGRADED)" — two states
src/main.js:326-338 returns four: healthy, slow, degraded, offline. DEGRADED renders orange, not red; OFFLINE is red.
11
line 121: "reachable count, min/max/avg"
Also renders median, a history-window min/max pair, and a checks counter.
12
line 138: "Listens on port 8080 by default (override with PORT env var)"
nginx.conf:2 is a hardcoded listen 8080;. No envsubst, no template, no entrypoint script. The override does not exist.
13
lines 154-155: "Local gateway: The 192.168.100.1 endpoint"
192.168.100.1 is LOCAL_CPE, the cable modem (src/main.js:126-127), explicitly upstream of the gateway. The real gateway is auto-detected from GATEWAY_CANDIDATES (:136-141). Lines 81-84 get this right and contradict lines 154-155.
14
—
Shipped features absent from the README entirely: user-selectable interval dropdown (1s-60s), debug log panel with 5 severity levels, host pinning, latency-based auto-sorting, the recovery probe, local + UTC clocks, first-tick discard for DNS/TLS warmup, and the commit-hash footer link. All are recorded as done in TODO.md.
Structural problems
Getting Started documents raw tools, not make.README.md:8-24 lists yarn install, yarn dev, yarn build, docker build. Zero make commands. This contradicts "Always use Makefile targets instead of invoking the underlying tools directly. The Makefile is the single source of truth." The README's own Entrypoints section documents the script layer correctly — Getting Started just ignores it.
The backend is invisible in the root README. Not one mention, despite being half the repo.
Two TODO lists that disagree.README.md:159-165 has five items; root TODO.md has a different structure and different content. TODO.md:42-43 claims .editorconfig and a hooks Makefile target are both missing — hooks has existed at Makefile:34-35 for some time, so that line is stale.
TODO.md Status is wrong. It says "Backend work in flight on feat/reportbuf-storage (dirty: src/main.js) ... backend is new and unmerged." The backend is merged (commit add5f1f), the working tree is clean, and TODO.md:46-47 asks what to do about an untracked resume.sh that no longer exists.
Definition of done
Every one of the 14 items above is corrected against the actual code. Verify each against the source rather than trusting this list — it was compiled by audit and should itself be checked.
Getting Started leads with make targets (make setup, make dev, make check, make docker), with the underlying yarn commands mentioned only as context if at all.
The backend is documented in the root README: what it is, how to build and run it, and its API surface.
The two TODO lists are reconciled into a single source of truth. Policy puts the TODO in README.md; TODO.md additionally carries the Workflow/Status/Next Step/Completed/Future structure this repo uses. Keep both files but make them non-contradictory, and state in the PR how you divided responsibility between them.
TODO.md Status and Next Step reflect reality: backend merged, tree clean, no resume.sh, hooks target exists.
make fmt has been run and the result is included in the commit. No unformatted markdown.
make check passes.
Commit title ends with (closes #N).
Implementation requirements
This is a documentation-only change. Do not modify any code, config, script, CI, or build file. If you find yourself wanting to fix the code to match the docs, stop — file it or leave it to the issue that owns it. In particular, do not implement the PORT override for nginx here (item 12); correct the README to describe current behaviour, and note that the missing override is tracked separately.
Markdown must be formatted with the repo's own tooling (make fmt) before committing.
Verbatim identifiers (filenames, env vars, branch names, commands) go in backticks.
Dates in ISO 8601 (YYYY-MM-DD).
No attribution trailers in the commit message.
## Problem
`README.md` describes an earlier version of NetWatch. Fourteen concrete claims contradict the code on `main` at `fbfe1df`, and `TODO.md` describes a branch state that no longer exists. All eight REPO_POLICIES-required README sections are present, so this is purely about content accuracy.
### Factually wrong
| # | README says | Code actually does |
| --- | --- | --- |
| 1 | line 92: "**HEAD requests**" | `src/main.js:365` `method: "GET"`. Gateway detector likewise `src/main.js:176`. The app's own footer (`src/main.js:663`) correctly says GET, so the running UI contradicts the README. Line 151 repeats the error. |
| 2 | lines 52-54: "zero-dependency SPA ... **no backend required**" | A Go backend exists: 15 files under `backend/`, chi server, zstd report storage, its own `Dockerfile.backend` and CI step. |
| 3 | line 119: "**2s** update interval" | `src/main.js:11` `updateInterval: 3000`. UI default is also 3s (`src/main.js:610`). |
| 4 | lines 93-94: "**1-second timeout**; anything over **1000ms** is unreachable" | `src/main.js:16-21`: `requestTimeout` = 2900ms, `maxLatency` = 2900ms. The 1000ms figure is `graphMaxLatency` — the chart Y-axis ceiling, a different constant. The README conflates the two. |
| 5 | line 77: "**22** WAN hosts" | 26. Count `src/main.js:34-104`. |
| 6 | lines 78-80: "**7** S3 regional endpoints" | 8 — Singapore (`src/main.js:63-66`) is omitted from the list. |
| 7 | lines 79-80: "4 GCS locational endpoints (Iowa, Belgium, Singapore, Sydney)" | **These do not exist.** No `storage.googleapis.com` entry anywhere in `src/main.js`. Entirely phantom. |
| 8 | — | 6 Hetzner endpoints (`src/main.js:79-103`) and plain `Google` (`:44`) are undocumented. |
| 9 | line 61: "`CONFIG`: **Frozen** configuration object" | No `Object.freeze` anywhere; `src/main.js:1202` mutates `CONFIG.updateInterval` at runtime. |
| 10 | line 120: "green (HEALTHY) or red (DEGRADED)" — two states | `src/main.js:326-338` returns **four**: `healthy`, `slow`, `degraded`, `offline`. DEGRADED renders orange, not red; OFFLINE is red. |
| 11 | line 121: "reachable count, min/max/avg" | Also renders median, a history-window min/max pair, and a checks counter. |
| 12 | line 138: "Listens on port 8080 by default (**override with `PORT` env var**)" | `nginx.conf:2` is a hardcoded `listen 8080;`. No `envsubst`, no template, no entrypoint script. The override does not exist. |
| 13 | lines 154-155: "**Local gateway**: The 192.168.100.1 endpoint" | `192.168.100.1` is `LOCAL_CPE`, the cable modem (`src/main.js:126-127`), explicitly upstream of the gateway. The real gateway is auto-detected from `GATEWAY_CANDIDATES` (`:136-141`). Lines 81-84 get this right and contradict lines 154-155. |
| 14 | — | Shipped features absent from the README entirely: user-selectable interval dropdown (1s-60s), debug log panel with 5 severity levels, host pinning, latency-based auto-sorting, the recovery probe, local + UTC clocks, first-tick discard for DNS/TLS warmup, and the commit-hash footer link. All are recorded as done in `TODO.md`. |
### Structural problems
- **Getting Started documents raw tools, not `make`.** `README.md:8-24` lists `yarn install`, `yarn dev`, `yarn build`, `docker build`. Zero `make` commands. This contradicts "Always use Makefile targets instead of invoking the underlying tools directly. The Makefile is the single source of truth." The README's own **Entrypoints** section documents the script layer correctly — Getting Started just ignores it.
- **The backend is invisible in the root README.** Not one mention, despite being half the repo.
- **Two TODO lists that disagree.** `README.md:159-165` has five items; root `TODO.md` has a different structure and different content. `TODO.md:42-43` claims `.editorconfig` and a `hooks` Makefile target are both missing — `hooks` has existed at `Makefile:34-35` for some time, so that line is stale.
- **`TODO.md` Status is wrong.** It says "Backend work in flight on feat/reportbuf-storage (dirty: src/main.js) ... backend is new and unmerged." The backend **is** merged (commit `add5f1f`), the working tree is clean, and `TODO.md:46-47` asks what to do about an untracked `resume.sh` that no longer exists.
## Definition of done
- [ ] Every one of the 14 items above is corrected against the actual code. Verify each against the source rather than trusting this list — it was compiled by audit and should itself be checked.
- [ ] Getting Started leads with `make` targets (`make setup`, `make dev`, `make check`, `make docker`), with the underlying `yarn` commands mentioned only as context if at all.
- [ ] The backend is documented in the root README: what it is, how to build and run it, and its API surface.
- [ ] The two TODO lists are reconciled into a single source of truth. Policy puts the TODO in `README.md`; `TODO.md` additionally carries the Workflow/Status/Next Step/Completed/Future structure this repo uses. Keep both files but make them non-contradictory, and state in the PR how you divided responsibility between them.
- [ ] `TODO.md` Status and Next Step reflect reality: backend merged, tree clean, no `resume.sh`, `hooks` target exists.
- [ ] `make fmt` has been run and the result is included in the commit. No unformatted markdown.
- [ ] `make check` passes.
- [ ] Commit title ends with ` (closes #N)`.
## Implementation requirements
- **This is a documentation-only change.** Do not modify any code, config, script, CI, or build file. If you find yourself wanting to fix the code to match the docs, stop — file it or leave it to the issue that owns it. In particular, do **not** implement the `PORT` override for nginx here (item 12); correct the README to describe current behaviour, and note that the missing override is tracked separately.
- Markdown must be formatted with the repo's own tooling (`make fmt`) before committing.
- Verbatim identifiers (filenames, env vars, branch names, commands) go in backticks.
- Dates in ISO 8601 (YYYY-MM-DD).
- No attribution trailers in the commit message.
clawbot
added this to the 1.0.0 milestone 2026-08-09 03:43:24 +02:00
.editorconfig — done by PR #35, which moved the org-model file to the repo root.
hooks target — was already wrong before any of this work. The root Makefile has had hooks: @script/install-precommit since the scripts-to-rule-them-all commit (e45bc57). The bullet has been describing non-existent work for some time.
PR #35 deliberately left it alone to avoid manufacturing a conflict with PR #31, which rewrites Status and Next Step. That reasoning was sound for those two sections but does not extend to Future Steps, which #31 does not touch — so the bullet survived, and it lands here.
Add to this issue's definition of done
The stale Future Steps compliance bullet is deleted (not amended — both halves are complete or were never real).
The remaining Future Steps bullets are checked against reality the same way. The existing DoD already covers the resume.sh bullet, which refers to a file that no longer exists. Verify each surviving bullet still describes work that is actually outstanding, rather than trusting the list.
Note on sequencing: by the time this issue is implemented, PRs #31 and #35 should both have landed and TODO.md will have moved. Re-read the file as it exists then rather than working from the line numbers quoted in this issue's original description.
## Additional item: `TODO.md`'s first `Future Steps` bullet is stale in both halves
Surfaced during the review of PR #35. Adding it here because this issue owns `TODO.md` accuracy.
`TODO.md` `Future Steps` bullet 1:
> Compliance top-up as one small commit: add .editorconfig and add the hooks target to the Makefile
Both halves are wrong as of PR #35:
- **`.editorconfig`** — done by PR #35, which moved the org-model file to the repo root.
- **`hooks` target** — was **already** wrong before any of this work. The root `Makefile` has had `hooks: @script/install-precommit` since the scripts-to-rule-them-all commit (`e45bc57`). The bullet has been describing non-existent work for some time.
PR #35 deliberately left it alone to avoid manufacturing a conflict with PR #31, which rewrites Status and Next Step. That reasoning was sound for those two sections but does not extend to `Future Steps`, which #31 does not touch — so the bullet survived, and it lands here.
### Add to this issue's definition of done
- [ ] The stale `Future Steps` compliance bullet is deleted (not amended — both halves are complete or were never real).
- [ ] The remaining `Future Steps` bullets are checked against reality the same way. The existing DoD already covers the `resume.sh` bullet, which refers to a file that no longer exists. Verify each surviving bullet still describes work that is actually outstanding, rather than trusting the list.
Note on sequencing: by the time this issue is implemented, PRs #31 and #35 should both have landed and `TODO.md` will have moved. Re-read the file as it exists then rather than working from the line numbers quoted in this issue's original description.
Plan. Documentation only, as the issue says; one PR, the last of the units that change README.md (after #28 and #45, which add make build, script/dev and the dependency targets that Getting Started should name).
Much has changed since the audit: check each of the 14 items and the structural points against the tree at that time, fix those still wrong, and drop those already true. The list is a starting point, not the scope: every sentence of README.md and TODO.md that is false of the tree is in scope.
Getting Started leads with make targets; the backend gets a short section in the root README.md (what it is, how it is built and run inside the image, its routes), pointing to backend/README.md for its settings.
One to-do list: TODO.md keeps Workflow, Status, Next Step, Completed and Future Steps; the README's TODO section points to it. The PR says how the two divide.
TODO.md Workflow says to branch from next and open the PR against next, as this repo works; Status and Next Step describe the tree as it is; Future Steps holds only work that is still open, each item linked to its issue.
A missing behaviour (for example a PORT override for nginx) is described as it is, not built; if no issue tracks it, say so in the PR.
Model: opus-5-5
Plan. Documentation only, as the issue says; one PR, the last of the units that change `README.md` (after https://git.eeqj.de/sneak/netwatch/issues/28 and https://git.eeqj.de/sneak/netwatch/issues/45, which add `make build`, `script/dev` and the dependency targets that Getting Started should name).
1. Much has changed since the audit: check each of the 14 items and the structural points against the tree at that time, fix those still wrong, and drop those already true. The list is a starting point, not the scope: every sentence of `README.md` and `TODO.md` that is false of the tree is in scope.
2. Getting Started leads with `make` targets; the backend gets a short section in the root `README.md` (what it is, how it is built and run inside the image, its routes), pointing to `backend/README.md` for its settings.
3. One to-do list: `TODO.md` keeps Workflow, Status, Next Step, Completed and Future Steps; the README's TODO section points to it. The PR says how the two divide.
4. `TODO.md` Workflow says to branch from `next` and open the PR against `next`, as this repo works; Status and Next Step describe the tree as it is; Future Steps holds only work that is still open, each item linked to its issue.
5. A missing behaviour (for example a `PORT` override for nginx) is described as it is, not built; if no issue tracks it, say so in the PR.
Model: opus-5-5
Also in scope: test/viewport/README.md (lines 107-113 on next) still says vitest will test the functions; the frontend unit tests use Node's built-in test runner (#99). Found by that PR's review.
Model: opus-5-5
Also in scope: `test/viewport/README.md` (lines 107-113 on `next`) still says `vitest` will test the functions; the frontend unit tests use Node's built-in test runner (https://git.eeqj.de/sneak/netwatch/pulls/99). Found by that PR's review.
Model: opus-5-5
Done in #110: every sentence of README.md, TODO.md and test/viewport/README.md checked against next and corrected. The PR body says how the README and TODO.md divide the work and which open items no issue tracks yet.
Model: opus-5-5
Done in https://git.eeqj.de/sneak/netwatch/pulls/110: every sentence of `README.md`, `TODO.md` and `test/viewport/README.md` checked against `next` and corrected. The PR body says how the README and `TODO.md` divide the work and which open items no issue tracks yet.
Model: opus-5-5
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.
Problem
README.mddescribes an earlier version of NetWatch. Fourteen concrete claims contradict the code onmainatfbfe1df, andTODO.mddescribes a branch state that no longer exists. All eight REPO_POLICIES-required README sections are present, so this is purely about content accuracy.Factually wrong
src/main.js:365method: "GET". Gateway detector likewisesrc/main.js:176. The app's own footer (src/main.js:663) correctly says GET, so the running UI contradicts the README. Line 151 repeats the error.backend/, chi server, zstd report storage, its ownDockerfile.backendand CI step.src/main.js:11updateInterval: 3000. UI default is also 3s (src/main.js:610).src/main.js:16-21:requestTimeout= 2900ms,maxLatency= 2900ms. The 1000ms figure isgraphMaxLatency— the chart Y-axis ceiling, a different constant. The README conflates the two.src/main.js:34-104.src/main.js:63-66) is omitted from the list.storage.googleapis.comentry anywhere insrc/main.js. Entirely phantom.src/main.js:79-103) and plainGoogle(:44) are undocumented.CONFIG: Frozen configuration object"Object.freezeanywhere;src/main.js:1202mutatesCONFIG.updateIntervalat runtime.src/main.js:326-338returns four:healthy,slow,degraded,offline. DEGRADED renders orange, not red; OFFLINE is red.PORTenv var)"nginx.conf:2is a hardcodedlisten 8080;. Noenvsubst, no template, no entrypoint script. The override does not exist.192.168.100.1isLOCAL_CPE, the cable modem (src/main.js:126-127), explicitly upstream of the gateway. The real gateway is auto-detected fromGATEWAY_CANDIDATES(:136-141). Lines 81-84 get this right and contradict lines 154-155.TODO.md.Structural problems
make.README.md:8-24listsyarn install,yarn dev,yarn build,docker build. Zeromakecommands. This contradicts "Always use Makefile targets instead of invoking the underlying tools directly. The Makefile is the single source of truth." The README's own Entrypoints section documents the script layer correctly — Getting Started just ignores it.README.md:159-165has five items; rootTODO.mdhas a different structure and different content.TODO.md:42-43claims.editorconfigand ahooksMakefile target are both missing —hookshas existed atMakefile:34-35for some time, so that line is stale.TODO.mdStatus is wrong. It says "Backend work in flight on feat/reportbuf-storage (dirty: src/main.js) ... backend is new and unmerged." The backend is merged (commitadd5f1f), the working tree is clean, andTODO.md:46-47asks what to do about an untrackedresume.shthat no longer exists.Definition of done
maketargets (make setup,make dev,make check,make docker), with the underlyingyarncommands mentioned only as context if at all.README.md;TODO.mdadditionally carries the Workflow/Status/Next Step/Completed/Future structure this repo uses. Keep both files but make them non-contradictory, and state in the PR how you divided responsibility between them.TODO.mdStatus and Next Step reflect reality: backend merged, tree clean, noresume.sh,hookstarget exists.make fmthas been run and the result is included in the commit. No unformatted markdown.make checkpasses.(closes #N).Implementation requirements
PORToverride for nginx here (item 12); correct the README to describe current behaviour, and note that the missing override is tracked separately.make fmt) before committing.Additional item:
TODO.md's firstFuture Stepsbullet is stale in both halvesSurfaced during the review of PR #35. Adding it here because this issue owns
TODO.mdaccuracy.TODO.mdFuture Stepsbullet 1:> Compliance top-up as one small commit: add .editorconfig and add the hooks target to the Makefile
Both halves are wrong as of PR #35:
.editorconfig— done by PR #35, which moved the org-model file to the repo root.hookstarget — was already wrong before any of this work. The rootMakefilehas hadhooks: @script/install-precommitsince the scripts-to-rule-them-all commit (e45bc57). The bullet has been describing non-existent work for some time.PR #35 deliberately left it alone to avoid manufacturing a conflict with PR #31, which rewrites Status and Next Step. That reasoning was sound for those two sections but does not extend to
Future Steps, which #31 does not touch — so the bullet survived, and it lands here.Add to this issue's definition of done
Future Stepscompliance bullet is deleted (not amended — both halves are complete or were never real).Future Stepsbullets are checked against reality the same way. The existing DoD already covers theresume.shbullet, which refers to a file that no longer exists. Verify each surviving bullet still describes work that is actually outstanding, rather than trusting the list.Note on sequencing: by the time this issue is implemented, PRs #31 and #35 should both have landed and
TODO.mdwill have moved. Re-read the file as it exists then rather than working from the line numbers quoted in this issue's original description.Plan. Documentation only, as the issue says; one PR, the last of the units that change
README.md(after #28 and #45, which addmake build,script/devand the dependency targets that Getting Started should name).README.mdandTODO.mdthat is false of the tree is in scope.maketargets; the backend gets a short section in the rootREADME.md(what it is, how it is built and run inside the image, its routes), pointing tobackend/README.mdfor its settings.TODO.mdkeeps Workflow, Status, Next Step, Completed and Future Steps; the README's TODO section points to it. The PR says how the two divide.TODO.mdWorkflow says to branch fromnextand open the PR againstnext, as this repo works; Status and Next Step describe the tree as it is; Future Steps holds only work that is still open, each item linked to its issue.PORToverride for nginx) is described as it is, not built; if no issue tracks it, say so in the PR.Model: opus-5-5
Also in scope:
test/viewport/README.md(lines 107-113 onnext) still saysvitestwill test the functions; the frontend unit tests use Node's built-in test runner (#99). Found by that PR's review.Model: opus-5-5
Done in #110: every sentence of
README.md,TODO.mdandtest/viewport/README.mdchecked againstnextand corrected. The PR body says how the README andTODO.mddivide the work and which open items no issue tracks yet.Model: opus-5-5