Skip to content

feat: add anonymous opt-out telemetry - #684

Open
jumski wants to merge 2 commits into
mainfrom
telemetry
Open

jumski wants to merge 2 commits into
mainfrom
telemetry

Conversation

@jumski

@jumski jumski commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Anonymous opt-out telemetry

Summary

Ships the researched daily anonymous telemetry (plan: Plans/2026-09-18-anonymous-telemetry.md, spec: Runs/anonymous-telemetry-research/research.md).

  • SQL collector — new pgflow_telemetry schema: sent_reports audit/dedup table, bucket helpers, build_payload() covering all 26 metrics, preview() (never sends), report() with gates (inactive day → already reported → local), one pg_net attempt with 5 s timeout, no retries, and enable()/disable() where the cron.job row is the switch. The Atlas migration schedules the daily job exactly once; later migrations never re-schedule it.
  • Version stampingpgflow.workers.pgflow_version column; edge workers stamp their package version at registration (Deno/JSR-compatible JSON import, vendored for e2e).
  • Cloudflare ingest workerapps/telemetry-worker: strict allowlist validation (metric names, bucket strings, semver), one Analytics Engine data point per contribution, no cookies, no body logging, 2 KB / 64-contribution caps.
  • Privacy — payloads contain only allowlisted metric names, bucket strings, semver versions, and count buckets. Never slugs, names, IDs, hosts, URLs, inputs, outputs, errors, IPs, or free text. Every sent payload stays auditable in pgflow_telemetry.sent_reports; preview() shows any day's exact bytes; local dev stacks never send.
  • Docs & release — new /reference/telemetry/ page, sidebar + reference card + redirect for the renamed news article (combined 0.17.1), changeset (@pgflow/core, @pgflow/edge-worker: patch).

Deferred (manual follow-up, not in this PR): wrangler deploy of the ingest worker and the live endpoint smoke test. The SQL endpoint constant is https://pgflow-telemetry.workers.dev; if the deployed subdomain differs, it needs a follow-up change per the plan's Task 8 Step 5.

Checks

  • 4 new pgTAP files (red/green cycles; migration replay with dependencies): telemetry/{workers_version,schema,payload,report}.test.sql
  • Full pgTAP suite: 314 files, 1606 tests — pass (one pre-existing timing-flaky perf test passes standalone)
  • nx affected -t build test — pass, except demo:test: 4 Groq-API tests fail only when a GROQ_API_KEY is present in the environment (model llama-3.1-8b-instant decommissioned); demo sources untouched by this PR and CI has no such key
  • telemetry-worker: 10 vitest tests + typecheck — pass
  • edge-worker: build + 265 tests, JSR publish dry-run, e2e 13/13 — pass
  • Migration verification: verify-migrations, gen-types, verify-gen-types — pass
  • Live local round-trip: preview() shows real contributions; report() returns skipped: local, zero audit rows; worker registration stamps pgflow_version = 0.17.0
  • Website build with link validator and redirect check — pass
  • Lint on all touched packages — pass

A daily pg_cron job (pgflow_telemetry.report) aggregates yesterday's pgflow.* activity into coarse, identifier-free buckets (active-day, worker versions, run/worker counts, flow shapes, feature adoption, durations) and posts one small JSON payload via pg_net to a Cloudflare Worker backed by Workers Analytics Engine. Edge workers stamp their package version into pgflow.workers at registration.

Design decisions: the cron.job row is the only switch — the migration schedules it exactly once and nothing re-schedules it, so disable() stays permanent across upgrades. pgflow_telemetry.sent_reports doubles as user-auditable payload log and per-day dedup marker. report() gates run in order: inactive day, already reported, is_local(); one pg_net attempt, 5s statement timeout, no retries, no response inspection. Metric names, bucket strings, and count buckets are closed allowlists identical across SQL (0133), the ingest worker (apps/telemetry-worker), and docs; anything else never leaves the database. Local supabase-start stacks never send.

