Removed paths. A file or directory that is gone when the scan reaches it is passed over with no line, no skipped count and no record. That covers a directory gone before it is opened, an entry gone before its stat, and a file gone before the hash phase opens it. Every other error is reported as before. If the first of several hard links to one file is gone, the hash phase reads the next link.
Progress line. On a terminal every display is now the library's spinner followed by the line, the hash phase's included. A phase with an exact total pads its line and ends it with its percent and a 10-column bar, so the bar stays at a fixed distance from the right edge. sfdupes draws that bar itself, because the library shows no spinner beside its own bar. A line too wide for the terminal loses its rate, or the words of a stalled phase, before its bar.
Label. The time remaining reads remain in the output, the code and the README.
Not in the diff: on an 80-column terminal at ordinary counts, a stalled phase with a bar now shows the bar instead of saying where it waits.
Disclosures:
Judgement call: an operand removed after the scan starts is also passed over silently.
Deviation: README's example of a stalled line keeping its words now names a terminal 100 columns wide, not 80.
Model: opus-5-5
Implements https://git.eeqj.de/sneak/sfdupes/issues/133.
**Removed paths.** A file or directory that is gone when the scan reaches it is passed over with no line, no skipped count and no record. That covers a directory gone before it is opened, an entry gone before its stat, and a file gone before the hash phase opens it. Every other error is reported as before. If the first of several hard links to one file is gone, the hash phase reads the next link.
**Progress line.** On a terminal every display is now the library's spinner followed by the line, the hash phase's included. A phase with an exact total pads its line and ends it with its percent and a 10-column bar, so the bar stays at a fixed distance from the right edge. sfdupes draws that bar itself, because the library shows no spinner beside its own bar. A line too wide for the terminal loses its rate, or the words of a stalled phase, before its bar.
**Label.** The time remaining reads `remain` in the output, the code and the README.
Not in the diff: on an 80-column terminal at ordinary counts, a stalled phase with a bar now shows the bar instead of saying where it waits.
Disclosures:
- Judgement call: an operand removed after the scan starts is also passed over silently.
- Deviation: README's example of a stalled line keeping its words now names a terminal 100 columns wide, not 80.
Model: opus-5-5
scan_test.go:690: no test checks that the walk still warns about an error other than a removed path. If the new checks in walkOneDir, emitFile and seedRoot caught every error instead of only a missing path, the suite would still pass, so a permission-denied directory could go silent unnoticed. Acceptable: a test that an unreadable directory, and a file in a directory that can be read but not searched, each still give a warning and count as skipped.
README.md:636: "A file or directory removed before the scan reaches it is not an error." also covers an operand that is already gone when scan starts, which "scan mode" makes a fatal error (exit 1). Acceptable: say the path was removed while the scan runs. The new TODO.md entry uses the same wording.
README.md:638: "Such a path gets no record" is not true of every file removed since the walk. The hash phase opens only one of several hard links and never opens an empty file, so a removed later link, or a removed empty file, still gets a record. Acceptable: a short true sentence, for example naming the hash-phase case as a file that is gone when the phase opens it.
README.md:941: "Where the words and the time remaining do not both fit, as at millions of files and times in hours, the words give way." The subject comes after two leading clauses, and the bullet already says the words give way before the four parts kept whole. Acceptable: remove it, or one short sentence that starts with its subject.
README.md:942: "A terminal made narrower while a phase runs gets the same: the next draw erases the line within the new width and fits the line to it, and the display goes on redrawing in place." runs to 35 words. Acceptable: two short sentences.
Judgement call: the older Completed Steps entries in TODO.md that say ETA are history, and were not counted against this change.
Model: opus-5-5
FAIL: needs-rework.
1. `scan_test.go:690`: no test checks that the walk still warns about an error other than a removed path. If the new checks in `walkOneDir`, `emitFile` and `seedRoot` caught every error instead of only a missing path, the suite would still pass, so a permission-denied directory could go silent unnoticed. Acceptable: a test that an unreadable directory, and a file in a directory that can be read but not searched, each still give a warning and count as skipped.
2. `README.md:636`: "A file or directory removed before the scan reaches it is not an error." also covers an operand that is already gone when `scan` starts, which "`scan` mode" makes a fatal error (exit 1). Acceptable: say the path was removed while the scan runs. The new `TODO.md` entry uses the same wording.
3. `README.md:638`: "Such a path gets no record" is not true of every file removed since the walk. The hash phase opens only one of several hard links and never opens an empty file, so a removed later link, or a removed empty file, still gets a record. Acceptable: a short true sentence, for example naming the hash-phase case as a file that is gone when the phase opens it.
4. `README.md:941`: "Where the words and the time remaining do not both fit, as at millions of files and times in hours, the words give way." The subject comes after two leading clauses, and the bullet already says the words give way before the four parts kept whole. Acceptable: remove it, or one short sentence that starts with its subject.
5. `README.md:942`: "A terminal made narrower while a phase runs gets the same: the next draw erases the line within the new width and fits the line to it, and the display goes on redrawing in place." runs to 35 words. Acceptable: two short sentences.
Judgement call: the older Completed Steps entries in `TODO.md` that say ETA are history, and were not counted against this change.
Model: opus-5-5
Rework pushed, one line per finding of the review:
Added TestScanWarnsAboutUnreadablePaths: an unreadable directory, a file in a directory that can be read but not searched, and such a file given as an operand each give a warning and count as skipped.
Now "removed while the scan runs", in README.md and in the TODO.md entry.
Now: a path gone when the walk reaches it gets no record, and a file gone when the hash phase opens it gets none either.
Removed.
Split into two sentences.
Judgement call: the TODO.md entry also drops "gives it no record", which had the same fault as finding 3.
Rule suppressed: gosec on the test's cleanup, which gives the directories back their search bit so they can be deleted, as main_test.go already does.
Model: opus-5-5
Rework pushed, one line per finding of the review:
1. Added `TestScanWarnsAboutUnreadablePaths`: an unreadable directory, a file in a directory that can be read but not searched, and such a file given as an operand each give a warning and count as skipped.
2. Now "removed while the scan runs", in `README.md` and in the `TODO.md` entry.
3. Now: a path gone when the walk reaches it gets no record, and a file gone when the hash phase opens it gets none either.
4. Removed.
5. Split into two sentences.
Judgement call: the `TODO.md` entry also drops "gives it no record", which had the same fault as finding 3.
Rule suppressed: `gosec` on the test's cleanup, which gives the directories back their search bit so they can be deleted, as `main_test.go` already does.
Model: opus-5-5
progress_test.go:746: TestTerminalBarStaysAtRightEdge checks only where the bar starts. A bar drawn only as long as its filled cells, so that its right end moves as the phase advances, would pass every test. Acceptable: the test also checks that the bar ends at the same distance from the right edge each time, with a partly filled bar and with a full one.
progress.go:255: no test covers this line. If it counted the text's bytes instead of its columns, every draw of a phase whose bar has a filled cell would erase the line and start the spinner over, so the spinner would stop turning, and the suite would still pass. Acceptable: a test that draws such a phase several times at one width and checks that the spinner changes from draw to draw.
README.md:839: "Once the walk passes the estimate, or when there are no such records, as on a first scan, the time remaining is unknown." The subject comes after three leading clauses. Acceptable: start with the subject, for example "The time remaining is unknown once the walk passes the estimate, and when there are no such records, as on a first scan."
README.md:913: "On a terminal, a phase with an exact total ends its line with its percent and a bar 10 columns wide." is not true of a phase whose total is 0, such as load on a first scan or update when nothing changed: it shows no bar. Acceptable: draw a full bar for a total of 0 too, or add a short sentence saying that a phase with nothing to do shows no bar.
Judgement call: on a terminal about 95 to 105 columns wide, the hash phase's bar in a long scan comes and goes as the rate, the stall words and the times change length, because README has the bar give way before the rate. That order predates this change and is not counted against it.
Model: opus-5-5
FAIL: needs-rework.
1. `progress_test.go:746`: `TestTerminalBarStaysAtRightEdge` checks only where the bar starts. A bar drawn only as long as its filled cells, so that its right end moves as the phase advances, would pass every test. Acceptable: the test also checks that the bar ends at the same distance from the right edge each time, with a partly filled bar and with a full one.
2. `progress.go:255`: no test covers this line. If it counted the text's bytes instead of its columns, every draw of a phase whose bar has a filled cell would erase the line and start the spinner over, so the spinner would stop turning, and the suite would still pass. Acceptable: a test that draws such a phase several times at one width and checks that the spinner changes from draw to draw.
3. `README.md:839`: "Once the walk passes the estimate, or when there are no such records, as on a first scan, the time remaining is unknown." The subject comes after three leading clauses. Acceptable: start with the subject, for example "The time remaining is unknown once the walk passes the estimate, and when there are no such records, as on a first scan."
4. `README.md:913`: "On a terminal, a phase with an exact total ends its line with its percent and a bar 10 columns wide." is not true of a phase whose total is 0, such as `load` on a first scan or `update` when nothing changed: it shows no bar. Acceptable: draw a full bar for a total of 0 too, or add a short sentence saying that a phase with nothing to do shows no bar.
Judgement call: on a terminal about 95 to 105 columns wide, the hash phase's bar in a long scan comes and goes as the rate, the stall words and the times change length, because README has the bar give way before the rate. That order predates this change and is not counted against it.
Model: opus-5-5
Rework: findings 1 to 4 stand. For finding 4, the short README sentence is enough: a phase with nothing to do shows no bar.
Added to the rework, from the reviewer's judgement call: the bar must not come and go as the line's text changes length, which is the movement #133 reports. A line too wide for the terminal first loses its rate, the words of a stalled phase or what it waits for. It loses its bar only when the four kept parts and the bar do not fit.
Model: opus-5-5
Rework: findings 1 to 4 stand. For finding 4, the short README sentence is enough: a phase with nothing to do shows no bar.
Added to the rework, from the reviewer's judgement call: the bar must not come and go as the line's text changes length, which is the movement https://git.eeqj.de/sneak/sfdupes/issues/133 reports. A line too wide for the terminal first loses its rate, the words of a stalled phase or what it waits for. It loses its bar only when the four kept parts and the bar do not fit.
Model: opus-5-5
A path removed while the scan runs gets no warning and no skipped
count, in the walk or the hash phase. If the first of several hard
links is gone, the next is read. Other errors are still warned about.
On a terminal every display is the library's spinner, then the line. A
phase with an exact total ends the padded line with its percent and a
bar at a fixed column, drawn by sfdupes, as the library shows no
spinner beside its own bar. A too-wide line loses its rate first.
The time remaining is labelled remain, not eta.
Judgement call: an operand removed mid-scan is skipped silently too.
Deviation: README's stalled-line example keeps its words on 100
columns, not 80.
Model: opus-5-5
TestTerminalBarStaysAtRightEdge also checks where the bar ends, partly filled and full.
Added TestTerminalSpinnerTurnsBesideBar: a bar with a filled cell, drawn several times at one width, must turn the spinner at every draw.
Rewritten to start with its subject, as suggested.
Added "A phase with nothing to do shows no bar."
A too-wide line now loses its rate or the words of a stalled phase first, and its bar only when the four kept parts and the bar do not fit; README and the TODO.md entry state the order, and TestTerminalRateGivesWayBeforeBar checks for the bar without the rate at 90 columns.
Judgement call: once the bar gives way the rate stays out too, so the order holds at every width; the same test checks this at 85 columns.
Deviation: on 80 columns a stalled phase with a bar now shows its bar instead of where it waits, so README's stalled-line example and TestTerminalStalledLines now use 100 columns.
Judgement call: TestTerminalNarrowedRedrawsInPlace narrows to 80 columns, not 90, so the bar still gives way there as its comment says.
Model: opus-5-5
Rework pushed, one line per item of https://git.eeqj.de/sneak/sfdupes/pulls/139#issuecomment-155135 and https://git.eeqj.de/sneak/sfdupes/pulls/139#issuecomment-155151:
1. `TestTerminalBarStaysAtRightEdge` also checks where the bar ends, partly filled and full.
2. Added `TestTerminalSpinnerTurnsBesideBar`: a bar with a filled cell, drawn several times at one width, must turn the spinner at every draw.
3. Rewritten to start with its subject, as suggested.
4. Added "A phase with nothing to do shows no bar."
5. A too-wide line now loses its rate or the words of a stalled phase first, and its bar only when the four kept parts and the bar do not fit; README and the `TODO.md` entry state the order, and `TestTerminalRateGivesWayBeforeBar` checks for the bar without the rate at 90 columns.
Judgement call: once the bar gives way the rate stays out too, so the order holds at every width; the same test checks this at 85 columns.
Deviation: on 80 columns a stalled phase with a bar now shows its bar instead of where it waits, so README's stalled-line example and `TestTerminalStalledLines` now use 100 columns.
Judgement call: `TestTerminalNarrowedRedrawsInPlace` narrows to 80 columns, not 90, so the bar still gives way there as its comment says.
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.
Implements #133.
Removed paths. A file or directory that is gone when the scan reaches it is passed over with no line, no skipped count and no record. That covers a directory gone before it is opened, an entry gone before its stat, and a file gone before the hash phase opens it. Every other error is reported as before. If the first of several hard links to one file is gone, the hash phase reads the next link.
Progress line. On a terminal every display is now the library's spinner followed by the line, the hash phase's included. A phase with an exact total pads its line and ends it with its percent and a 10-column bar, so the bar stays at a fixed distance from the right edge. sfdupes draws that bar itself, because the library shows no spinner beside its own bar. A line too wide for the terminal loses its rate, or the words of a stalled phase, before its bar.
Label. The time remaining reads
remainin the output, the code and the README.Not in the diff: on an 80-column terminal at ordinary counts, a stalled phase with a bar now shows the bar instead of saying where it waits.
Disclosures:
Model: opus-5-5
FAIL: needs-rework.
scan_test.go:690: no test checks that the walk still warns about an error other than a removed path. If the new checks inwalkOneDir,emitFileandseedRootcaught every error instead of only a missing path, the suite would still pass, so a permission-denied directory could go silent unnoticed. Acceptable: a test that an unreadable directory, and a file in a directory that can be read but not searched, each still give a warning and count as skipped.README.md:636: "A file or directory removed before the scan reaches it is not an error." also covers an operand that is already gone whenscanstarts, which "scanmode" makes a fatal error (exit 1). Acceptable: say the path was removed while the scan runs. The newTODO.mdentry uses the same wording.README.md:638: "Such a path gets no record" is not true of every file removed since the walk. The hash phase opens only one of several hard links and never opens an empty file, so a removed later link, or a removed empty file, still gets a record. Acceptable: a short true sentence, for example naming the hash-phase case as a file that is gone when the phase opens it.README.md:941: "Where the words and the time remaining do not both fit, as at millions of files and times in hours, the words give way." The subject comes after two leading clauses, and the bullet already says the words give way before the four parts kept whole. Acceptable: remove it, or one short sentence that starts with its subject.README.md:942: "A terminal made narrower while a phase runs gets the same: the next draw erases the line within the new width and fits the line to it, and the display goes on redrawing in place." runs to 35 words. Acceptable: two short sentences.Judgement call: the older Completed Steps entries in
TODO.mdthat say ETA are history, and were not counted against this change.Model: opus-5-5
c4aeec355atoe80c6541d2Rework pushed, one line per finding of the review:
TestScanWarnsAboutUnreadablePaths: an unreadable directory, a file in a directory that can be read but not searched, and such a file given as an operand each give a warning and count as skipped.README.mdand in theTODO.mdentry.Judgement call: the
TODO.mdentry also drops "gives it no record", which had the same fault as finding 3.Rule suppressed:
gosecon the test's cleanup, which gives the directories back their search bit so they can be deleted, asmain_test.goalready does.Model: opus-5-5
FAIL: needs-rework.
progress_test.go:746:TestTerminalBarStaysAtRightEdgechecks only where the bar starts. A bar drawn only as long as its filled cells, so that its right end moves as the phase advances, would pass every test. Acceptable: the test also checks that the bar ends at the same distance from the right edge each time, with a partly filled bar and with a full one.progress.go:255: no test covers this line. If it counted the text's bytes instead of its columns, every draw of a phase whose bar has a filled cell would erase the line and start the spinner over, so the spinner would stop turning, and the suite would still pass. Acceptable: a test that draws such a phase several times at one width and checks that the spinner changes from draw to draw.README.md:839: "Once the walk passes the estimate, or when there are no such records, as on a first scan, the time remaining is unknown." The subject comes after three leading clauses. Acceptable: start with the subject, for example "The time remaining is unknown once the walk passes the estimate, and when there are no such records, as on a first scan."README.md:913: "On a terminal, a phase with an exact total ends its line with its percent and a bar 10 columns wide." is not true of a phase whose total is 0, such asloadon a first scan orupdatewhen nothing changed: it shows no bar. Acceptable: draw a full bar for a total of 0 too, or add a short sentence saying that a phase with nothing to do shows no bar.Judgement call: on a terminal about 95 to 105 columns wide, the hash phase's bar in a long scan comes and goes as the rate, the stall words and the times change length, because README has the bar give way before the rate. That order predates this change and is not counted against it.
Model: opus-5-5
Rework: findings 1 to 4 stand. For finding 4, the short README sentence is enough: a phase with nothing to do shows no bar.
Added to the rework, from the reviewer's judgement call: the bar must not come and go as the line's text changes length, which is the movement #133 reports. A line too wide for the terminal first loses its rate, the words of a stalled phase or what it waits for. It loses its bar only when the four kept parts and the bar do not fit.
Model: opus-5-5
e80c6541d2toe6452bb67bRework pushed, one line per item of #139 (comment) and #139 (comment):
TestTerminalBarStaysAtRightEdgealso checks where the bar ends, partly filled and full.TestTerminalSpinnerTurnsBesideBar: a bar with a filled cell, drawn several times at one width, must turn the spinner at every draw.TODO.mdentry state the order, andTestTerminalRateGivesWayBeforeBarchecks for the bar without the rate at 90 columns.Judgement call: once the bar gives way the rate stays out too, so the order holds at every width; the same test checks this at 85 columns.
Deviation: on 80 columns a stalled phase with a bar now shows its bar instead of where it waits, so README's stalled-line example and
TestTerminalStalledLinesnow use 100 columns.Judgement call:
TestTerminalNarrowedRedrawsInPlacenarrows to 80 columns, not 90, so the bar still gives way there as its comment says.Model: opus-5-5
PASS: #139 passes review and is ready to merge into
next.Model: opus-5-5