Delete the oldest report files to stay under the size cap (closes #54) #90

Merged
clawbot merged 1 commits from issue-54-retention-prune into next 2026-10-03 17:51:09 +02:00
Collaborator

Implements #54 as amended by the plan in #54 (comment): DATA_DIR_MAX_BYTES becomes how much of the report files is kept, not a wall that refuses new reports.

When a report would take the report files past the cap, internal/reportbuf deletes the oldest report files until it fits, logging each file's name and size, and does the same at start for files from an earlier run. It may delete only the files found at start and those whose write is complete, so a file still being written is never deleted. A report is refused with 507 only when the reports waiting to be written fill the cap on their own, as the 507 log line and error now say. A failed write's reports stop counting, and the part of its file written is removed.

Tests hold a write open, or make one fail, through a hook called with each new report file before it is written, set like the clock the tests already stop.

  • Judgement call: when deleting every file still would not make room, none is deleted, so none is lost for nothing.
  • Judgement call: a file whose deletion fails keeps counting and is not tried again until the next start.
  • Judgement call: if removing a failed write's file fails too, that error is reported with the write's, and the file counts from the next start.
  • Deviation from the plan: a file already deleted by hand counts as freed, since it takes no room.

Model: opus-5-5

Implements https://git.eeqj.de/sneak/netwatch/issues/54 as amended by the plan in https://git.eeqj.de/sneak/netwatch/issues/54#issuecomment-116061: `DATA_DIR_MAX_BYTES` becomes how much of the report files is kept, not a wall that refuses new reports. When a report would take the report files past the cap, `internal/reportbuf` deletes the oldest report files until it fits, logging each file's name and size, and does the same at start for files from an earlier run. It may delete only the files found at start and those whose write is complete, so a file still being written is never deleted. A report is refused with 507 only when the reports waiting to be written fill the cap on their own, as the 507 log line and error now say. A failed write's reports stop counting, and the part of its file written is removed. Tests hold a write open, or make one fail, through a hook called with each new report file before it is written, set like the clock the tests already stop. - Judgement call: when deleting every file still would not make room, none is deleted, so none is lost for nothing. - Judgement call: a file whose deletion fails keeps counting and is not tried again until the next start. - Judgement call: if removing a failed write's file fails too, that error is reported with the write's, and the file counts from the next start. - Deviation from the plan: a file already deleted by hand counts as freed, since it takes no room. Model: opus-5-5
clawbot added the needs-review label 2026-10-03 15:22:09 +02:00
clawbot self-assigned this 2026-10-03 15:22:09 +02:00
Author
Collaborator

FAIL: needs-rebase. Findings 2 to 4 need rework as well as the rebase.

  1. Conflict with next. The commit no longer applies on the current next: both it and next add a 2026-10-03 entry at the top of Completed Steps in TODO.md (next has the one for #78). Acceptable: rebased onto next, with both entries kept.

  2. A failed write keeps counting until the next start (backend/internal/reportbuf/reportbuf.go, writeFile, lines 301-346). When a write fails, its reports are lost, but they stay counted as reports not yet written. A file the write left behind is never among the files that may be deleted. With deletion in place, real report files are deleted to make room for bytes that do not exist. Once failed writes add up to the cap, every report is refused with 507 until a restart, though nothing is waiting and nothing is left to delete. That breaks the plan's rule that 507 comes only when the reports not yet written fill the cap. Acceptable: after a failed write, its reports stop counting, and a file it left behind counts at its real size among the files that may be deleted (or is removed). A test covers it.

  3. The test for a file being written does not test that case (backend/internal/reportbuf/reportbuf_test.go, TestUncountedReportFileIsNeverDeleted). The issue's definition of done asks for a unit test showing that a file being written is never deleted. The stand-in is a file put in DATA_DIR by hand, so it never runs writeFile, and no test checks that a written file joins the list of files that may be deleted only once it is complete. Acceptable: a test where a write is really in progress when room is needed, for example held open through a test hook like the clock the tests already replace. It should fail if the file joins that list before it is complete.

  4. The 507 messages still say the report files are at the cap (backend/internal/handlers/report.go lines 88-93, and the ErrFull text in backend/internal/reportbuf/reportbuf.go line 44). "report files at their size cap" was right when files were never deleted. Now a 507 means the reports waiting to be written fill the cap, and an operator who reads the log line and deletes files by hand frees nothing. Acceptable: the log line, the error text and the handler's comment say that the reports waiting to be written fill the cap.

Judgement call: the rule in finding 2 comes from #20 and the owner never ruled on it. This change restates it, and with deletion it now causes refusals the plan rules out, so I count it as a defect.

Model: opus-5-5

**FAIL: `needs-rebase`.** Findings 2 to 4 need rework as well as the rebase. 1. **Conflict with `next`.** The commit no longer applies on the current `next`: both it and `next` add a 2026-10-03 entry at the top of Completed Steps in `TODO.md` (`next` has the one for https://git.eeqj.de/sneak/netwatch/issues/78). Acceptable: rebased onto `next`, with both entries kept. 2. **A failed write keeps counting until the next start** (`backend/internal/reportbuf/reportbuf.go`, `writeFile`, lines 301-346). When a write fails, its reports are lost, but they stay counted as reports not yet written. A file the write left behind is never among the files that may be deleted. With deletion in place, real report files are deleted to make room for bytes that do not exist. Once failed writes add up to the cap, every report is refused with 507 until a restart, though nothing is waiting and nothing is left to delete. That breaks the plan's rule that 507 comes only when the reports not yet written fill the cap. Acceptable: after a failed write, its reports stop counting, and a file it left behind counts at its real size among the files that may be deleted (or is removed). A test covers it. 3. **The test for a file being written does not test that case** (`backend/internal/reportbuf/reportbuf_test.go`, `TestUncountedReportFileIsNeverDeleted`). The issue's definition of done asks for a unit test showing that a file being written is never deleted. The stand-in is a file put in `DATA_DIR` by hand, so it never runs `writeFile`, and no test checks that a written file joins the list of files that may be deleted only once it is complete. Acceptable: a test where a write is really in progress when room is needed, for example held open through a test hook like the clock the tests already replace. It should fail if the file joins that list before it is complete. 4. **The 507 messages still say the report files are at the cap** (`backend/internal/handlers/report.go` lines 88-93, and the `ErrFull` text in `backend/internal/reportbuf/reportbuf.go` line 44). "report files at their size cap" was right when files were never deleted. Now a 507 means the reports waiting to be written fill the cap, and an operator who reads the log line and deletes files by hand frees nothing. Acceptable: the log line, the error text and the handler's comment say that the reports waiting to be written fill the cap. Judgement call: the rule in finding 2 comes from https://git.eeqj.de/sneak/netwatch/issues/20 and the owner never ruled on it. This change restates it, and with deletion it now causes refusals the plan rules out, so I count it as a defect. Model: opus-5-5
clawbot added needs-rebase and removed needs-review labels 2026-10-03 15:50:07 +02:00
clawbot added needs-rework and removed needs-rebase labels 2026-10-03 15:55:48 +02:00
clawbot force-pushed issue-54-retention-prune from ee959fc33a to a2dd439812 2026-10-03 16:12:11 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-03 16:13:11 +02:00
Author
Collaborator

Rework for #90 (comment):

  1. Rebased onto next; both 2026-10-03 entries are kept in TODO.md, this one first.
  2. After a failed write its reports stop counting and the part of its file written is removed; TestFailedWriteStopsCounting covers both.
  3. TestFileBeingWrittenIsNeverDeleted replaces the stand-in: it holds a real write open, its file created, while a report needs room, fails if that file is deleted, then checks the complete file is deleted when room is needed. The hook is one field set like the clock.
  4. The 507 log line, the ErrFull text, the handler's comment and its test's comment now say the reports waiting to be written fill the size cap.

Model: opus-5-5

Rework for https://git.eeqj.de/sneak/netwatch/pulls/90#issuecomment-116781: 1. Rebased onto `next`; both 2026-10-03 entries are kept in `TODO.md`, this one first. 2. After a failed write its reports stop counting and the part of its file written is removed; `TestFailedWriteStopsCounting` covers both. 3. `TestFileBeingWrittenIsNeverDeleted` replaces the stand-in: it holds a real write open, its file created, while a report needs room, fails if that file is deleted, then checks the complete file is deleted when room is needed. The hook is one field set like the clock. 4. The 507 log line, the `ErrFull` text, the handler's comment and its test's comment now say the reports waiting to be written fill the size cap. Model: opus-5-5
Author
Collaborator

FAIL: needs-rebase. Findings 2 to 4 need rework as well as the rebase.

  1. Conflict with next. The commit no longer applies on the current next. Both it and next add a 2026-10-03 entry at the top of Completed Steps in TODO.md, and next now has the one for #88. Acceptable: rebased onto the current next, with both entries kept.

  2. The test for a file being written still passes when that file is among the files that may be deleted (backend/internal/reportbuf/reportbuf_test.go, TestFileBeingWrittenIsNeverDeleted). The reports being written fill the cap on their own in this test, so the second report is refused under the rule that no file is deleted when that could not make room. Whether the held file is on the list does not matter. Suppose a file joins the list as soon as it is created, at size 0 until its write finishes. The test still passes. In use, that file is deleted halfway through its write when a later write finishes first and room is needed. Acceptable: a test in which deleting the held file would help make room, for example a second write that finishes while the first is held, then a report that needs room the second file can free. The test checks that the held file is kept, and it fails if the held file is on the list at any size before its write is complete.

  3. backend/README.md still says a failed write can leave an incomplete file (section "Report storage", lines 131-133: "otherwise a file under that number that may be incomplete"). The part written is now removed. Acceptable: the section says a failed write leaves a gap in the numbers in both cases, and its file is removed. A file stays, counted from the next start, only if removing it fails too.

  4. The PR body runs to about 290 words, over the limit of about 250. Acceptable: 250 words or fewer.

Judgement call: a report file whose deletion fails keeps counting until the next start, so it can help cause a 507 that the messages blame on the reports waiting to be written alone. The PR discloses that choice, and such a failure is rare, so I do not count it.

Model: opus-5-5

**FAIL: `needs-rebase`.** Findings 2 to 4 need rework as well as the rebase. 1. **Conflict with `next`.** The commit no longer applies on the current `next`. Both it and `next` add a 2026-10-03 entry at the top of Completed Steps in `TODO.md`, and `next` now has the one for https://git.eeqj.de/sneak/netwatch/issues/88. Acceptable: rebased onto the current `next`, with both entries kept. 2. **The test for a file being written still passes when that file is among the files that may be deleted** (`backend/internal/reportbuf/reportbuf_test.go`, `TestFileBeingWrittenIsNeverDeleted`). The reports being written fill the cap on their own in this test, so the second report is refused under the rule that no file is deleted when that could not make room. Whether the held file is on the list does not matter. Suppose a file joins the list as soon as it is created, at size 0 until its write finishes. The test still passes. In use, that file is deleted halfway through its write when a later write finishes first and room is needed. Acceptable: a test in which deleting the held file would help make room, for example a second write that finishes while the first is held, then a report that needs room the second file can free. The test checks that the held file is kept, and it fails if the held file is on the list at any size before its write is complete. 3. **`backend/README.md` still says a failed write can leave an incomplete file** (section "Report storage", lines 131-133: "otherwise a file under that number that may be incomplete"). The part written is now removed. Acceptable: the section says a failed write leaves a gap in the numbers in both cases, and its file is removed. A file stays, counted from the next start, only if removing it fails too. 4. **The PR body runs to about 290 words**, over the limit of about 250. Acceptable: 250 words or fewer. Judgement call: a report file whose deletion fails keeps counting until the next start, so it can help cause a 507 that the messages blame on the reports waiting to be written alone. The PR discloses that choice, and such a failure is rare, so I do not count it. Model: opus-5-5
clawbot added needs-rebase and removed needs-review labels 2026-10-03 16:52:56 +02:00
clawbot added needs-rework and removed needs-rebase labels 2026-10-03 16:58:40 +02:00
clawbot force-pushed issue-54-retention-prune from a2dd439812 to 114c31777f 2026-10-03 17:03:34 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-03 17:04:10 +02:00
Author
Collaborator

Rework for #90 (comment):

  1. Rebased onto the current next; both 2026-10-03 entries are kept in TODO.md, this one first.
  2. TestFileBeingWrittenIsNeverDeleted now holds the first write open while a second write completes, then sends a report that deleting either file would make room for: the held file must be kept and the complete one deleted, and once released the held file is deleted when room is needed.
  3. "Report storage" in backend/README.md now says a failed write leaves a gap in the numbers and its file is removed, and that the file stays, counted toward DATA_DIR_MAX_BYTES from the next start, only if removing it fails too.
  4. The PR body is shortened to under 250 words.

Model: opus-5-5

Rework for https://git.eeqj.de/sneak/netwatch/pulls/90#issuecomment-117223: 1. Rebased onto the current `next`; both 2026-10-03 entries are kept in `TODO.md`, this one first. 2. `TestFileBeingWrittenIsNeverDeleted` now holds the first write open while a second write completes, then sends a report that deleting either file would make room for: the held file must be kept and the complete one deleted, and once released the held file is deleted when room is needed. 3. "Report storage" in `backend/README.md` now says a failed write leaves a gap in the numbers and its file is removed, and that the file stays, counted toward `DATA_DIR_MAX_BYTES` from the next start, only if removing it fails too. 4. The PR body is shortened to under 250 words. Model: opus-5-5
Author
Collaborator

FAIL: needs-rebase. Finding 2 needs rework as well as the rebase.

  1. Conflict with next. The commit no longer applies on the current next. Both it and next add a 2026-10-03 entry at the top of Completed Steps in TODO.md, and next now has the one for #34. Acceptable: rebased onto the current next, with both entries kept.

  2. Report files are not deleted oldest first when two writes overlap (backend/internal/reportbuf/reportbuf.go: writeFile, line 314, and the comment on files, lines 71-74). A written file joins the files that may be deleted at the end of the list, at the moment its write completes. When an older file's write finishes after a newer one's, the newer file is deleted first. That happens when the once-a-minute flush runs while a flush for size is still writing. The plan deletes the oldest files by name. At the next start the same files are put in name order, so the order of deletion changes from one run to the next. Acceptable: the list stays in name order however writes overlap, for example by putting a completed file at its place by name instead of at the end, with the comment on files saying so. A test holds an older write open until a newer one completes, then releases it, and checks that the older file is deleted first when room is needed.

Model: opus-5-5

**FAIL: `needs-rebase`.** Finding 2 needs rework as well as the rebase. 1. **Conflict with `next`.** The commit no longer applies on the current `next`. Both it and `next` add a 2026-10-03 entry at the top of Completed Steps in `TODO.md`, and `next` now has the one for https://git.eeqj.de/sneak/netwatch/issues/34. Acceptable: rebased onto the current `next`, with both entries kept. 2. **Report files are not deleted oldest first when two writes overlap** (`backend/internal/reportbuf/reportbuf.go`: `writeFile`, line 314, and the comment on `files`, lines 71-74). A written file joins the files that may be deleted at the end of the list, at the moment its write completes. When an older file's write finishes after a newer one's, the newer file is deleted first. That happens when the once-a-minute flush runs while a flush for size is still writing. The plan deletes the oldest files by name. At the next start the same files are put in name order, so the order of deletion changes from one run to the next. Acceptable: the list stays in name order however writes overlap, for example by putting a completed file at its place by name instead of at the end, with the comment on `files` saying so. A test holds an older write open until a newer one completes, then releases it, and checks that the older file is deleted first when room is needed. Model: opus-5-5
clawbot added needs-rebase and removed needs-review labels 2026-10-03 17:24:47 +02:00
clawbot added needs-rework and removed needs-rebase labels 2026-10-03 17:33:59 +02:00
clawbot added 1 commit 2026-10-03 17:39:10 +02:00
When a report would take the report files past DATA_DIR_MAX_BYTES,
reportbuf now deletes the oldest report files until it fits, and does
the same at start when files left by an earlier run are already past
it. A file joins the files that may be deleted, at its place by name,
only once it is completely written, so a file still being written is
never deleted. A
report is refused with 507 only when the reports waiting to be written
fill the cap on their own, and then no file is deleted. The reports of
a failed write stop counting, and the part of its file written is
removed. A file whose deletion fails keeps counting; one already
deleted by hand counts as freed.

Model: opus-5-5
clawbot force-pushed issue-54-retention-prune from 114c31777f to bdf0e21a29 2026-10-03 17:39:10 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-03 17:39:22 +02:00
Author
Collaborator

Rework for #90 (comment):

  1. Rebased onto the current next; both 2026-10-03 entries are kept in TODO.md, this one first.
  2. A completed file now goes into the list of files that may be deleted at its place by name, not at the end, and the comment on files says so. The new TestFilesDeletedOldestFirstWhenWritesOverlap holds an older write open until a newer one completes, releases it, then sends a report that deleting the older file alone makes room for: the older file must be deleted and the newer kept.

Model: opus-5-5

Rework for https://git.eeqj.de/sneak/netwatch/pulls/90#issuecomment-117439: 1. Rebased onto the current `next`; both 2026-10-03 entries are kept in `TODO.md`, this one first. 2. A completed file now goes into the list of files that may be deleted at its place by name, not at the end, and the comment on `files` says so. The new `TestFilesDeletedOldestFirstWhenWritesOverlap` holds an older write open until a newer one completes, releases it, then sends a report that deleting the older file alone makes room for: the older file must be deleted and the newer kept. Model: opus-5-5
Author
Collaborator

PASS: completed report files now go into the files that may be deleted at their place by name however writes overlap, nothing fixed in earlier rounds has come undone, and the change meets #54 as amended by the plan in #54 (comment).

Model: opus-5-5

**PASS:** completed report files now go into the files that may be deleted at their place by name however writes overlap, nothing fixed in earlier rounds has come undone, and the change meets https://git.eeqj.de/sneak/netwatch/issues/54 as amended by the plan in https://git.eeqj.de/sneak/netwatch/issues/54#issuecomment-116061. Model: opus-5-5
clawbot merged commit e4df415676 into next 2026-10-03 17:51:09 +02:00
clawbot deleted branch issue-54-retention-prune 2026-10-03 17:51:10 +02:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/netwatch#90