Compatibility fixes found during implementation: Deno 2.1.4 requires the JSON import attribute ('with { type: json }') and a default import for package.json version lookup, so jsr.json publish.includes package.json and the e2e vendor script copies it; bucket_steps takes bigint because steps_per_flow passes count(*); 0136 uses $disable$/$enable$ dollar-quote tags because the plan's nested $$ would terminate enable()'s body early. Plan test bugs corrected with rationale in the tests: 90s lands in 1-4.9m not 1-9.9s; bucket_count(2) is '2-3'; the 65-contribution body always exceeds the 2KB cap so 413 fires before the count guard.

Verification: 4 new pgTAP files (red/green, migration replay with deps), telemetry-worker vitest 10, full pgTAP suite 314 files/1606 tests, nx affected build+test, e2e 13/13, live report() returns skipped: local with zero audit rows, live worker registration stamps 0.17.0, website build. Ingest worker deployment (wrangler deploy + smoke) is a manual follow-up and is not part of this commit.
@changeset-bot

changeset-bot Bot commented Sep 18, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4d10e7f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 5 packages
Name Type
@pgflow/core Patch
@pgflow/edge-worker Patch
pgflow Patch
@pgflow/client Patch
@pgflow/dsl Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@nx-cloud

nx-cloud Bot commented Sep 18, 2026

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit 4f7f279

Command Status Duration Result
nx run-many -t build --projects=dsl,core,cli ✅ Succeeded 6s View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-09-18 15:52:40 UTC

CI build-and-test failed on @pgflow/telemetry-worker:typecheck with TS5069: the @nx/js plugin infers 'tsc --build --emitDeclarationOnly' for every root-tsconfig project, but this wrangler-deployed worker's tsconfig sets noEmit and never emits declarations. A package.json 'typecheck' script overrides the inferred target with tsc --noEmit — the same per-project override pattern pkgs/client uses (project.json noEmit target) instead of touching nx.json.

Verified: focused typecheck exit=0; nx affected -t lint typecheck test green except the known unrelated demo Groq tests (sandbox GROQ_API_KEY, decommissioned llama-3.1-8b-instant).
Comment on lines +120 to +126
for (const c of contributions) {
env.PGFLOW_TELEMETRY.writeDataPoint({
indexes: [c.metric as string],
blobs: [c.bucket as string],
doubles: [1],
});
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The count field from contributions is validated (lines 113-117) but never used when writing data points. All contributions are written with doubles: [1] regardless of their actual count value. This means aggregated count data (like "count": "8-15") is completely lost.

Fix:

for (const c of contributions) {
  env.PGFLOW_TELEMETRY.writeDataPoint({
    indexes: [c.metric as string],
    blobs: [c.bucket as string, c.count as string ?? ''],
    doubles: [1],
  });
}

Or if count should affect the double value, the SQL queries building these payloads (like line 27 in 0133_function_build_telemetry_payload.sql) would need to be updated to not include the count field at all since it cannot be meaningfully transmitted in the current schema.

Suggested change
for (const c of contributions) {
env.PGFLOW_TELEMETRY.writeDataPoint({
indexes: [c.metric as string],
blobs: [c.bucket as string],
doubles: [1],
});
}
for (const c of contributions) {
env.PGFLOW_TELEMETRY.writeDataPoint({
indexes: [c.metric as string],
blobs: [c.bucket as string, c.count as string ?? ''],
doubles: [1],
});
}

Spotted by Graphite

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

@github-actions

Copy link
Copy Markdown
Contributor

🔍 Preview Deployment: Website

Deployment successful!

🔗 Preview URL: https://pr-684.pgflow.pages.dev

📝 Details:

  • Branch: telemetry
  • Commit: 10e1ad7b4163c40b5cfc13e43448bde33d7ac1c4
  • View Logs

_Last updated: _

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.

1 participant