Step 6 of the on-by-default telemetry rollout — the server-side half. The API now actually emits the events documented at ferrlabs.com/telemetry instead of only persisting envelopes from external POSTs.

Wiring. api/src/telemetry_emit.rs owns the Emitter (BLAKE3-keyed Hasher loaded from FERRLABS_TELEMETRY_SALT at startup, ephemeral fallback in dev with a loud warn). Two helpers, spawn_emit_org and spawn_emit_user, fire-and-forget through tokio::spawn — they check the relevant opt-out (organizations.telemetry_opt_out for org events, user_prefs.telemetry_opt_out for user events) before writing into telemetry_events. Emit failures tracing::warn! and never propagate — telemetry is never the reason a request fails.

Wired call sites.

Surface Event Properties
POST /v1/orgs org.created (org_hash + actor user_hash)
POST /v1/orgs/{slug}/members org.member.added role
POST /v1/orgs/{slug}/subscriptions product.activated product, tier
PATCH /v1/orgs/{slug}/subscriptions/{product} product.tier_changed product, tier_to (when tier changes)
DELETE /v1/orgs/{slug}/subscriptions/{product} product.canceled product
POST /auth/login auth.login method (currently always password)
POST /auth/verify-email auth.signup method (account becomes active)

OAuth login methods will populate method=oauth-google / oauth-github / sso once those flows ship.

Hash stability. FERRLABS_TELEMETRY_SALT is a 64-char hex (32 bytes) loaded from a sealed K8s secret in prod. Rotating it invalidates correlation across the rotation boundary by design — same intent as the 90-day raw retention on telemetry_events.

Wording flip is next. Step 7 (drop the draft banner from /telemetry, switch principle №04 + hero stat №03 to "Telemetry, but transparent" / "OPEN TELEMETRY") will land as soon as the events are visibly arriving in DB on a preview cluster.