Add shared PostHog telemetry reporter#10
Conversation
Several Kenn daemons need the same anonymous PostHog telemetry behavior, but keeping separate internal implementations makes it easy for privacy defaults, opt-out handling, and event allowlists to drift between apps. This adds a shared reporter that requires callers to provide their own PostHog project key, anonymous distinct ID, env prefix, and allowed events. The reusable package owns the sanitization and privacy defaults while callers keep app-specific keys and event semantics outside kit. The option-based event allowlist keeps the public API usable without exposing the internal map representation, and the build-tag/process disable hook preserves the existing test-binary exclusion pattern for daemon integrations. Validation: go test ./telemetry; go test -tags kit_posthog_disabled ./telemetry; golangci-lint run; go run ./cmd/testify-helper-check ./...; go tool nilaway -include-pkgs=go.kenn.io/kit ./...; go tool gotestsum --format pkgname-and-test-fails -- ./... 🤖 Generated with [OpenAI Codex](https://openai.com/codex) Co-authored-by: OpenAI Codex <noreply@openai.com>
roborev: Combined Review (
|
The option-based PostHog API allows callers to register events whose payload is only the shared default metadata. Dropping those events during allowlist cloning made that API contract inconsistent and caused construction or capture to fail for valid default-properties-only daemon events. Preserving empty property maps keeps event authorization separate from property authorization, while the regression test proves unallowlisted submitted properties are still stripped from such events. Validation: go test ./telemetry; go test -tags kit_posthog_disabled ./telemetry; golangci-lint run; go run ./cmd/testify-helper-check ./...; go tool gotestsum --format pkgname-and-test-fails -- ./...; go tool nilaway -include-pkgs=go.kenn.io/kit ./... 🤖 Generated with [OpenAI Codex](https://openai.com/codex) Co-authored-by: OpenAI Codex <noreply@openai.com>
roborev: Combined Review (
|
DisablePostHogTelemetry is a process-wide switch, so callers should not need to recreate already-initialized reporters for it to take effect. The previous implementation only consulted that switch while constructing reporters, leaving long-running daemons able to enqueue after a build-tag or runtime disable path fired. This makes submission eligibility check the process disable state on every capture while keeping Close tied to the underlying client state so existing clients can still flush or release resources. Validation: go test ./telemetry; go test -tags kit_posthog_disabled ./telemetry; golangci-lint run; go run ./cmd/testify-helper-check ./...; go tool nilaway -include-pkgs=go.kenn.io/kit ./...; go tool gotestsum --format pkgname-and-test-fails -- ./... 🤖 Generated with [OpenAI Codex](https://openai.com/codex) Co-authored-by: OpenAI Codex <noreply@openai.com>
roborev: Combined Review (
|
The process-level telemetry disable path should stop outbound telemetry altogether, including buffered events that might otherwise be flushed during reporter shutdown. This keeps Close aligned with Enabled so disabling telemetry after reporter creation prevents both new captures and shutdown flushes. Validation: go test ./telemetry; go test -tags kit_posthog_disabled ./telemetry; golangci-lint run; go run ./cmd/testify-helper-check ./...; go tool nilaway -include-pkgs=go.kenn.io/kit ./...; go tool gotestsum --format pkgname-and-test-fails -- ./... 🤖 Generated with [OpenAI Codex](https://openai.com/codex) Co-authored-by: OpenAI Codex <noreply@openai.com>
roborev: Combined Review (
|
PostHog Close is the only available client shutdown path, but it drains queued messages. Skipping Close avoided a flush but left the async client alive, while calling Close without a guard could send after process-level telemetry disable. This installs a transport guard in the shared reporter so queued flush attempts after DisablePostHogTelemetry fail before network I/O, allowing Close to release the client without submitting disabled telemetry. Validation: go test ./telemetry; go test -tags kit_posthog_disabled ./telemetry; golangci-lint run; go run ./cmd/testify-helper-check ./...; go tool nilaway -include-pkgs=go.kenn.io/kit ./...; go tool gotestsum --format pkgname-and-test-fails -- ./... 🤖 Generated with [OpenAI Codex](https://openai.com/codex) Co-authored-by: OpenAI Codex <noreply@openai.com>
roborev: Combined Review (
|
Process-level telemetry disable is a stronger guarantee than graceful delivery. Once DisablePostHogTelemetry has been called, reporter shutdown should not ask the PostHog SDK to drain a queue that may contain pre-disable events. Close now deactivates the shared wrapper locally when telemetry is disabled, so callers can still use Close as their shutdown hook without triggering a final flush. The regression test covers the queued-before-disable case called out by review. Validation: go test ./telemetry; go test -tags kit_posthog_disabled ./telemetry; golangci-lint run; go run ./cmd/testify-helper-check ./...; go tool nilaway -include-pkgs=go.kenn.io/kit ./...; go tool gotestsum --format pkgname-and-test-fails -- ./... Generated with OpenAI Codex Co-authored-by: OpenAI Codex <noreply@openai.com>
roborev: Combined Review (
|
The reporter lifecycle can be touched by daemon activity and shutdown paths at the same time. After Close started deactivating the wrapper, Capture needed to share the same synchronization boundary so it cannot enqueue through a client that Close is concurrently clearing. The mutex keeps Enabled, Capture, and Close consistent while preserving the process-disable guarantee that Close does not flush queued telemetry after DisablePostHogTelemetry. The regression test forces Capture and Close to overlap and verifies Close waits for the in-flight enqueue. Validation: go test ./telemetry; go test -race ./telemetry; go test -tags kit_posthog_disabled ./telemetry; golangci-lint run; go run ./cmd/testify-helper-check ./...; go tool nilaway -include-pkgs=go.kenn.io/kit ./...; go tool gotestsum --format pkgname-and-test-fails -- ./... Generated with OpenAI Codex Co-authored-by: OpenAI Codex <noreply@openai.com>
roborev: Combined Review (
|
Process-level telemetry disable should not choose between leaking the SDK client and sending queued telemetry during shutdown. The reporter can close the SDK safely by routing disabled HTTP attempts to a local 204 response, which lets the SDK drain and stop without network I/O. The string property helper also now requires an explicit allowed-value set. That keeps the shared API from treating arbitrary token-shaped user data, such as slugs or names, as anonymous telemetry by default. Validation: go test ./telemetry; go test -race ./telemetry; go test -tags kit_posthog_disabled ./telemetry; golangci-lint run; go run ./cmd/testify-helper-check ./...; go tool nilaway -include-pkgs=go.kenn.io/kit ./...; go tool gotestsum --format pkgname-and-test-fails -- ./... Generated with OpenAI Codex Co-authored-by: OpenAI Codex <noreply@openai.com>
roborev: Combined Review (
|
Summary
Validation