Skip to content

feat: Flush telemetry events to remote ingest endpoint#283

Merged
stack72 merged 1 commit into
mainfrom
feat/telemetry-flush
Feb 11, 2026
Merged

feat: Flush telemetry events to remote ingest endpoint#283
stack72 merged 1 commit into
mainfrom
feat/telemetry-flush

Conversation

@johnrwatson
Copy link
Copy Markdown
Contributor

Summary

Closes #282

  • Flush up to 25 telemetry events per CLI invocation to a remote /ingest endpoint (default: https://telemetry.swamp.club)
  • Events are deleted after successful flush by default; set telemetryKeepFlushed: true in .swamp.yaml to rename to .flushed.json instead
  • Auto-generates a repoId UUID in .swamp.yaml on swamp init (lazy-migrated for existing repos), sent as distinct_id on every event
  • Telemetry endpoint configurable via telemetryEndpoint in .swamp.yaml
  • Fire-and-forget: flush failures never break CLI commands (visible via --log-level debug)
  • New TelemetrySender domain port with HttpTelemetrySender infrastructure adapter (5s timeout)

Test Plan

  • 32 new/updated unit tests covering findUnflushed, markFlushed (delete + keep modes), HttpTelemetrySender, and flushTelemetry service method
  • Full test suite: 1746 tests passing
  • Manually verified against production telemetry server (telemetry-app-production.up.railway.app) — events arriving with correct distinct_id and properties

🤖 Generated with Claude Code

Add telemetry flush system that sends up to 25 events per CLI invocation
to a configurable remote endpoint. Events are deleted after successful
flush by default; set telemetryKeepFlushed: true in .swamp.yaml to
rename to .flushed.json instead. Repo UUID (repoId) is auto-generated
on init and lazy-migrated for existing repos.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@johnrwatson johnrwatson marked this pull request as draft February 11, 2026 21:06
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review: Flush telemetry events to remote ingest endpoint

This PR adds a telemetry flush system that sends CLI invocation events to a remote endpoint. The implementation follows domain-driven design principles well and includes comprehensive test coverage.

Summary

No blocking issues found. The code is well-structured, follows the project's conventions, and has good test coverage.


Code Quality Assessment

TypeScript Strict Mode Compliance: ✅

  • No any types used
  • All parameters and return types are properly typed
  • Uses readonly appropriately for immutable fields

Named Exports: ✅

  • All exports are named exports, no default exports
  • Module barrel (mod.ts) properly re-exports new types

Domain-Driven Design: ✅

  • TelemetrySender is correctly modeled as a domain port (interface) in src/domain/telemetry/
  • HttpTelemetrySender is correctly placed in infrastructure as an adapter
  • TelemetryRepository interface is properly extended with findUnflushed and markFlushed methods
  • TelemetryService orchestrates the flushing logic appropriately as a domain service
  • Follows the ports-and-adapters pattern correctly

Test Coverage: ✅

  • 32 new/updated tests covering:
    • TelemetryService.flushTelemetry (3 tests)
    • JsonTelemetryRepository.findUnflushed (4 tests)
    • JsonTelemetryRepository.markFlushed (4 tests)
    • HttpTelemetrySender.sendBatch (4 tests)
  • Tests verify edge cases: empty results, network errors, non-202 responses, file not found

Security: ✅

  • Uses 5-second timeout on HTTP requests to prevent hanging
  • Fire-and-forget pattern prevents telemetry from blocking CLI execution
  • Response body is properly consumed to prevent resource leaks
  • No sensitive data appears to be transmitted (arguments are already redacted elsewhere)

Suggestions (non-blocking)

  1. Documentation suggestion: Consider adding a note to the README or design docs about the telemetry endpoint configuration options (telemetryEndpoint, telemetryKeepFlushed in .swamp.yaml).

  2. Minor inconsistency: The deleteOlderThan method uses entry.name.endsWith(".json") which will match both .json and .flushed.json files - this is actually correct behavior for cleanup, but the test at line 439-479 (deleteOlderThan cleans up both flushed and unflushed files) documents this well.

  3. Consideration for future: The HttpTelemetrySender sends a single event vs batch format based on array length. While this works correctly, documenting why this optimization exists (API compatibility?) might help future maintainers.


Files Reviewed

File Assessment
src/cli/mod.ts ✅ Clean integration with telemetry flush
src/domain/telemetry/mod.ts ✅ Proper exports added
src/domain/telemetry/repositories.ts ✅ Well-documented interface methods
src/domain/telemetry/telemetry_sender.ts ✅ Clean port interface
src/domain/telemetry/telemetry_service.ts ✅ Fire-and-forget with proper error handling
src/domain/telemetry/telemetry_service_test.ts ✅ Comprehensive tests
src/infrastructure/persistence/json_telemetry_repository.ts ✅ Robust file handling
src/infrastructure/persistence/json_telemetry_repository_test.ts ✅ Thorough test coverage
src/infrastructure/persistence/repo_marker_repository.ts ✅ New fields for telemetry config
src/infrastructure/telemetry/http_telemetry_sender.ts ✅ Clean adapter implementation
src/infrastructure/telemetry/http_telemetry_sender_test.ts ✅ Tests with real HTTP server

LGTM! 🚀

@johnrwatson johnrwatson marked this pull request as ready for review February 11, 2026 21:19
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review: Telemetry Flush Feature

Verdict: APPROVED

This PR implements a well-designed telemetry flush system that follows good DDD principles and adheres to the project's code standards.

Code Quality ✅

  • TypeScript strict mode: All types explicitly defined, no any types
  • Named exports used throughout (no default exports)
  • Code passes deno check and deno lint

Domain-Driven Design ✅

The architecture correctly follows DDD patterns:

  • TelemetrySender is a proper domain port (interface) in src/domain/telemetry/
  • HttpTelemetrySender is an infrastructure adapter implementing the port
  • TelemetryRepository extension with findUnflushed/markFlushed is appropriate
  • TelemetryService.flushTelemetry() is a proper domain service method orchestrating the operation

Test Coverage ✅

Comprehensive tests added:

  • telemetry_service_test.ts: 3 tests for flush success, failure, no-op
  • json_telemetry_repository_test.ts: 7 tests for findUnflushed, markFlushed, cleanup
  • http_telemetry_sender_test.ts: 4 tests for single/batch sends, error handling

Security ✅

  • Fire-and-forget pattern prevents telemetry from blocking CLI
  • 5-second timeout on HTTP requests prevents hanging
  • Error handling suppresses exceptions appropriately
  • repoId UUID provides anonymity (no PII sent)
  • Telemetry endpoint is user-configurable

Suggestions (non-blocking)

  1. Sequential markFlushed: The doFlush method marks entries flushed sequentially. Using Promise.all could improve throughput for the 25-entry batch, but sequential is safer for file operations and this is fire-and-forget anyway.

  2. Pre-existing: findByDate includes flushed files: The existing findByDate method doesn't exclude .flushed.json files, which could affect findByDateRange results. This is pre-existing behavior, not introduced by this PR.

Overall this is clean, well-tested code that follows the project's architectural patterns.

@stack72 stack72 merged commit 8e12330 into main Feb 11, 2026
6 of 7 checks passed
@stack72 stack72 deleted the feat/telemetry-flush branch February 11, 2026 21:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Flush telemetry events to remote ingest endpoint

2 participants