cratefield-module-telemetry 0.3.0

Cratefield module: counted aggregate usage telemetry with a consent model built in — pseudonymous, with no stored link to a person
Documentation

cratefield-module-telemetry

Aggregate usage telemetry for a Cratefield venture: clients report batches of counted events to POST /v1/telemetry/events, every field is validated against a closed grammar — an unknown field or an undeclared value is a rejection, never a truncation — and the counts accumulate into buckets in the venture's own database. No third-party analytics service, no vendor SDK, and no field anywhere a sentence could fit.

use cratefield_module_telemetry::Telemetry;

let module = Telemetry::new()
    .events(["run", "report", "upgrade"])
    .modules(["telemetry", "waitlist"])
    .retention_days(180)
    .max_events_per_batch(64)
    .opt_out_command("fz telemetry off")
    .status_command("fz telemetry status");

Both vocabularies default to empty, which fails closed: a venture that forgets to declare them runs a collector that rejects every batch naming an event or a module, not one that counts anything it is sent.

Consent ships as a model, not as wiring: consent::decide is the pure decision over the local opt-out, DO_NOT_TRACK and CI; consent::notice generates the first-run text from the payload schema, so it cannot promise less or more than the parser enforces; consent::status renders the exact bytes a sender would POST; and a rotation predicate bounds the install id to 30 days. The crate performs none of the doing — it does not read the environment in production, print the notice, persist an opt-out switch, provide the fz telemetry off and fz telemetry status commands, hold a pending batch, or send anything (it never opens a connection). That half belongs to the client, which must wire the primitives so reporting is off with no network and off before the next batch. The install id is 16 random bytes the caller supplies, never derived from anything about the machine — pseudonymous, with no stored link to a person.

Routes: POST /v1/telemetry/events (public, unauthenticated — the caller is a CLI; the guards are the RateLimiter port, the batch ceiling and the closed grammar), GET /v1/telemetry/notice (the machine-readable consent notice, unauthenticated like the privacy manifest), and GET /v1/telemetry/admin/usage (admin-guarded aggregate rows; the GROUP BY is the privacy control, so no per-install row exists to leak).

What is never sent: identifiers or addresses, paths, repository or branch names, prompts, model output, commit or issue text — free text of any kind. Rejection bodies never echo what the client sent.

Emits telemetry.recorded after an accepted batch. Both tables are declared in personal_data() with subject: "install_id" and Disposition::Erase, so cratefield-module-privacy can erase exactly one install's rows from the id its own client prints.

See docs/TELEMETRY.md for the payload contract, the consent model and the client rules this crate implements.


MIT. Built in the open for Cratefield, a Factory Zero venture.