Rewrites README.md from scratch for #189: what the page is and how to use it, then the settings, then development. Every sentence was checked against the code on next. 3,500 words by wc -w, from 5,864; the settings reference and the entrypoint list hold about 700.
Dropped, each with its reason:
Chrome's connection reuse per target: not verifiable here.
Hetzner's Referer and query-string refusal, no-cors, no-store: measureLatency comment.
Why the timeout is 80%, how an early round gives up the last one's checks: CONFIG and init comments.
When rows are sorted, when gray figures recolor: tick, sortAndRebuildWAN.
Console and log line contents, log levels, clocks, footer links, color table: visible on the page.
Browser features needed, IPv4 or IPv6: the browser's doing.
Loss arithmetic per interval and pause: the 100-round history.
Viewport test details: test/viewport/README.md. upaas's own behaviour: not verifiable here.
Disclosure: that browsers block a public page from private addresses is from the code's comment, not re-measured.
Model: fable-5-1
Rewrites `README.md` from scratch for https://git.eeqj.de/sneak/netwatch/issues/189: what the page is and how to use it, then the settings, then development. Every sentence was checked against the code on `next`. 3,500 words by `wc -w`, from 5,864; the settings reference and the entrypoint list hold about 700.
Dropped, each with its reason:
- Chrome's connection reuse per target: not verifiable here.
- Hetzner's `Referer` and query-string refusal, `no-cors`, `no-store`: `measureLatency` comment.
- Why the timeout is 80%, how an early round gives up the last one's checks: `CONFIG` and `init` comments.
- When rows are sorted, when gray figures recolor: `tick`, `sortAndRebuildWAN`.
- Console and log line contents, log levels, clocks, footer links, color table: visible on the page.
- Browser features needed, IPv4 or IPv6: the browser's doing.
- Loss arithmetic per interval and pause: the 100-round history.
- `dist/` contents, `Cache-Control`, security headers: `configs/`.
- Hard-link and device cases of `prepare-data-dir`: `datadir.go`.
- Three failed checks before `unhealthy`: `Dockerfile`.
- File numbering, `O_EXCL`, failed-write cleanup: `reportbuf.go`.
- Body-length cases, sliding minute, `X-RateLimit-*` headers, why JSON only: `middleware`, `handlers` comments.
- Which requests metrics skip and why, the `/metrics` limit's reason: `routes.go`.
- Sentry release and flush, rejected DSN, log source location: `server.go`, `logger.go`.
- Build caching: `Dockerfile` header, script comments.
- `cli` exit code 2, bootstrap mechanics, `script/test` reruns: `cli.go`, the scripts.
- Viewport test details: `test/viewport/README.md`. upaas's own behaviour: not verifiable here.
Disclosure: that browsers block a public page from private addresses is from the code's comment, not re-measured.
Model: fable-5-1
"Each check is a GET request to the target's URL." False for 8 of the 26 hosts: the S3 regions are checked with HEAD, as the same section says two paragraphs later. Acceptable: one correct sentence up front, for example "A check is a request to the target's URL: GET, or HEAD for the S3 regions."
"An address is sure never to be refused only while it sends at most half the limit in any 60 seconds." Two negations and a late "only while"; it takes a second reading. Acceptable: "An address that sends at most half the limit in any 60 seconds is never refused. Above that, it may be."
Dropped without a reason: the old "Running under upaas" section warned that any client connecting from an address in TRUSTED_PROXIES can write its own X-Forwarded-For, that through a port Docker publishes clients can arrive from the Docker network's gateway, such as 172.17.0.1, which the default includes, and that only the proxy's own addresses should be named where that matters. It also said that with TRUSTED_PROXIES set and empty, every client behind the proxy shares one allowance of REPORTS_PER_MINUTE. Neither is in the new text or in the PR body's list of what was left out. Acceptable: both back, in short sentences, under Trusted proxies or the upaas section, or a line in the PR body saying why they go.
The PR closes #189 but adds no Completed Steps entry to TODO.md. Every other issue closed here has one, and the Workflow section of TODO.md asks for that change in the same commit as the work. Acceptable: a dated entry linking the issue, added once #196 has merged so the two PRs do not conflict.
Model: fable-5-1
Review failed. Findings in `README.md`:
- "Each check is a GET request to the target's URL." False for 8 of the 26 hosts: the S3 regions are checked with HEAD, as the same section says two paragraphs later. Acceptable: one correct sentence up front, for example "A check is a request to the target's URL: GET, or HEAD for the S3 regions."
- "An address is sure never to be refused only while it sends at most half the limit in any 60 seconds." Two negations and a late "only while"; it takes a second reading. Acceptable: "An address that sends at most half the limit in any 60 seconds is never refused. Above that, it may be."
- Dropped without a reason: the old "Running under upaas" section warned that any client connecting from an address in `TRUSTED_PROXIES` can write its own `X-Forwarded-For`, that through a port Docker publishes clients can arrive from the Docker network's gateway, such as `172.17.0.1`, which the default includes, and that only the proxy's own addresses should be named where that matters. It also said that with `TRUSTED_PROXIES` set and empty, every client behind the proxy shares one allowance of `REPORTS_PER_MINUTE`. Neither is in the new text or in the PR body's list of what was left out. Acceptable: both back, in short sentences, under Trusted proxies or the upaas section, or a line in the PR body saying why they go.
- The PR closes https://git.eeqj.de/sneak/netwatch/issues/189 but adds no Completed Steps entry to `TODO.md`. Every other issue closed here has one, and the Workflow section of `TODO.md` asks for that change in the same commit as the work. Acceptable: a dated entry linking the issue, added once https://git.eeqj.de/sneak/netwatch/pulls/196 has merged so the two PRs do not conflict.
Model: fable-5-1
Reworked at e6ca7f5, one change per finding and nothing else:
"Each check is a GET request to the target's URL." is now "A check is a request to the target's URL: GET, or HEAD for the S3 regions."
The rate-limit sentence is now "An address that sends at most half the limit in any 60 seconds is never refused. Above that, it may be."
The upaas TRUSTED_PROXIES entry has both warnings back, in short sentences: set and empty, every client behind the proxy shares one allowance of REPORTS_PER_MINUTE; a client on a trusted address can write its own X-Forwarded-For; a published Docker port can bring a connection from the gateway 172.17.0.1, which the default includes; so name only the proxy's own addresses where that matters.
TODO.md has a dated Completed Steps entry linking #189, now that #196 has merged.
Rebased onto the current next.
Model: fable-5-1
Reworked at `e6ca7f5`, one change per finding and nothing else:
- "Each check is a GET request to the target's URL." is now "A check is a request to the target's URL: GET, or HEAD for the S3 regions."
- The rate-limit sentence is now "An address that sends at most half the limit in any 60 seconds is never refused. Above that, it may be."
- The upaas `TRUSTED_PROXIES` entry has both warnings back, in short sentences: set and empty, every client behind the proxy shares one allowance of `REPORTS_PER_MINUTE`; a client on a trusted address can write its own `X-Forwarded-For`; a published Docker port can bring a connection from the gateway `172.17.0.1`, which the default includes; so name only the proxy's own addresses where that matters.
- `TODO.md` has a dated Completed Steps entry linking https://git.eeqj.de/sneak/netwatch/issues/189, now that https://git.eeqj.de/sneak/netwatch/pulls/196 has merged.
Rebased onto the current `next`.
Model: fable-5-1
"Each check that fails writes one line to the browser console with console.error, and the same line to the debug log." False: only a check the page records is logged. A failed check in the discarded first round, in a round given up early or in the recovery probe writes nothing. Acceptable: "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 and the recovery probe write none."
"Before the backend starts, netwatch-server prepare-data-dir creates that directory and gives /data and everything in it to user netwatch." False for part of "everything": a file with a second name (hard link) keeps its owner and its path is logged, and devices, pipes and sockets keep theirs. Acceptable: "... and gives /data and the directories, files and symbolic links in it to user netwatch. A file with a second name (hard link) keeps its owner, and its path is logged."
"cli runs the command line: the check-cidr and prepare-data-dir subcommands, which bin/entrypoint.sh runs before the server starts, and, given no arguments, the server." The second thing it runs arrives after a relative clause and a parenthetical, so the sentence takes a second reading. Acceptable: "cli runs the command line. Given no arguments, it runs the server. It also runs the check-cidr and prepare-data-dir subcommands, which bin/entrypoint.sh runs before the server starts."
Dropped without a reason: the old text said why a check times out at 80% of the interval (so a round's checks have all finished before the next round is due), and that a round started early gives up the last round's waiting checks, so rounds never overlap. The new text keeps the 80% figure and neither. Acceptable: both back, one short sentence each, under What a figure measures; or a line in the PR body saying why they go.
The four earlier findings are fixed.
Disclosure: the new TODO.md entry names test/viewport/README.md as rewritten, which holds only once #197 has merged.
Model: fable-5-1
Review failed. Findings in `README.md`:
- "Each check that fails writes one line to the browser console with `console.error`, and the same line to the debug log." False: only a check the page records is logged. A failed check in the discarded first round, in a round given up early or in the recovery probe writes nothing. Acceptable: "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 and the recovery probe write none."
- "Before the backend starts, `netwatch-server prepare-data-dir` creates that directory and gives `/data` and everything in it to user `netwatch`." False for part of "everything": a file with a second name (hard link) keeps its owner and its path is logged, and devices, pipes and sockets keep theirs. Acceptable: "... and gives `/data` and the directories, files and symbolic links in it to user `netwatch`. A file with a second name (hard link) keeps its owner, and its path is logged."
- "`cli` runs the command line: the `check-cidr` and `prepare-data-dir` subcommands, which `bin/entrypoint.sh` runs before the server starts, and, given no arguments, the server." The second thing it runs arrives after a relative clause and a parenthetical, so the sentence takes a second reading. Acceptable: "`cli` runs the command line. Given no arguments, it runs the server. It also runs the `check-cidr` and `prepare-data-dir` subcommands, which `bin/entrypoint.sh` runs before the server starts."
- Dropped without a reason: the old text said why a check times out at 80% of the interval (so a round's checks have all finished before the next round is due), and that a round started early gives up the last round's waiting checks, so rounds never overlap. The new text keeps the 80% figure and neither. Acceptable: both back, one short sentence each, under What a figure measures; or a line in the PR body saying why they go.
The four earlier findings are fixed.
Disclosure: the new `TODO.md` entry names `test/viewport/README.md` as rewritten, which holds only once https://git.eeqj.de/sneak/netwatch/pulls/197 has merged.
Model: fable-5-1
The console line: "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."
prepare-data-dir now "gives /data and the directories, regular files and symbolic links in it to user netwatch. A file with a second name (hard link) keeps its owner, and its path is logged."
The cli entry is three sentences: it runs the command line; given no arguments, the server; also the two subcommands, which bin/entrypoint.sh runs before the server starts.
Under What a figure measures, the 80% timeout has its reason back ("So a round's checks have all finished before the next round is due"), and a new short paragraph says a round can start early and then gives up the last round's waiting checks, so rounds never overlap.
A full pass over the document, sentence by sentence against the code, changed these too:
Claims broader than the code, each now a correct short sentence: a row shows timeout or unreachable after a failed check; the page posts a report only when it has undelivered samples; the server writes a file only when reports are waiting; each refusal by the backend answers JSON (nginx's 413 does not); the rate-limit headers are on every answer the route gives (not on the 413 before the route); script/fmt runs the formatters rather than formatting "all files".
Under upaas, BIND_ADDRESS is a fourth difference in the image: it has no effect, as the backend is started on 127.0.0.1. The text said three differences.
Six sentences whose subject was split from its verb by a clause are now two sentences each or reordered: the recovery probe's 4 hosts, the forwarded entry with a port, the failed write's retry and its file, both rate limits' client address, the nvm archive in script/bootstrap.
The viewport test's "same nginx image and configuration as the Docker image" is now "the nginx image and the configs/nginx.conf that the Docker image ships".
Rebased onto the current next; the branch already contained it, so nothing moved. TODO.md is unchanged from the first rework.
Model: fable-5-1
Reworked at `a3b18b6`, one change per finding:
- The console line: "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."
- `prepare-data-dir` now "gives `/data` and the directories, regular files and symbolic links in it to user `netwatch`. A file with a second name (hard link) keeps its owner, and its path is logged."
- The `cli` entry is three sentences: it runs the command line; given no arguments, the server; also the two subcommands, which `bin/entrypoint.sh` runs before the server starts.
- Under What a figure measures, the 80% timeout has its reason back ("So a round's checks have all finished before the next round is due"), and a new short paragraph says a round can start early and then gives up the last round's waiting checks, so rounds never overlap.
A full pass over the document, sentence by sentence against the code, changed these too:
- Claims broader than the code, each now a correct short sentence: a row shows `timeout` or `unreachable` after a failed check; the page posts a report only when it has undelivered samples; the server writes a file only when reports are waiting; each refusal *by the backend* answers JSON (nginx's 413 does not); the rate-limit headers are on every answer *the route gives* (not on the 413 before the route); `script/fmt` runs the formatters rather than formatting "all files".
- Under upaas, `BIND_ADDRESS` is a fourth difference in the image: it has no effect, as the backend is started on `127.0.0.1`. The text said three differences.
- Six sentences whose subject was split from its verb by a clause are now two sentences each or reordered: the recovery probe's 4 hosts, the forwarded entry with a port, the failed write's retry and its file, both rate limits' client address, the nvm archive in `script/bootstrap`.
- The viewport test's "same nginx image and configuration as the Docker image" is now "the nginx image and the `configs/nginx.conf` that the Docker image ships".
Rebased onto the current `next`; the branch already contained it, so nothing moved. `TODO.md` is unchanged from the first rework.
Model: fable-5-1
"A path through a symbolic link that leads out of /data is refused too." (Running under upaas, DATA_DIR). Narrower than the code: prepare-data-dir follows a link only when it is written as a relative path that stays inside /data, so a link written as an absolute path is refused even when it points inside /data. The old text had this ("or is written as a full path"). Acceptable: "A path through a symbolic link is refused unless the link is relative and stays inside /data."
"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." (Controls). In the first sentence the subject is split from its verb by a clause ("records writes"); in the second the verb comes last, after a three-part subject with a clause inside it. Both take a second reading. Acceptable: "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."
"netwatch-server is a Go HTTP server wired with fx." (Design, The backend). fx is named but never said what it is. Acceptable: "netwatch-server is a Go HTTP server. The fx library starts and stops its parts in dependency order."
"and the Makefile targets are thin shims that call them" (Entrypoints). Makefile is a file name and goes in backticks, as it does under Design.
The body of commit a3b18b6 runs to about 165 words, over the 120 or so a commit body may have. Acceptable: a shorter body; the detail is already in the PR comments.
The earlier findings are fixed.
Disclosures:
The claim that Chrome opens a new connection for every check of the Hetzner servers, and for more targets at longer intervals, is carried over from the old text and was not re-measured here.
Judgement call: leaving out upaas's own behaviour (one health read after a deploy, no restart of an unhealthy container) is accepted, as the PR body says why.
Model: fable-5-1
Review failed. Findings in `README.md`:
- "A path through a symbolic link that leads out of `/data` is refused too." (Running under upaas, `DATA_DIR`). Narrower than the code: `prepare-data-dir` follows a link only when it is written as a relative path that stays inside `/data`, so a link written as an absolute path is refused even when it points inside `/data`. The old text had this ("or is written as a full path"). Acceptable: "A path through a symbolic link is refused unless the link is relative and stays inside `/data`."
- "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." (Controls). In the first sentence the subject is split from its verb by a clause ("records writes"); in the second the verb comes last, after a three-part subject with a clause inside it. Both take a second reading. Acceptable: "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."
- "`netwatch-server` is a Go HTTP server wired with `fx`." (Design, The backend). `fx` is named but never said what it is. Acceptable: "`netwatch-server` is a Go HTTP server. The `fx` library starts and stops its parts in dependency order."
- "and the Makefile targets are thin shims that call them" (Entrypoints). `Makefile` is a file name and goes in backticks, as it does under Design.
- The body of commit `a3b18b6` runs to about 165 words, over the 120 or so a commit body may have. Acceptable: a shorter body; the detail is already in the PR comments.
The earlier findings are fixed.
Disclosures:
- The claim that Chrome opens a new connection for every check of the Hetzner servers, and for more targets at longer intervals, is carried over from the old text and was not re-measured here.
- Judgement call: leaving out upaas's own behaviour (one health read after a deploy, no restart of an `unhealthy` container) is accepted, as the PR body says why.
Model: fable-5-1
DATA_DIR under upaas: "A path through a symbolic link is refused unless the link is relative and stays inside /data."
The console line is now "When the page records a failed check, it writes one line ..." and "Nothing is written for the discarded first round, for a check a round gives up, or by the recovery probe."
The backend: "netwatch-server is a Go HTTP server. The fx library starts and stops its parts in dependency order."
Makefile is in backticks under Entrypoints.
The commit body: no change; the manager writes the squash commit's message.
A full pass over the document, sentence by sentence against the code, changed nine more sentences:
Claims broader than the code, each now a correct short sentence: docker stop exits non-zero when the final write fails; WAN_HOSTS entries carry a URL, and only the S3 entries a method; tick draws nothing in a discarded round.
Subjects split from their verbs, or a late verb, now reordered or two sentences: the timeout rule, the late-answering server, the cleared samples after an interval change, the two sentences on a value the server or container cannot use, the rejected Sentry DSN, the health check's two reasons to fail.
Rebased onto the current next; the branch already contained it, so nothing moved. TODO.md is unchanged.
Disclosure: the claim that Chrome opens a new connection for every check of the Hetzner servers, and for more targets at longer intervals, is carried over from the old text and was not re-measured here.
Model: fable-5-1
Reworked at `a6d6826`:
- `DATA_DIR` under upaas: "A path through a symbolic link is refused unless the link is relative and stays inside `/data`."
- The console line is now "When the page records a failed check, it writes one line ..." and "Nothing is written for the discarded first round, for a check a round gives up, or by the recovery probe."
- The backend: "`netwatch-server` is a Go HTTP server. The `fx` library starts and stops its parts in dependency order."
- `Makefile` is in backticks under Entrypoints.
- The commit body: no change; the manager writes the squash commit's message.
A full pass over the document, sentence by sentence against the code, changed nine more sentences:
- Claims broader than the code, each now a correct short sentence: `docker stop` exits non-zero when the final write fails; `WAN_HOSTS` entries carry a URL, and only the S3 entries a method; `tick` draws nothing in a discarded round.
- Subjects split from their verbs, or a late verb, now reordered or two sentences: the timeout rule, the late-answering server, the cleared samples after an interval change, the two sentences on a value the server or container cannot use, the rejected Sentry DSN, the health check's two reasons to fail.
Rebased onto the current `next`; the branch already contained it, so nothing moved. `TODO.md` is unchanged.
Disclosure: the claim that Chrome opens a new connection for every check of the Hetzner servers, and for more targets at longer intervals, is carried over from the old text and was not re-measured here.
Model: fable-5-1
"To serve the page from elsewhere, list that origin in CORS_ALLOWED_ORIGINS, for example https://netwatch.example.com." (CORS). The page as built posts its reports to /api/v1/reports on its own origin, as the Reporting section says, so a page served from a listed origin still never calls this server. The setting lets pages on the listed origins call the API; the shipped page does not use it. Acceptable: "CORS_ALLOWED_ORIGINS lets pages served from the listed origins call the API, for example https://netwatch.example.com. The page as built posts to its own origin only, so it needs no entry."
"No value of it stops the start." (Settings, DEBUG). Right after "default empty" and "any non-empty value", "No value" reads as "an empty value", and the sentence as its opposite. Acceptable: "Every value is accepted."
The earlier findings are fixed.
Disclosures:
Unverified: the browser claims (Chrome's new connection for every Hetzner check and for more targets at longer intervals; browsers blocking private addresses from a page on a public address) cannot be checked against the code and were not re-measured.
Judgement call: standard web and network names (CORS, CIDR, basic auth, peer, nginx) are taken as known to a newcomer, not as undefined jargon.
Judgement call: the WAN host list names the two LLM API providers, as the code and the old text do; read as a description of the targets.
Model: fable-5-1
Review failed. Findings in `README.md`:
- "To serve the page from elsewhere, list that origin in `CORS_ALLOWED_ORIGINS`, for example `https://netwatch.example.com`." (CORS). The page as built posts its reports to `/api/v1/reports` on its own origin, as the Reporting section says, so a page served from a listed origin still never calls this server. The setting lets pages on the listed origins call the API; the shipped page does not use it. Acceptable: "`CORS_ALLOWED_ORIGINS` lets pages served from the listed origins call the API, for example `https://netwatch.example.com`. The page as built posts to its own origin only, so it needs no entry."
- "No value of it stops the start." (Settings, `DEBUG`). Right after "default empty" and "any non-empty value", "No value" reads as "an empty value", and the sentence as its opposite. Acceptable: "Every value is accepted."
The earlier findings are fixed.
Disclosures:
- Unverified: the browser claims (Chrome's new connection for every Hetzner check and for more targets at longer intervals; browsers blocking private addresses from a page on a public address) cannot be checked against the code and were not re-measured.
- Judgement call: standard web and network names (CORS, CIDR, basic auth, peer, nginx) are taken as known to a newcomer, not as undefined jargon.
- Judgement call: the WAN host list names the two LLM API providers, as the code and the old text do; read as a description of the targets.
Model: fable-5-1
Every sentence is under about 30 words, with one idea each. The page,
its targets and what a figure measures come first, then reporting,
deployment, the settings reference, the design, and development last.
No tables; every identifier in backticks. The code on next decides
what is true.
Model: fable-5-1
The check sentence names HEAD for the S3 regions up front. The rate-limit
sentence states the safe rate plainly: an address that sends at most half
the limit in any 60 seconds is never refused. The upaas `TRUSTED_PROXIES`
entry again warns that a client connecting from a trusted address can
write its own `X-Forwarded-For`, that a connection through a published
Docker port can arrive from the Docker network's gateway, which the
default includes, and that set and empty, every client behind the proxy
shares one allowance. `TODO.md` gets the Completed Steps entry for
#189, now that
#196 has merged. For
#195.
Model: fable-5-1
The four findings: only a recorded failed check is logged, and the
discarded round, given-up checks and the recovery probe log nothing;
prepare-data-dir gives directories, regular files and symbolic links to
the netwatch user, and a hard link keeps its owner and is logged; the
cli entry names what it runs in three short sentences; the 80% timeout
and the early-round rule have their reasons back, so rounds never
overlap.
The full pass also fixed claims broader than the code (a row always
shows its stats; a report is posted every 60 seconds; a file is written
every minute; each refusal answers JSON; every answer to a report
carries rate-limit headers; every setting applies in the image, where
BIND_ADDRESS has no effect; fmt formats all files), six sentences whose
subject was split from its verb (the recovery probe, the forwarded
entry with a port, the failed write's retry and its file, both rate
limits, the nvm archive), and the viewport test's "same ... as"
comparison.
Model: fable-5-1
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
Reworked against the fourth review; the two findings only, nothing else changed.
CORS: CORS_ALLOWED_ORIGINS lets pages served from the listed origins call the API, for example https://netwatch.example.com. The page as built posts to its own origin only, so it needs no entry.
DEBUG: "No value of it stops the start." is now "Every value is accepted."
Model: fable-5-1
Reworked against the fourth review; the two findings only, nothing else changed.
- CORS: `CORS_ALLOWED_ORIGINS` lets pages served from the listed origins call the API, for example `https://netwatch.example.com`. The page as built posts to its own origin only, so it needs no entry.
- `DEBUG`: "No value of it stops the start." is now "Every value is accepted."
Model: fable-5-1
"The WAN rows are sorted by their latest latency, fastest first and unreachable last." (Row order). Narrower than the code: every host whose last check failed sorts last, a timed-out one too, and the document uses "unreachable" for a network error only. The rows are also re-sorted whenever a row is pinned or unpinned, which the schedule in the next sentence leaves out. Acceptable: "fastest first and failed last", and "The rows are also sorted whenever a row is pinned or unpinned."
"The figures turn gray until Resume." (Controls). After Resume a figure stays gray until its host's next check ends, up to an interval and the timeout later. Acceptable: "The figures turn gray. After Resume, each takes its color again when its host's next check ends."
"Docker keeps the layers above that line, the system packages and the Go modules, until the base image, their own lines, or go.mod and go.sum change." (Build caching). False for the frontend-build stage: its git install is above ARG CACHEBUST and still runs on every build, because the stage starts from frontend-test, whose steps run again on every build, as the Dockerfile comment says. The PR body lists that detail as left out, but the general rule that replaced it is wrong for that stage. Acceptable: a correct short sentence, for example the old text's exception for frontend-build.
"It also runs the check-cidr and prepare-data-dir subcommands, which bin/entrypoint.sh runs before the server starts." (Design, The backend). check-cidr is named but never said what it does; prepare-data-dir is described under The Docker image. The old text said bin/entrypoint.sh checks each TRUSTED_PROXIES entry with it. Dropped without a reason in the PR body. Acceptable: one sentence under the upaas TRUSTED_PROXIES entry, for example "bin/entrypoint.sh gives a lone address a /32 or /128 and checks each entry with netwatch-server check-cidr, which refuses what the backend would refuse."
"script/fmt: run the formatters, which write: prettier over the JavaScript, CSS, HTML and Markdown, then gofmt over cmd/ and internal/." (Entrypoints). "which write:" followed by the list reads as "which write prettier over the JavaScript" on the first pass. Acceptable: "script/fmt: run the formatters: prettier over the JavaScript, CSS, HTML and Markdown, then gofmt over cmd/ and internal/. They write the files in place."
"A report is refused with 507 only when the reports waiting to be written fill the cap on their own; then no file is deleted." (Report limits, Size cap). Not strictly true: a file whose deletion fails keeps counting until the next start, and the deletion goes on past it, so a 507 can follow deletions, and without the waiting reports filling the cap alone. Acceptable: "A report is refused with 507 when deleting the oldest files cannot make room. A file that could not be deleted still counts until the next start."
"The S3 entries also name HEAD as their method." (Design, The page), and GET and HEAD under What a figure measures. HEAD is the value in the code and an HTTP method name; the document puts GET and POST in backticks under Routes and CORS. Acceptable: backticks on every method name.
The earlier findings are fixed, and the last rework changed only the two sentences it names.
Disclosures:
Unverified: the browser and network claims carried from the old text (Chrome's new connection for each Hetzner check and at longer intervals, the S3 connection kept after HEAD, Private Network Access, the Hetzner servers' behaviour on a Referer header or query string) were not re-measured.
Judgement call: the old sentence that the Hetzner servers do not answer a HEAD request is dropped without a reason; the code does not state it, so leaving it out is accepted.
Judgement call: "Nothing is written ... by the recovery probe" is read as being about failed-check lines; the probe does write two notice lines to the debug log, at start and when a target answers.
Judgement call: the Browsers sentence is read as a minimum, not the full requirement; the build targets esnext.
Model: fable-5-1
Review failed. Findings in `README.md`:
- "The WAN rows are sorted by their latest latency, fastest first and unreachable last." (Row order). Narrower than the code: every host whose last check failed sorts last, a timed-out one too, and the document uses "unreachable" for a network error only. The rows are also re-sorted whenever a row is pinned or unpinned, which the schedule in the next sentence leaves out. Acceptable: "fastest first and failed last", and "The rows are also sorted whenever a row is pinned or unpinned."
- "The figures turn gray until `Resume`." (Controls). After `Resume` a figure stays gray until its host's next check ends, up to an interval and the timeout later. Acceptable: "The figures turn gray. After `Resume`, each takes its color again when its host's next check ends."
- "Docker keeps the layers above that line, the system packages and the Go modules, until the base image, their own lines, or `go.mod` and `go.sum` change." (Build caching). False for the `frontend-build` stage: its git install is above `ARG CACHEBUST` and still runs on every build, because the stage starts from `frontend-test`, whose steps run again on every build, as the `Dockerfile` comment says. The PR body lists that detail as left out, but the general rule that replaced it is wrong for that stage. Acceptable: a correct short sentence, for example the old text's exception for `frontend-build`.
- "It also runs the `check-cidr` and `prepare-data-dir` subcommands, which `bin/entrypoint.sh` runs before the server starts." (Design, The backend). `check-cidr` is named but never said what it does; `prepare-data-dir` is described under The Docker image. The old text said `bin/entrypoint.sh` checks each `TRUSTED_PROXIES` entry with it. Dropped without a reason in the PR body. Acceptable: one sentence under the upaas `TRUSTED_PROXIES` entry, for example "`bin/entrypoint.sh` gives a lone address a `/32` or `/128` and checks each entry with `netwatch-server check-cidr`, which refuses what the backend would refuse."
- "`script/fmt`: run the formatters, which write: prettier over the JavaScript, CSS, HTML and Markdown, then gofmt over `cmd/` and `internal/`." (Entrypoints). "which write:" followed by the list reads as "which write prettier over the JavaScript" on the first pass. Acceptable: "`script/fmt`: run the formatters: prettier over the JavaScript, CSS, HTML and Markdown, then gofmt over `cmd/` and `internal/`. They write the files in place."
- "A report is refused with 507 only when the reports waiting to be written fill the cap on their own; then no file is deleted." (Report limits, Size cap). Not strictly true: a file whose deletion fails keeps counting until the next start, and the deletion goes on past it, so a 507 can follow deletions, and without the waiting reports filling the cap alone. Acceptable: "A report is refused with 507 when deleting the oldest files cannot make room. A file that could not be deleted still counts until the next start."
- "The S3 entries also name HEAD as their method." (Design, The page), and GET and HEAD under What a figure measures. `HEAD` is the value in the code and an HTTP method name; the document puts `GET` and `POST` in backticks under Routes and CORS. Acceptable: backticks on every method name.
The earlier findings are fixed, and the last rework changed only the two sentences it names.
Disclosures:
- Unverified: the browser and network claims carried from the old text (Chrome's new connection for each Hetzner check and at longer intervals, the S3 connection kept after HEAD, Private Network Access, the Hetzner servers' behaviour on a `Referer` header or query string) were not re-measured.
- Judgement call: the old sentence that the Hetzner servers do not answer a HEAD request is dropped without a reason; the code does not state it, so leaving it out is accepted.
- Judgement call: "Nothing is written ... by the recovery probe" is read as being about failed-check lines; the probe does write two notice lines to the debug log, at start and when a target answers.
- Judgement call: the Browsers sentence is read as a minimum, not the full requirement; the build targets `esnext`.
Model: fable-5-1
Decided: the review loops. Five fresh reviews of this 5,200-word README have each found new sentences that fail, so the unit is too big. The next rework fixes the findings above mostly by cutting.
The README keeps the sections REPO_POLICIES.md requires (Description, Getting Started, Entrypoints, Rationale, Design, TODO, License, Author) and the settings reference.
Design says how the program is structured. It drops mechanism detail that the code and its comments already hold, such as build caching, report-limit edge cases and when rows are sorted or turn gray.
Target: about half the current length.
The PR body lists each topic dropped, one line each, with the reason.
Then one fresh Fable review.
Model: opus-5-5
Decided: the review loops. Five fresh reviews of this 5,200-word README have each found new sentences that fail, so the unit is too big. The next rework fixes the findings above mostly by cutting.
- The README keeps the sections `REPO_POLICIES.md` requires (Description, Getting Started, Entrypoints, Rationale, Design, TODO, License, Author) and the settings reference.
- Design says how the program is structured. It drops mechanism detail that the code and its comments already hold, such as build caching, report-limit edge cases and when rows are sorted or turn gray.
- Target: about half the current length.
- The PR body lists each topic dropped, one line each, with the reason.
Then one fresh Fable review.
Model: opus-5-5
Reworked at df40083, mostly by cutting: 5,864 words to 3,500. The dropped topics and their reasons are in the PR body.
Rows: sorted fastest first and failed last, with no schedule given.
Pause: "the figures turn gray", with nothing said about Resume.
Build caching: the section is gone.
check-cidr: described under the upaas TRUSTED_PROXIES entry, with the /32 or /128 rule.
script/fmt: "run the formatters: ... They write the files in place."
507: "when deleting the oldest files cannot make room".
GET, HEAD and POST in backticks throughout.
Design is the parts, where each lives and what each does; mechanism detail stayed with its code and comments.
Model: fable-5-1
Reworked at `df40083`, mostly by cutting: 5,864 words to 3,500. The dropped topics and their reasons are in the PR body.
- Rows: sorted fastest first and failed last, with no schedule given.
- Pause: "the figures turn gray", with nothing said about `Resume`.
- Build caching: the section is gone.
- `check-cidr`: described under the upaas `TRUSTED_PROXIES` entry, with the `/32` or `/128` rule.
- `script/fmt`: "run the formatters: ... They write the files in place."
- 507: "when deleting the oldest files cannot make room".
- `GET`, `HEAD` and `POST` in backticks throughout.
Design is the parts, where each lives and what each does; mechanism detail stayed with its code and comments.
Model: fable-5-1
"A sample waits only as long as the history holds it: the last 100 rounds of each host." (Reporting). Narrower than the code: the samples an interval change clears from the history wait apart, the last 100 of each host, until a report delivers them, so "only" does not hold for them. Acceptable: drop "only" ("A sample waits as long as the history holds it: the last 100 rounds of each host."), or one more short sentence: "The samples an interval change clears wait apart, the last 100 of each host, until they are delivered."
The fifth review's findings are fixed or their topics dropped with a reason. The TODO.md entry holds now that #197 has merged.
Disclosures:
Unverified: the browser claim carried from the old text, that a page on a public address cannot reach private addresses, so the local targets answer only from localhost or a private address, was not re-measured.
Judgement call: standard web and network names (CORS, CIDR, origin, basic auth, loopback, DSN, nginx) are taken as known to a newcomer.
Judgement call: "tick: one round, which checks every host in parallel and draws each row as soon as its check ends" is read as the function's role; that it draws nothing in a discarded round is stated under What a figure measures.
Judgement call: "Two local targets follow under the heading ..." is read with the sentence after it, which says the gateway has no row when none answers.
Judgement call: the PR body is 259 words, taken as about 250.
Model: fable-5-1
Review failed. Finding in `README.md`:
- "A sample waits only as long as the history holds it: the last 100 rounds of each host." (Reporting). Narrower than the code: the samples an interval change clears from the history wait apart, the last 100 of each host, until a report delivers them, so "only" does not hold for them. Acceptable: drop "only" ("A sample waits as long as the history holds it: the last 100 rounds of each host."), or one more short sentence: "The samples an interval change clears wait apart, the last 100 of each host, until they are delivered."
The fifth review's findings are fixed or their topics dropped with a reason. The `TODO.md` entry holds now that https://git.eeqj.de/sneak/netwatch/pulls/197 has merged.
Disclosures:
- Unverified: the browser claim carried from the old text, that a page on a public address cannot reach private addresses, so the local targets answer only from `localhost` or a private address, was not re-measured.
- Judgement call: standard web and network names (CORS, CIDR, origin, basic auth, loopback, DSN, nginx) are taken as known to a newcomer.
- Judgement call: "`tick`: one round, which checks every host in parallel and draws each row as soon as its check ends" is read as the function's role; that it draws nothing in a discarded round is stated under What a figure measures.
- Judgement call: "Two local targets follow under the heading ..." is read with the sentence after it, which says the gateway has no row when none answers.
- Judgement call: the PR body is 259 words, taken as about 250.
Model: fable-5-1
Reworked at 1f1a5a6: Reporting gains the sentence that the samples an interval change clears wait apart, the last 100 of each host, until they are delivered; nothing else changed.
Model: fable-5-1
Reworked at `1f1a5a6`: Reporting gains the sentence that the samples an interval change clears wait apart, the last 100 of each host, until they are delivered; nothing else changed.
Model: fable-5-1
"The samples an interval change clears wait apart, the last 100 of each host, until they are delivered." (Reporting; the wording the sixth review offered). The subject carries a clause with no "that", so "clears" runs into "wait" and the sentence takes a second reading; "wait apart" does not say apart from what. Acceptable: "An interval change clears the history. The cleared samples are kept, the last 100 of each host, until a report delivers them." The sentence before it can then lose "only", which this one excepts.
The last rework changed only the Reporting paragraph it names, and the sixth review's finding is fixed. Nothing else in the document fails the rules or disagrees with the code.
Disclosures:
Unverified: that a page on a public address cannot reach private addresses, and that a published Docker port can bring connections from 172.17.0.1, are carried from the old text and the code's comments, not re-measured.
Judgement call: standard network and web names (CORS, CIDR, origin, basic auth, loopback, peer, DSN, nginx) and tool names (prettier, gofmt, eslint, golangci-lint, ping) are taken as known and left out of backticks.
Judgement call: "a graph of its last 100 checks" is read with the page's own Checks label, which counts rounds; a paused round takes a slot too.
Judgement call: that one of METRICS_USERNAME and METRICS_PASSWORD without the other, or a : in the user name, stops the start is covered only by the general sentence on unusable values; not counted as lost.
Note: the PR body's dropped list still names "cleared samples still reported", which the last rework put back.
Judgement call: the PR body is 259 words, taken as about 250.
Model: fable-5-1
Review failed. Finding in `README.md`:
- "The samples an interval change clears wait apart, the last 100 of each host, until they are delivered." (Reporting; the wording the sixth review offered). The subject carries a clause with no "that", so "clears" runs into "wait" and the sentence takes a second reading; "wait apart" does not say apart from what. Acceptable: "An interval change clears the history. The cleared samples are kept, the last 100 of each host, until a report delivers them." The sentence before it can then lose "only", which this one excepts.
The last rework changed only the Reporting paragraph it names, and the sixth review's finding is fixed. Nothing else in the document fails the rules or disagrees with the code.
Disclosures:
- Unverified: that a page on a public address cannot reach private addresses, and that a published Docker port can bring connections from `172.17.0.1`, are carried from the old text and the code's comments, not re-measured.
- Judgement call: standard network and web names (CORS, CIDR, origin, basic auth, loopback, peer, DSN, nginx) and tool names (prettier, gofmt, eslint, golangci-lint, ping) are taken as known and left out of backticks.
- Judgement call: "a graph of its last 100 checks" is read with the page's own `Checks` label, which counts rounds; a paused round takes a slot too.
- Judgement call: that one of `METRICS_USERNAME` and `METRICS_PASSWORD` without the other, or a `:` in the user name, stops the start is covered only by the general sentence on unusable values; not counted as lost.
- Note: the PR body's dropped list still names "cleared samples still reported", which the last rework put back.
- Judgement call: the PR body is 259 words, taken as about 250.
Model: fable-5-1
Reporting: the cleared-samples sentence rewritten to say an interval change clears the history and the cleared samples are kept, the last 100 of each host, until a report delivers them; "only" dropped from the sentence before it; PR body no longer lists cleared samples as dropped.
Model: fable-5-1
Reporting: the cleared-samples sentence rewritten to say an interval change clears the history and the cleared samples are kept, the last 100 of each host, until a report delivers them; "only" dropped from the sentence before it; PR body no longer lists cleared samples as dropped.
Model: fable-5-1
Unverified: that a page served from a public address cannot reach private addresses is carried from the code's comment, not re-measured.
Judgement call: "a YAML file named netwatch-server.yaml" names one case; the server also reads netwatch-server.yml and the other extensions viper knows, parsed as YAML. The sentence is read as true, not as exhaustive.
Judgement call: that one of METRICS_USERNAME and METRICS_PASSWORD without the other, or a : in the user name, stops the start is left to the general sentence on unusable values; not counted as lost.
Dropped without a line in the PR body, and taken as not needed to run netwatch: an X-Forwarded-For entry written with a port is read as its address; the /metrics and report rate limits are separate allowances; report files over the cap are deleted at start.
Judgement call: standard network and web names (CORS, CIDR, origin, basic auth, loopback, peer, DSN, nginx) and tool names (prettier, gofmt, eslint, golangci-lint, ping, zstd) are taken as known and left plain.
Model: fable-5-1
Review passed.
Disclosures:
- Unverified: that a page served from a public address cannot reach private addresses is carried from the code's comment, not re-measured.
- Judgement call: "a YAML file named `netwatch-server.yaml`" names one case; the server also reads `netwatch-server.yml` and the other extensions viper knows, parsed as YAML. The sentence is read as true, not as exhaustive.
- Judgement call: that one of `METRICS_USERNAME` and `METRICS_PASSWORD` without the other, or a `:` in the user name, stops the start is left to the general sentence on unusable values; not counted as lost.
- Dropped without a line in the PR body, and taken as not needed to run netwatch: an `X-Forwarded-For` entry written with a port is read as its address; the `/metrics` and report rate limits are separate allowances; report files over the cap are deleted at start.
- Judgement call: standard network and web names (CORS, CIDR, origin, basic auth, loopback, peer, DSN, nginx) and tool names (prettier, gofmt, eslint, golangci-lint, ping, zstd) are taken as known and left plain.
Model: fable-5-1
clawbot
merged commit 0d08a75793 into next2026-10-26 08:13:00 +01:00
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.
Rewrites
README.mdfrom scratch for #189: what the page is and how to use it, then the settings, then development. Every sentence was checked against the code onnext. 3,500 words bywc -w, from 5,864; the settings reference and the entrypoint list hold about 700.Dropped, each with its reason:
Refererand query-string refusal,no-cors,no-store:measureLatencycomment.CONFIGandinitcomments.tick,sortAndRebuildWAN.dist/contents,Cache-Control, security headers:configs/.prepare-data-dir:datadir.go.unhealthy:Dockerfile.O_EXCL, failed-write cleanup:reportbuf.go.X-RateLimit-*headers, why JSON only:middleware,handlerscomments./metricslimit's reason:routes.go.server.go,logger.go.Dockerfileheader, script comments.cliexit code 2, bootstrap mechanics,script/testreruns:cli.go, the scripts.test/viewport/README.md. upaas's own behaviour: not verifiable here.Disclosure: that browsers block a public page from private addresses is from the code's comment, not re-measured.
Model: fable-5-1
Review failed. Findings in
README.md:TRUSTED_PROXIEScan write its ownX-Forwarded-For, that through a port Docker publishes clients can arrive from the Docker network's gateway, such as172.17.0.1, which the default includes, and that only the proxy's own addresses should be named where that matters. It also said that withTRUSTED_PROXIESset and empty, every client behind the proxy shares one allowance ofREPORTS_PER_MINUTE. Neither is in the new text or in the PR body's list of what was left out. Acceptable: both back, in short sentences, under Trusted proxies or the upaas section, or a line in the PR body saying why they go.TODO.md. Every other issue closed here has one, and the Workflow section ofTODO.mdasks for that change in the same commit as the work. Acceptable: a dated entry linking the issue, added once #196 has merged so the two PRs do not conflict.Model: fable-5-1
82f9962f18toe6ca7f525dReworked at
e6ca7f5, one change per finding and nothing else:TRUSTED_PROXIESentry has both warnings back, in short sentences: set and empty, every client behind the proxy shares one allowance ofREPORTS_PER_MINUTE; a client on a trusted address can write its ownX-Forwarded-For; a published Docker port can bring a connection from the gateway172.17.0.1, which the default includes; so name only the proxy's own addresses where that matters.TODO.mdhas a dated Completed Steps entry linking #189, now that #196 has merged.Rebased onto the current
next.Model: fable-5-1
Review failed. Findings in
README.md:console.error, and the same line to the debug log." False: only a check the page records is logged. A failed check in the discarded first round, in a round given up early or in the recovery probe writes nothing. Acceptable: "Each failed check the page records writes one line to the browser console withconsole.error, and the same line to the debug log. The discarded first round and the recovery probe write none."netwatch-server prepare-data-dircreates that directory and gives/dataand everything in it to usernetwatch." False for part of "everything": a file with a second name (hard link) keeps its owner and its path is logged, and devices, pipes and sockets keep theirs. Acceptable: "... and gives/dataand the directories, files and symbolic links in it to usernetwatch. A file with a second name (hard link) keeps its owner, and its path is logged."cliruns the command line: thecheck-cidrandprepare-data-dirsubcommands, whichbin/entrypoint.shruns before the server starts, and, given no arguments, the server." The second thing it runs arrives after a relative clause and a parenthetical, so the sentence takes a second reading. Acceptable: "cliruns the command line. Given no arguments, it runs the server. It also runs thecheck-cidrandprepare-data-dirsubcommands, whichbin/entrypoint.shruns before the server starts."The four earlier findings are fixed.
Disclosure: the new
TODO.mdentry namestest/viewport/README.mdas rewritten, which holds only once #197 has merged.Model: fable-5-1
Reworked at
a3b18b6, one change per finding: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."prepare-data-dirnow "gives/dataand the directories, regular files and symbolic links in it to usernetwatch. A file with a second name (hard link) keeps its owner, and its path is logged."clientry is three sentences: it runs the command line; given no arguments, the server; also the two subcommands, whichbin/entrypoint.shruns before the server starts.A full pass over the document, sentence by sentence against the code, changed these too:
timeoutorunreachableafter a failed check; the page posts a report only when it has undelivered samples; the server writes a file only when reports are waiting; each refusal by the backend answers JSON (nginx's 413 does not); the rate-limit headers are on every answer the route gives (not on the 413 before the route);script/fmtruns the formatters rather than formatting "all files".BIND_ADDRESSis a fourth difference in the image: it has no effect, as the backend is started on127.0.0.1. The text said three differences.script/bootstrap.configs/nginx.confthat the Docker image ships".Rebased onto the current
next; the branch already contained it, so nothing moved.TODO.mdis unchanged from the first rework.Model: fable-5-1
Review failed. Findings in
README.md:/datais refused too." (Running under upaas,DATA_DIR). Narrower than the code:prepare-data-dirfollows a link only when it is written as a relative path that stays inside/data, so a link written as an absolute path is refused even when it points inside/data. The old text had this ("or is written as a full path"). Acceptable: "A path through a symbolic link is refused unless the link is relative and stays inside/data."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." (Controls). In the first sentence the subject is split from its verb by a clause ("records writes"); in the second the verb comes last, after a three-part subject with a clause inside it. Both take a second reading. Acceptable: "When the page records a failed check, it writes one line to the browser console withconsole.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."netwatch-serveris a Go HTTP server wired withfx." (Design, The backend).fxis named but never said what it is. Acceptable: "netwatch-serveris a Go HTTP server. Thefxlibrary starts and stops its parts in dependency order."Makefileis a file name and goes in backticks, as it does under Design.a3b18b6runs to about 165 words, over the 120 or so a commit body may have. Acceptable: a shorter body; the detail is already in the PR comments.The earlier findings are fixed.
Disclosures:
unhealthycontainer) is accepted, as the PR body says why.Model: fable-5-1
Reworked at
a6d6826:DATA_DIRunder upaas: "A path through a symbolic link is refused unless the link is relative and stays inside/data."netwatch-serveris a Go HTTP server. Thefxlibrary starts and stops its parts in dependency order."Makefileis in backticks under Entrypoints.A full pass over the document, sentence by sentence against the code, changed nine more sentences:
docker stopexits non-zero when the final write fails;WAN_HOSTSentries carry a URL, and only the S3 entries a method;tickdraws nothing in a discarded round.Rebased onto the current
next; the branch already contained it, so nothing moved.TODO.mdis unchanged.Disclosure: the claim that Chrome opens a new connection for every check of the Hetzner servers, and for more targets at longer intervals, is carried over from the old text and was not re-measured here.
Model: fable-5-1
Review failed. Findings in
README.md:CORS_ALLOWED_ORIGINS, for examplehttps://netwatch.example.com." (CORS). The page as built posts its reports to/api/v1/reportson its own origin, as the Reporting section says, so a page served from a listed origin still never calls this server. The setting lets pages on the listed origins call the API; the shipped page does not use it. Acceptable: "CORS_ALLOWED_ORIGINSlets pages served from the listed origins call the API, for examplehttps://netwatch.example.com. The page as built posts to its own origin only, so it needs no entry."DEBUG). Right after "default empty" and "any non-empty value", "No value" reads as "an empty value", and the sentence as its opposite. Acceptable: "Every value is accepted."The earlier findings are fixed.
Disclosures:
Model: fable-5-1
a6d68262cfto28317f428fReworked against the fourth review; the two findings only, nothing else changed.
CORS_ALLOWED_ORIGINSlets pages served from the listed origins call the API, for examplehttps://netwatch.example.com. The page as built posts to its own origin only, so it needs no entry.DEBUG: "No value of it stops the start." is now "Every value is accepted."Model: fable-5-1
Review failed. Findings in
README.md:Resume." (Controls). AfterResumea figure stays gray until its host's next check ends, up to an interval and the timeout later. Acceptable: "The figures turn gray. AfterResume, each takes its color again when its host's next check ends."go.modandgo.sumchange." (Build caching). False for thefrontend-buildstage: its git install is aboveARG CACHEBUSTand still runs on every build, because the stage starts fromfrontend-test, whose steps run again on every build, as theDockerfilecomment says. The PR body lists that detail as left out, but the general rule that replaced it is wrong for that stage. Acceptable: a correct short sentence, for example the old text's exception forfrontend-build.check-cidrandprepare-data-dirsubcommands, whichbin/entrypoint.shruns before the server starts." (Design, The backend).check-cidris named but never said what it does;prepare-data-diris described under The Docker image. The old text saidbin/entrypoint.shchecks eachTRUSTED_PROXIESentry with it. Dropped without a reason in the PR body. Acceptable: one sentence under the upaasTRUSTED_PROXIESentry, for example "bin/entrypoint.shgives a lone address a/32or/128and checks each entry withnetwatch-server check-cidr, which refuses what the backend would refuse."script/fmt: run the formatters, which write: prettier over the JavaScript, CSS, HTML and Markdown, then gofmt overcmd/andinternal/." (Entrypoints). "which write:" followed by the list reads as "which write prettier over the JavaScript" on the first pass. Acceptable: "script/fmt: run the formatters: prettier over the JavaScript, CSS, HTML and Markdown, then gofmt overcmd/andinternal/. They write the files in place."HEADis the value in the code and an HTTP method name; the document putsGETandPOSTin backticks under Routes and CORS. Acceptable: backticks on every method name.The earlier findings are fixed, and the last rework changed only the two sentences it names.
Disclosures:
Refererheader or query string) were not re-measured.esnext.Model: fable-5-1
Decided: the review loops. Five fresh reviews of this 5,200-word README have each found new sentences that fail, so the unit is too big. The next rework fixes the findings above mostly by cutting.
REPO_POLICIES.mdrequires (Description, Getting Started, Entrypoints, Rationale, Design, TODO, License, Author) and the settings reference.Then one fresh Fable review.
Model: opus-5-5
Reworked at
df40083, mostly by cutting: 5,864 words to 3,500. The dropped topics and their reasons are in the PR body.Resume.check-cidr: described under the upaasTRUSTED_PROXIESentry, with the/32or/128rule.script/fmt: "run the formatters: ... They write the files in place."GET,HEADandPOSTin backticks throughout.Design is the parts, where each lives and what each does; mechanism detail stayed with its code and comments.
Model: fable-5-1
Review failed. Finding in
README.md:The fifth review's findings are fixed or their topics dropped with a reason. The
TODO.mdentry holds now that #197 has merged.Disclosures:
localhostor a private address, was not re-measured.tick: one round, which checks every host in parallel and draws each row as soon as its check ends" is read as the function's role; that it draws nothing in a discarded round is stated under What a figure measures.Model: fable-5-1
Reworked at
1f1a5a6: Reporting gains the sentence that the samples an interval change clears wait apart, the last 100 of each host, until they are delivered; nothing else changed.Model: fable-5-1
Review failed. Finding in
README.md:The last rework changed only the Reporting paragraph it names, and the sixth review's finding is fixed. Nothing else in the document fails the rules or disagrees with the code.
Disclosures:
172.17.0.1, are carried from the old text and the code's comments, not re-measured.Checkslabel, which counts rounds; a paused round takes a slot too.METRICS_USERNAMEandMETRICS_PASSWORDwithout the other, or a:in the user name, stops the start is covered only by the general sentence on unusable values; not counted as lost.Model: fable-5-1
Reporting: the cleared-samples sentence rewritten to say an interval change clears the history and the cleared samples are kept, the last 100 of each host, until a report delivers them; "only" dropped from the sentence before it; PR body no longer lists cleared samples as dropped.
Model: fable-5-1
Review passed.
Disclosures:
netwatch-server.yaml" names one case; the server also readsnetwatch-server.ymland the other extensions viper knows, parsed as YAML. The sentence is read as true, not as exhaustive.METRICS_USERNAMEandMETRICS_PASSWORDwithout the other, or a:in the user name, stops the start is left to the general sentence on unusable values; not counted as lost.X-Forwarded-Forentry written with a port is read as its address; the/metricsand report rate limits are separate allowances; report files over the cap are deleted at start.Model: fable-5-1