HarperFast / HarperFast/harper
read_log SSE tail: rotation detection via file size is a narrow race vs. inode identity
- Dominant language
- JavaScript
- Stars
- 89
- Forks
- 10
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 200
Description
## Context
Raised during review of #1693 (`feat(logs): stream read_log over SSE as a live tail`): https://github.com/HarperFast/harper/pull/1693
## Issue
The live log tail's rotation detection uses raw file size (`if (size < offset)`) rather than inode identity to detect that the underlying log file has been rotated/replaced:
```ts
if (size < offset) {
// assume rotation: file shrank, so it must be a new file
...
}
```
This is correct for the common case (a rotated file starts small and grows), but has a narrow failure mode: if a brand-new file happens to already exceed the old file's `offset` before the next `stat()` poll catches the rotation, the size-based check won't fire and the tail could misread across the rotation boundary.
Reviewers (both Claude and Gemini across separate passes) agree the practical trigger window is narrow — it requires an implausible write rate for the replacement file specifically within one poll interval — so this wasn't treated as blocking for #1693. Filing as a tracked fast-follow rather than losing it.
## Suggested fix
Track the file's inode (`fs.Stats.ino`) alongside size/offset, and treat an inode change as the authoritative rotation signal instead of (or in addition to) the size-decrease heuristic.
Contributor guide
Research direction
Start at the read_log SSE live-tail implementation and trace how the current size and offset values are recorded between stat polls. Update the rotation check to account for fs.Stats.ino, then verify that a replacement file is treated as a new stream even when its size already exceeds the previous offset.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- nodejs, typescript
- Domain
- observability
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 64/100