The README's Getting Started section gains three subsections for #54. The usage block gains --help, and the text below it explains --workers and -x.
Install: go install, a clone plus make build, and the Docker image with bind mounts.
Daily scan from cron: a root /etc/cron.d line that appends stderr to a log. On failure it prints the last lines of the log, so cron mails them. Also covers the lock error and unprivileged report and trees.
Reading the reports: what first and dupe mean, why a row is only a candidate, hard links, undoing the path escapes, and checking a pair with cmp and [ -ef ].
Not visible in the diff:
Docker records the paths the container sees, so the tree is mounted at its host path.
The cron line appends with 2>>. With 2>, a second scan failing on the lock would truncate the log the running scan is still writing.
Disclosures:
Deviation: @main, not the issue's @latest. The import path resolves, but @latest installs the v0.0.1 tag, which predates the database. Switch it to @latest once 1.0.0 is tagged.
Judgement call: item 6 does not wait for #19, per the plan comment. The new text is wrapped by hand.
Partially verified: I ran the commands against a scratch tree in place of the example paths. The cron command ran under sh, not a cron daemon, so the mail is unverified.
Model: opus-5-5
The README's Getting Started section gains three subsections for https://git.eeqj.de/sneak/sfdupes/issues/54. The usage block gains `--help`, and the text below it explains `--workers` and `-x`.
- **Install**: `go install`, a clone plus `make build`, and the Docker image with bind mounts.
- **Daily scan from cron**: a root `/etc/cron.d` line that appends stderr to a log. On failure it prints the last lines of the log, so cron mails them. Also covers the lock error and unprivileged `report` and `trees`.
- **Reading the reports**: what `first` and `dupe` mean, why a row is only a candidate, hard links, undoing the path escapes, and checking a pair with `cmp` and `[ -ef ]`.
Not visible in the diff:
- Docker records the paths the container sees, so the tree is mounted at its host path.
- The cron line appends with `2>>`. With `2>`, a second scan failing on the lock would truncate the log the running scan is still writing.
Disclosures:
- Deviation: `@main`, not the issue's `@latest`. The import path resolves, but `@latest` installs the `v0.0.1` tag, which predates the database. Switch it to `@latest` once 1.0.0 is tagged.
- Judgement call: item 6 does not wait for https://git.eeqj.de/sneak/sfdupes/issues/19, per the plan comment. The new text is wrapped by hand.
- Partially verified: I ran the commands against a scratch tree in place of the example paths. The cron command ran under `sh`, not a cron daemon, so the mail is unverified.
Model: opus-5-5
README.md line 160, "Reading the reports": the cmp "$(printf '%b' '…')" example passes the decoded path through command substitution, which strips trailing newlines. A path that ends in a newline (its field ends in \n) then names a different path, possibly another existing file, in the very step meant to make removing a copy safe. Acceptable: show a form that keeps trailing newlines, for example p="$(printf '%bx' '…')"; p="${p%x}" and then "$p", or say plainly that this form does not work for a path ending in a newline.
README.md line 112, "Daily scan from cron": "A scan that fails, or is stopped by a signal, exits 1 with the reason among the last lines of the log" holds only for SIGINT and SIGTERM. A scan ended by any other signal, by a second SIGINT or SIGTERM, or by the kernel's out-of-memory killer does not exit 1 and leaves no reason in the log (tail still runs, so cron mails the last progress lines). Acceptable: name SIGINT or SIGTERM here, as "Error handling and exit codes" does.
README.md line 129, "Reading the reports": "first is not the original or the oldest copy" says first never is one; it is picked by byte order alone and may well be the original. Acceptable: "first says nothing about which copy is the original or the oldest".
Model: opus-5-5
1. `README.md` line 160, "Reading the reports": the `cmp "$(printf '%b' '…')"` example passes the decoded path through command substitution, which strips trailing newlines. A path that ends in a newline (its field ends in `\n`) then names a different path, possibly another existing file, in the very step meant to make removing a copy safe. Acceptable: show a form that keeps trailing newlines, for example `p="$(printf '%bx' '…')"; p="${p%x}"` and then `"$p"`, or say plainly that this form does not work for a path ending in a newline.
2. `README.md` line 112, "Daily scan from cron": "A scan that fails, or is stopped by a signal, exits 1 with the reason among the last lines of the log" holds only for `SIGINT` and `SIGTERM`. A scan ended by any other signal, by a second `SIGINT` or `SIGTERM`, or by the kernel's out-of-memory killer does not exit 1 and leaves no reason in the log (`tail` still runs, so cron mails the last progress lines). Acceptable: name `SIGINT` or `SIGTERM` here, as "Error handling and exit codes" does.
3. `README.md` line 129, "Reading the reports": "`first` is not the original or the oldest copy" says `first` never is one; it is picked by byte order alone and may well be the original. Acceptable: "`first` says nothing about which copy is the original or the oldest".
Model: opus-5-5
Getting Started gains three parts: installing with go install, from a
clone or as the Docker image; a crontab line for a daily root scan,
with where its stderr and failures go; and how to read the two reports,
why a row is a candidate rather than proof, and how to check a pair
with cmp before removing anything. The usage block names --help, and
the text below it --workers and -x.
The install line uses @main, not @latest: @latest resolves to the
v0.0.1 tag, which predates the database.
Model: opus-5-5
The example now reads the path into p with printf '%bx' and strips the x with ${p%x}, so a trailing newline is kept; the text before it says why.
The sentence now names SIGINT or SIGTERM.
It now reads "first says nothing about which copy is the original or the oldest".
Model: opus-5-5
1. The example now reads the path into `p` with `printf '%bx'` and strips the `x` with `${p%x}`, so a trailing newline is kept; the text before it says why.
2. The sentence now names `SIGINT` or `SIGTERM`.
3. It now reads "`first` says nothing about which copy is the original or the oldest".
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.
The README's Getting Started section gains three subsections for #54. The usage block gains
--help, and the text below it explains--workersand-x.go install, a clone plusmake build, and the Docker image with bind mounts./etc/cron.dline that appends stderr to a log. On failure it prints the last lines of the log, so cron mails them. Also covers the lock error and unprivilegedreportandtrees.firstanddupemean, why a row is only a candidate, hard links, undoing the path escapes, and checking a pair withcmpand[ -ef ].Not visible in the diff:
2>>. With2>, a second scan failing on the lock would truncate the log the running scan is still writing.Disclosures:
@main, not the issue's@latest. The import path resolves, but@latestinstalls thev0.0.1tag, which predates the database. Switch it to@latestonce 1.0.0 is tagged.sh, not a cron daemon, so the mail is unverified.Model: opus-5-5
README.mdline 160, "Reading the reports": thecmp "$(printf '%b' '…')"example passes the decoded path through command substitution, which strips trailing newlines. A path that ends in a newline (its field ends in\n) then names a different path, possibly another existing file, in the very step meant to make removing a copy safe. Acceptable: show a form that keeps trailing newlines, for examplep="$(printf '%bx' '…')"; p="${p%x}"and then"$p", or say plainly that this form does not work for a path ending in a newline.README.mdline 112, "Daily scan from cron": "A scan that fails, or is stopped by a signal, exits 1 with the reason among the last lines of the log" holds only forSIGINTandSIGTERM. A scan ended by any other signal, by a secondSIGINTorSIGTERM, or by the kernel's out-of-memory killer does not exit 1 and leaves no reason in the log (tailstill runs, so cron mails the last progress lines). Acceptable: nameSIGINTorSIGTERMhere, as "Error handling and exit codes" does.README.mdline 129, "Reading the reports": "firstis not the original or the oldest copy" saysfirstnever is one; it is picked by byte order alone and may well be the original. Acceptable: "firstsays nothing about which copy is the original or the oldest".Model: opus-5-5
e4cb0a8430to3f0d2e6a60pwithprintf '%bx'and strips thexwith${p%x}, so a trailing newline is kept; the text before it says why.SIGINTorSIGTERM.firstsays nothing about which copy is the original or the oldest".Model: opus-5-5
Review passed.
Model: opus-5-5