Skip to content

fix(#50): enforce telemetry retention automatically, report footprint, drop fixed /tmp backup path - #127

Merged
bigknoxy merged 1 commit into
mainfrom
fix/50-telemetry-retention
Aug 19, 2026
Merged

fix(#50): enforce telemetry retention automatically, report footprint, drop fixed /tmp backup path#127
bigknoxy merged 1 commit into
mainfrom
fix/50-telemetry-retention

Conversation

@bigknoxy

Copy link
Copy Markdown
Owner

Closes #50.

1. Retention was never enforced

pruneEvents existed but was reachable only through the manual telemetry prune command, so retentionDays was 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.

recordEvent now sweeps rotated logs past retentionDays and 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-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 runs, so a prune that throws does not become a hot loop over the log — losing a day of retention beats that.

(maxFileSize was already enforced automatically via maybeRotate(); retention was the gap.)

2. Footprint was invisible

diskUsage() totals the active log, every rotated log, and the payload store. telemetry health reports it as diskBytes and warns past 100 MB; doctor gains a telemetry-size check — a warn, never a fail, because a large log is not a broken install. diskBytes is a point-in-time property, so on --trend output it is populated on current and always 0 on previous.

3. Backup written to a fixed world-writable path

install.sh copied 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 uses mktemp -d "$TARGET_DIR/.telemetry-backup.XXXXXX", chmod 700 on the directory and 600 on 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, configured retentionDays: 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, diskBytes covering payloads, the doctor check, and static assertions on install.sh.
  • Falsification: removing the maybeAutoPrune() call fails 3 tests.
  • Full suite 875 pass / 0 fail; bun run lint:docs clean; bash -n and shellcheck clean on install.sh.
  • No bench case: retention and install-script defects are outside the bench harness's edit-correctness model.

Contract: docs/ADAPTER-CONTRACT.md documents the new diskBytes field and threshold. README and ARCHITECTURE updated.

🤖 Generated with Claude Code

…, 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
bigknoxy force-pushed the fix/50-telemetry-retention branch from af9bdbf to 6f059a5 Compare August 19, 2026 19:33
@bigknoxy
bigknoxy merged commit 34ad3cf into main Aug 19, 2026
4 checks passed
@bigknoxy
bigknoxy deleted the fix/50-telemetry-retention branch August 19, 2026 19:34
bigknoxy pushed a commit that referenced this pull request Aug 19, 2026
## [4.4.16](v4.4.15...v4.4.16) (2026-08-19)

### Bug Fixes

* **#50:** enforce telemetry retention automatically, report footprint, drop fixed /tmp backup path ([#127](#127)) ([34ad3cf](34ad3cf)), closes [#51](#51)
@bigknoxy

Copy link
Copy Markdown
Owner Author

🎉 This PR is included in version 4.4.16 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P3] Telemetry retention never auto-enforced; backup written to a fixed /tmp path

1 participant