Skip to content

Two-level opt-in

Nothing is collected until two separate decisions have both been made, by two different people. Removing either one stops collection entirely.

The author's decision is a dependency

The first level is compile-time. A tool collects usage data only if its author added rtb-telemetry to Cargo.toml and wrote the record calls. There is no ambient collection, no framework hook that starts reporting because a crate happened to be in the tree, and no way for this crate to be switched on from outside the program that links it.

This matters most for the absence case. A tool that never depends on the crate has no telemetry code in its binary at all — not disabled telemetry, not dormant telemetry. There is nothing to audit, because there is nothing there.

The user's decision is the policy

The second level is runtime. Collection happens only when the context is built with CollectionPolicy::Enabled. The default is Disabled, and Disabled is not a filter applied late: record returns Ok(()) before constructing an event, before reading the attribute map, and before touching the sink. Building a Disabled context does not even derive the machine ID, so a user who has not opted in never has their host read.

The mapping from a stored decision to that policy is deliberately blunt. ConsentState::Enabled becomes Enabled; both Disabled and Unset become Disabled. There is no "ask me later" state that leaks into collecting.

Why the default is off and not "off unless configured"

An opt-out has to be discovered before it can be used, which means the data of everyone who did not discover it has already been collected. The design here treats consent as something given rather than something assumed and grudgingly reversed, so the default has to be the state that collects nothing.

The practical version of that principle is the Default impl on CollectionPolicy. A tool that forgets to wire consent up gets Disabled, because the failure mode of forgetting must be "no data", never "all the data".

Why the two levels are not one

They answer different questions and belong to different people. The author decides whether the capability exists in this binary at all; the user decides whether it runs for them. Collapsing them would mean either a user can turn on collection the author never implemented, or an author can implement collection the user cannot refuse. Neither is a thing this crate will do.

Where the decision is stored

The crate persists the user's decision through the consent module, and the tool decides where that file lives and when to ask. What the crate provides is the record and the mapping; the prompt, the CLI commands and the file path are the tool's own.