The sweep in aa770aa6 deliberately left this page alone, reasoning that
hashing the email is materially different from sending it. Reading
integrations/openclaw/telemetry.ts does not support that: distinctId() is an
unsalted sha256 of the account email, and Mem0 holds the emails it is derived
from, so recovering the account is a table join. resolveEmail() also rewrites
already-queued events onto that id, and identifyAnonymous() fires a PostHog
$identify that merges the prior random id into it for good.
That is pseudonymous, not anonymous, and it is the same mismatch between the
stated privacy posture and the wire format that this stack exists to close.
The opt-out is unchanged and still correct.
Claude-Session: https://claude.ai/code/session_01C7tEmH86HAr7GoAAKCEHZb
The first pass fixed the plugin README and the module docstring but left the
same claim standing everywhere else.
- docs/integrations/deepseek-plugin.mdx still said "Anonymous usage events".
The TS SDK's telemetryId is the raw account email, so it is not anonymous.
- The pause skill told users a "minimal anonymous telemetry ping" fires while
paused. Same ping, same email. Corrected in the template, which regenerates
into all six hosts.
- integrations/zapier-mem0/README.md advertised telemetry the app does not have:
there is no telemetry code in it at all. It now says what is actually true,
that its requests carry source="ZAPIER".
- The data directory listing is presented as exhaustive and had gone stale
against this stack's two new files, telemetry-salt and install-state.json.
Also replaced the property enumeration in both the README and the docs page.
Review pointed out it omitted the configured model name among others — writing
a fresh exhaustive list in a PR whose whole purpose is making docs match code
reproduces the defect being fixed. It now describes the shape and points at
where the rule is actually enforced, so it cannot drift again.
Deliberately unchanged: docs/integrations/openclaw.mdx. OpenClaw hashes the
email rather than sending it, which is materially different from the plugin and
the SDK, so its claim is not wrong in the same way.
Claude-Session: https://claude.ai/code/session_01C7tEmH86HAr7GoAAKCEHZb
The plugin README promises "anonymous usage events" and the telemetry module's
docstring says it sends only "salted hashes". Neither is true.
resolve_distinct_id() exchanges the API key for the account email and sends that
as the distinct_id on every event. Installing the plugin requires an API key, so
this is nearly every user. That is probably the behaviour we want — the Python
SDK and the CLI attribute the same way — but the description has to match it.
repo_hash and session_hash were unsalted SHA-256 cut to 16 hex characters.
repo.identity is a git remote URL, or `local:<absolute path>` when there is no
remote, which normally contains the account username. Sixteen unsalted hex
characters over that input space is enumerable, so the hash was not a privacy
control at all.
Salted per install, with the salt kept in the identity file. That preserves
every within-account join the analytics actually use and gives up only
cross-machine joins on the same repository, which nothing computes. Since the
distinct_id is already the email, the hash was never buying privacy from us —
only from whoever obtains the data later, which is exactly what the salt fixes.
Also corrects deepseek-plugin's README and source comment, which told readers
ZAPIER and STRANDS were already in the backend's KNOWN_EVENT_SOURCES allowlist.
Neither was.
Adds a Telemetry section to docs/integrations/claude-code.mdx, which had none.
Claude-Session: https://claude.ai/code/session_01C7tEmH86HAr7GoAAKCEHZb