fix(#50): enforce telemetry retention automatically, report footprint, drop fixed /tmp backup path - #127
Merged
Merged
Conversation
…, drop fixed /tmp backup path `pruneEvents` was reachable only through the manual `telemetry prune` command, so `retentionDays` was configuration nobody's store obeyed and an active user's log grew unbounded in `$HOME` forever — nobody runs the command because nobody knows the file is growing. - `recordEvent` now sweeps rotated logs past `retentionDays` and collects orphaned diff payloads. The prune reads every event (payload GC needs the full reference set), so it cannot run per write: a `.last-prune` marker gates it to once a day and the cost on every other invocation is a single `statSync`. The marker is touched before the prune, so a prune that throws does not turn into a hot loop over the log. - `diskUsage()` totals the active log, rotated logs, and the payload store. `telemetry health` reports it as `diskBytes` and warns past 100 MB; `doctor` gains a `telemetry-size` check (warn, never fail — a large log is not a broken install). `diskBytes` is point-in-time, so on `--trend` it is populated on `current` and always 0 on `previous`. - `install.sh` no longer copies the log — which can contain source diffs — to a fixed `/tmp/hashpilot-telemetry-backup`. A predictable path in a world-writable directory is readable by any local user and a symlink-attack target. It now uses `mktemp -d` under the install root, chmod 700, with the copy chmod 600. Also types `sessionId` as `string` so `setSessionId` (#51) assigns cleanly against the UUID template type. tests/telemetry-retention-50.test.ts adds 9 tests, including a configured-retentionDays case, a marker-gating case, a latency assertion on the already-pruned path with a 20k-line log, and static assertions that no fixed `/tmp` path remains in `scripts/`. Falsification: removing the `maybeAutoPrune()` call fails 3. Suite: 875 pass. Docs: ADAPTER-CONTRACT gains `diskBytes` and the new threshold; README and ARCHITECTURE document automatic retention. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bigknoxy
force-pushed
the
fix/50-telemetry-retention
branch
from
August 19, 2026 19:33
af9bdbf to
6f059a5
Compare
Owner
Author
|
🎉 This PR is included in version 4.4.16 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #50.
1. Retention was never enforced
pruneEventsexisted but was reachable only through the manualtelemetry prunecommand, soretentionDayswas configuration nobody's store obeyed. Steady-state growth for an active user is unbounded, in$HOME, forever — and nobody runs the command because nobody knows the file is growing.recordEventnow sweeps rotated logs pastretentionDaysand collects orphaned diff payloads in the same pass. The prune reads every event (payload GC needs the full reference set), so it cannot run per write: a.last-prunemarker gates it to once a day, and the cost on every other invocation is a singlestatSync. The marker is touched before the prune runs, so a prune that throws does not become a hot loop over the log — losing a day of retention beats that.(
maxFileSizewas already enforced automatically viamaybeRotate(); retention was the gap.)2. Footprint was invisible
diskUsage()totals the active log, every rotated log, and the payload store.telemetry healthreports it asdiskBytesand warns past 100 MB;doctorgains atelemetry-sizecheck — a warn, never a fail, because a large log is not a broken install.diskBytesis a point-in-time property, so on--trendoutput it is populated oncurrentand always0onprevious.3. Backup written to a fixed world-writable path
install.shcopied the log — which can contain source diffs — to/tmp/hashpilot-telemetry-backup. A fixed path in a world-writable directory is readable by any local user and a symlink-attack target. It now usesmktemp -d "$TARGET_DIR/.telemetry-backup.XXXXXX",chmod 700on the directory and600on the copy, with the restore leg reading the same variable.rg '/tmp/' scripts/is now empty and a test asserts it stays that way.Verification
tests/telemetry-retention-50.test.ts— 9 tests: default-retention prune, configuredretentionDays: 5, marker gating (no re-prune inside the interval, re-prunes once aged), a latency assertion on the already-pruned path against a 20,000-line log,diskBytescovering payloads, thedoctorcheck, and static assertions oninstall.sh.maybeAutoPrune()call fails 3 tests.bun run lint:docsclean;bash -nand shellcheck clean oninstall.sh.Contract:
docs/ADAPTER-CONTRACT.mddocuments the newdiskBytesfield and threshold. README and ARCHITECTURE updated.🤖 Generated with Claude Code