Telemetry: local preview and public contract
Apizr 0.4.6 keeps telemetry off by default in the CLI, Python SDK, VS Code and CI. This implementation contains a public receiving contract and an explicit local preview. After explicit consent, clients count only the approved operations in bounded process-local memory. There is no event spool, installation identifier or sending code. Opt-in cannot enable production transmission.
apizr telemetry status
apizr telemetry enable
apizr telemetry preview
apizr telemetry disable
Both commands operate without a project or experiment store. preview returns
an envelope containing the planned endpoint, consent request, context restriction,
the effective collection_enabled state, transmission_available: false and payload.
payload is a JSON string containing the exact report bytes, excluding its
terminal newline. A new preview process has an empty report because reports are
never persisted between processes:
{"schema_version":"apizr.telemetry/v1","context":"cli","events":[]}
The Python equivalent is explicit and local:
from apizr.telemetry import preview
result = preview(context="sdk", environ={})
assert result["collection_enabled"] is False
assert result["transmission_available"] is False
enable and disable save only schema_version and an enabled boolean in a
per-user consent file (macOS: ~/Library/Application Support/Apizr/telemetry.json;
Linux: $XDG_CONFIG_HOME/apizr/telemetry.json or ~/.config/apizr/telemetry.json;
Windows: %APPDATA%/Apizr/telemetry.json). It is limited to 512 bytes and written
atomically with mode 0600. APIZR_TELEMETRY_CONFIG selects an absolute operator-owned
location for testing or managed preferences. Invalid, symlinked, nonregular or
oversized preferences fail closed. Project files never grant consent.
APIZR_TELEMETRY=1 requests consent without creating a preference file. An explicit
saved disable, APIZR_TELEMETRY=0, a CI/served/runner context or
APIZR_TELEMETRY_ALLOWED=0 wins over opt-in. Disabling immediately discards active
local counters. No event data enters the consent file or experiment store.
To preview the actual counters of one CLI operation, explicitly request a local stderr preview (outside CI):
APIZR_TELEMETRY=1 APIZR_TELEMETRY_PREVIEW=1 apizr experiment inspect model.py
Normal stdout and exit status are preserved; stderr adds one
APIZR_TELEMETRY_PREVIEW JSON envelope. The wrapper records only the approved
operation and its coarse outcome. Collection or preview failures cannot change
the command's result. The SDK equivalent is an explicit telemetry.capture()
context: call usage.preview() inside it to inspect the exact report before the
scope clears its memory. Finalized tracking sessions contribute only one
capture_session counter, never their parameters, metrics or Run identity.
There are at most 1,000 observed calls per scope and 32 active scopes per process;
further observations are dropped. No persistent queue, retries or network client
exists.
The planned destination is https://telemetry.outerspace.sh, operated by Alien6
Studio, with intended EU hosting and no third-party processor. That infrastructure
is not represented as deployed or qualified. Production transmission is unavailable
until the private collector, retention, access and deletion procedures have been
qualified in #335
and a subsequent release enables it. There is no client
credential or token in this public contract.
Approved policy
The maintainer approved this policy on 2026-10-16, recorded in #316. It defines the allowed events and privacy boundaries for the remaining client work in #317. This approval does not enable collection or transmission. The current release still has no sending code, and production activation requires #335 and a subsequent release.
| Allowed operation | Product decision informed |
|---|---|
inspect |
Prioritize the first static inspection journey and refusal guidance. |
history_list, history_show, history_diff |
Prioritize history navigation and comparison usability. |
capture_session |
Prioritize SDK session usability and refusal guidance. |
generate_rest, generate_mcp |
Prioritize support for the two generated interfaces. |
Each entry contains only an operation, a coarse success, refused or failed
outcome, and a count. No exception message or diagnostic is included. The report
adds only schema_version and context (cli, sdk or vscode). Source code,
paths, filenames, experiment names, parameters, scientific metrics, traces, Run
digests, environment details, timestamps and user or installation IDs are excluded.
There is no free-form field. Counts describe calls, not installations or persons;
this contract cannot measure unique participating installations or people.
Client controls are tracked in
#317: explicit
enable/disable, bounded in-memory aggregation, status and exact preview. CI and
generated services never opt in. VS Code's global
telemetry.telemetryLevel and isTelemetryEnabled API restrict the Apizr choice: the stricter
decision wins and every child engine inherits it through
APIZR_TELEMETRY_ALLOWED=0. Usage requires global level all and the separate
apizr.telemetry.enabled setting. The preview honors these restrictions and any
truthy CI value, independently of APIZR_TELEMETRY=1.
There is no local event retention beyond the command/capture scope lifetime; disabling discards its counters. The extension keeps only the last bounded preview in memory for its window lifetime and clears it on opt-out. Server retention, IP/proxy logging, deletion, access and approved aggregate indicators require the private qualification in #335. No retention duration or deployed privacy control is claimed here. Website consent-gated analytics remain a separate system.
Receiving contract and reusable conformance fixtures
The closed v1 schema rejects unknown fields at every object level. Reports are UTF-8 JSON, at most 16,384 bytes, 32 event rows, 512 lexical nodes and depth 8. Each count is an integer from 1 to 1,000; an aggregate is at most 1,000 calls and cannot repeat an operation/outcome pair. These last two semantic constraints are enforced by admission in addition to the JSON schema. Unsupported versions, duplicate keys, non-finite values and oversized or structurally excessive reports are rejected with a fixed error.
Reusable accepted and rejected requests live in
tests/fixtures/telemetry/conformance.json. They contain synthetic aggregates,
not collected usage. The later private collector must pass these same fixtures.
# Regenerate the public schema.
python -m scripts.qualification.interfaces.telemetry_contract --export-schema
# Disposable CI receiver: prints an ephemeral loopback URL and stores no bodies.
python -m scripts.qualification.interfaces.telemetry_contract
The stub accepts POST / with one bounded Content-Length and
Content-Type: application/json. It returns 204 for an admitted report, 400 for
invalid content/framing and 413 for an invalid size. It does not log requests,
retain bodies or forward anything. CI tests post the CLI preview's exact payload
to this loopback stub; they never target production.
APIZR_TELEMETRY_TEST_ENDPOINT changes the preview destination only to an
explicit HTTP loopback IP and port, without DNS resolution. Other destinations,
credentials, query strings and fragments are refused. This is a conformance-test
override, not a production opt-in or a sender.