From a6d68262cf719fe9742bfa616b9d8dacc0b45ed8 Mon Sep 17 00:00:00 2001 From: clawbot Date: Mon, 26 Oct 2026 05:16:00 +0000 Subject: [PATCH] README.md: rework against the third review The symbolic link rule, the console line, fx and the Makefile name are fixed as the review asked. The full pass fixed nine more sentences: a split subject, a late verb or a claim broader than the code. Model: fable-5-1 --- README.md | 78 +++++++++++++++++++++++++++---------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 4ad498b..286d0af 100644 --- a/README.md +++ b/README.md @@ -104,9 +104,9 @@ Hetzner servers close the connection without an answer when either is present. A check times out after 80% of the interval: 2.4 seconds at the default of 3 seconds, 24 seconds at 30 seconds. So a round's checks have all finished before -the next round is due. A check that times out, or answers after that limit, is -recorded as a timeout. A check that fails with a network error is recorded as -unreachable. +the next round is due. A check that times out is recorded as a timeout, and so +is one that answers after that limit. A check that fails with a network error is +recorded as unreachable. A round can start early, after an interval change or when the recovery probe finds a target answering. It then gives up the last round's checks that are @@ -183,15 +183,15 @@ Pinned rows are sorted by name, and a line separates them from the rest. - The header shows the local time with its time zone, and the UTC time. The footer shows the color legend and links to the commit the page was built from. -Each failed check the page records writes one line to the browser console with -`console.error`, and the same line to the debug log. The discarded first round, -the checks a round gives up and the recovery probe write none. The line gives -the target's name and URL, the time, what failed and how long the request took. -The three kinds of failure are a timeout, an answer over the time limit, and a -network error. For a network error the line quotes the error the browser gives -the page, such as `TypeError: Failed to fetch`, which does not say why. When a -target answers again after failed checks, one `console.info` line gives its -latency and how many checks in a row had failed. +When the page records a failed check, it writes one line to the browser console +with `console.error`, and the same line to the debug log. Nothing is written for +the discarded first round, for a check a round gives up, or by the recovery +probe. The line gives the target's name and URL, the time, what failed and how +long the request took. The three kinds of failure are a timeout, an answer over +the time limit, and a network error. For a network error the line quotes the +error the browser gives the page, such as `TypeError: Failed to fetch`, which +does not say why. When a target answers again after failed checks, one +`console.info` line gives its latency and how many checks in a row had failed. ### Browsers @@ -218,8 +218,7 @@ host, the page remembers the time of the newest sample it delivered, and moves that mark only when the server answers 2xx. Paused rounds are never sent. While the page is paused, no report is sent at all. One report is in flight at a time. A report with no answer after 30 seconds is abandoned, and its samples go in the -next report. A server that stored them but answered late therefore gets them -twice. +next report. So a server that stored them but answered late gets them twice. A failed delivery is quiet. The page writes one debug log line when deliveries start failing and one when they recover. The checks go on. @@ -227,9 +226,9 @@ start failing and one when they recover. The checks go on. A sample waits for delivery only as long as the history holds it. The history keeps each host's last 100 rounds: 5 minutes at the default interval of 3 seconds. At 1 second it spans 100 seconds, at 2 seconds 200 seconds, and at 60 -seconds 100 minutes. Changing the interval clears the history, but the cleared -samples not yet delivered are kept apart, the last 100 per host, until they are -delivered. +seconds 100 minutes. Changing the interval clears the history. The cleared +samples are kept apart, the last 100 per host, and those not yet delivered go in +the next report. So at the 1-second interval, one refused or failed report loses the oldest 20 seconds of each host's samples: the next delivered report comes 2 minutes after @@ -284,12 +283,13 @@ The image: - refuses a request body over 1 MiB with nginx's own 413 error page; the backend never sees such a request - requests `/.well-known/healthcheck` through nginx every 30 seconds, as its - `HEALTHCHECK`. The check fails unless both nginx and the backend answer, and - while report files cannot be written. Three failures in a row make the - container `unhealthy`; one pass makes it `healthy` again. -- on `docker stop`, writes the waiting reports to disk and exits 0. If nginx or - the backend exits on its own, the other is stopped and the container exits - non-zero, so the platform restarts it. + `HEALTHCHECK`. The check fails unless both nginx and the backend answer. It + also fails while report files cannot be written. Three failures in a row make + the container `unhealthy`; one pass makes it `healthy` again. +- on `docker stop`, writes the waiting reports to disk and exits 0. If that + final write fails, the container exits non-zero. If nginx or the backend exits + on its own, the other is stopped and the container exits non-zero, so the + platform restarts it. ### Running under upaas @@ -304,8 +304,8 @@ The [upaas](https://git.eeqj.de/sneak/upaas) app for netwatch needs: - `PORT` is nginx's public port, from 1 to 65535 and not `8081`, where the backend listens inside the container. - `DATA_DIR` must be `/data` or a path below it, written in full, with no - `.` or `..` part and no extra `/`. A path through a symbolic link that - leads out of `/data` is refused too. + `.` or `..` part and no extra `/`. A path through a symbolic link is + refused unless the link is relative and stays inside `/data`. - `TRUSTED_PROXIES` names the proxies nginx trusts, as IP addresses or CIDRs separated by commas. The backend's own setting is fixed to `127.0.0.1/32`. With `TRUSTED_PROXIES` set and empty, nginx trusts no proxy. Every client @@ -317,8 +317,8 @@ The [upaas](https://git.eeqj.de/sneak/upaas) app for netwatch needs: only the addresses that nothing but the proxy connects from. - Health: the image's `HEALTHCHECK`, described above. -A variable set to a value the container cannot use stops it at start, with the -reason in its log. +The container stops at start when a variable holds a value it cannot use. The +reason is in its log. ## Settings @@ -328,9 +328,8 @@ reason in its log. `~/.config/netwatch-server/`, when one exists. A variable in the environment wins over a file. -A variable set to a value the server cannot use stops it from starting, with an -error naming the variable. An empty variable counts as unset, except -`TRUSTED_PROXIES`. +The server does not start when a variable holds a value it cannot use. Its error +names the variable. An empty variable counts as unset, except `TRUSTED_PROXIES`. - `BIND_ADDRESS`, default empty: the IP address to listen on. Empty listens on every interface. The image sets it to `127.0.0.1`. @@ -507,9 +506,9 @@ refused. With `SENTRY_DSN` set, each request whose handling crashes is reported to that Sentry project, under the release `netwatch-server-` followed by the server's -version. The request still gets a 500 answer. A DSN Sentry does not accept stops -the start. On shutdown the server waits up to 2 seconds for Sentry to finish -sending. Empty, the server sends nothing to Sentry. +version. The request still gets a 500 answer. The server does not start if +Sentry rejects the DSN. On shutdown the server waits up to 2 seconds for Sentry +to finish sending. Empty, the server sends nothing to Sentry. ### Logging @@ -541,15 +540,16 @@ The page is built with Vite and Tailwind CSS v4. All its code is in - `CONFIG` holds the timing and display constants. The interval menu sets its `updateInterval`; the check timeout, the history span and the time axis are computed from it. -- `WAN_HOSTS` is the list of WAN targets, with the URL and method each is - checked with. +- `WAN_HOSTS` is the list of WAN targets, each with its URL. The S3 entries also + name HEAD as their method. - `HostState` is one host's history, latest latency and status. - `AppState` holds the WAN hosts, the local hosts, the pause state and the round count, and computes the summary and the health. - `measureLatency` runs one check. - `tick` runs one round. It checks every host in parallel and draws each row as soon as its check ends. When the last check ends, it redraws every row, the - summary and the health box, and sorts the rows when a sort is due. + summary and the health box, and sorts the rows when a sort is due. A discarded + round draws nothing. - `SparklineRenderer` draws a graph on a canvas, scaled to the device's pixel ratio. - `buildUI` builds the page; `updateHostRow`, `updateSummary` and @@ -559,8 +559,8 @@ The page is built with Vite and Tailwind CSS v4. All its code is in ### The backend -`netwatch-server` is a Go HTTP server wired with `fx`. Its packages are in -`internal/`: +`netwatch-server` is a Go HTTP server. The `fx` library starts and stops its +parts in dependency order. The backend's packages are in `internal/`: - `cli` runs the command line. Given no arguments, it runs the server. It also runs the `check-cidr` and `prepare-data-dir` subcommands, which @@ -588,7 +588,7 @@ it on port 8080. This repository adheres to the [Scripts to Rule Them All](https://github.com/github/scripts-to-rule-them-all) standard. The scripts in `script/` are the entrypoints for the development -workflow, and the Makefile targets are thin shims that call them. The scripts +workflow, and the `Makefile` targets are thin shims that call them. The scripts cover both the page and the Go backend, so `make check` fails if either one is broken. Every script that runs yarn on the host does so through `script/yarn`, except `script/bootstrap`.