---
schema_version: 1
id: RAC-KTY25CK9W8TN
type: roadmap
---
# RAC v0.10.4 — Guide Telemetry

## Status

Planned

## Context

The Guide shipped in v0.10.0 and the onboarding and grounding work made
it installable and credible — but nothing answers the simplest product
question: is it actually being used, and which tools matter? Without
that signal, search-quality and description investments are guesses.

Telemetry for a trust-first, local-first tool has to be earned, not
assumed. ADR-035 forbids a mandatory RAC cloud dependency, and the
trust-transparency requirement names hosted infrastructure a non-goal.
ADR-040 settles the shape: opt-in, default-off, local-only recording of
counts and metadata — never tool arguments, never repository content —
with sharing as a deliberate, user-driven act.

This milestone implements that decision: a recorder inside the server
layer, an explicit `--telemetry` flag, a read-back command whose JSON
output is the export, and a share flow that prints a prefilled GitHub
issue URL the user submits with their own account.

## Outcomes

- `rac mcp --telemetry` appends one JSONL event per tool call to a
  local state file; without the flag, no file is touched.
- Tool responses are byte-identical with telemetry on and off; the
  existing Guide contract batteries pass unchanged.
- `rac mcp-stats` summarizes the local log (human and `--json`); the
  JSON output is the shareable export.
- `rac mcp-stats --share` prints a prefilled GitHub issue URL; RAC
  itself contains no network code.

## Initiatives

### Initiative 1 — Telemetry Recorder (ADR-040)

A stdlib-only recorder module in the server layer: event schema pinned
by ADR-040, append-only JSONL under the XDG state directory, a random
per-process session id, single-generation size rotation, and a
never-raise posture — a recorder that cannot write records nothing and
never breaks a tool call.

### Initiative 2 — Opt-In Serving

An explicit `--telemetry` flag on `rac mcp`, default off, surfaced in
the client's server configuration rather than hidden persistent state.
When enabled, the server prints a one-line stderr notice naming what is
recorded and where; stdout stays protocol-only. Each tool call routes
through an observe wrapper that times the call, classifies the outcome
from the structured payload, and returns the payload unchanged.

### Initiative 3 — Read-Back and Share Surface

A `rac mcp-stats` command renders the local log as a summary: event and
session counts, per-tool calls, errors, truncation, and timing, in
human and `--json` forms. `--share` URL-encodes the same JSON summary
into a prefilled new-issue URL for the RAC repository's usage-report
issue form and prints it; the user reviews and submits in their own
browser. A missing or empty log is a valid answer, not an error.

### Initiative 4 — Contract Battery

A telemetry battery pins the event schema field-for-field, proves
default-off behavior, proves payload stability (responses byte-identical
with a recorder attached versus none, across ok, error, and truncated
shapes), and covers write-failure tolerance, rotation, and corrupted-log
tolerance. Existing Guide goldens pass unchanged — that is the proof
telemetry never touches the wire contract.

## Constraints

- Tool response bytes are unchanged by telemetry; the recorded log is
  never an input to any tool response (ADR-032 holds untouched).
- No network code anywhere in RAC (ADR-035, rac-trust-transparency);
  the share flow builds a URL and the user's browser transmits it.
- Events carry counts and metadata only: no tool arguments, no artifact
  IDs, no query strings, no paths, no repository content (ADR-040).
- Tool descriptions are unchanged (ADR-030).
- The recorder lives in the server layer and imports only the standard
  library; Core and services stay telemetry-unaware (ADR-031).

## Non-Goals

- Automatic upload, remote endpoints, or any background transmission
- Config-file or environment-variable enablement
- Recording tool arguments or repository content
- Retention policy beyond one rotated generation
- Telemetry for CLI commands or Explorer; this is a Guide surface

## Implementation Contract

The following decisions are pinned for v0.10.4.

### Module Locations

- Recorder, summary, and share-URL logic live in
  `src/rac/mcp/telemetry.py`, stdlib-only; summary logic cannot live in
  services because services may not import the server layer.
- `build_server` accepts an optional recorder; `run_server` accepts a
  telemetry flag and owns the stderr notice.
- Rendering follows convention: human in `src/rac/output/human.py`,
  JSON in `src/rac/output/json.py`.

### Event Schema

One JSON object per line, fields pinned by ADR-040:
`schema_version` (`"1"`), `ts` (ISO 8601 UTC), `session` (random
per-process hex), `tool`, `outcome` (`ok` | `error` | `exception`),
`error` (structured error code, present only when outcome is `error`),
`duration_ms` (int), `truncated` (bool, always present).

### CLI and Exit Codes

- `rac mcp --telemetry`: store-true, default off.
- `rac mcp-stats [--json | --share]`: exit 0 whenever a summary is
  produced, including the empty and missing-log cases; usage errors
  exit 2. `--json` and `--share` are mutually exclusive.
- Log path: `$XDG_STATE_HOME/rac/guide-telemetry.jsonl`, defaulting to
  `~/.local/state/rac/guide-telemetry.jsonl`.

### Testing

- New telemetry battery (one battery, ADR-027) isolated via
  `XDG_STATE_HOME`; payload-stability cases compare responses
  byte-for-byte with and without a recorder.
- `mcp-stats` human, JSON, and share output pinned by goldens against a
  fixture log; the share URL decodes back to the exact JSON payload.
- Existing `mcp` batteries and goldens pass without re-pinning.

## Success Measures

- Running the dogfood corpus with `--telemetry` and driving the four
  tools produces events with no arguments or content in the log.
- `rac mcp-stats` answers "is Guide used, and which tools" from the
  local log alone.
- A usage report submitted through the share URL arrives as a labeled
  GitHub issue containing only counts and timestamps.
- Zero changes to existing Guide golden files in the delivering PR.

## Risks

- An opt-in flag nobody sets yields no signal. Accepted: a quiet
  channel is the cost of the trust posture; onboarding docs ask early
  users to enable it.
- Future fields drift toward recording content. Mitigated: the schema
  is pinned field-for-field in ADR-040 and the battery; adding a field
  is a recorded decision, not a patch.
- Prefilled-URL length limits. Mitigated: the summary is a few hundred
  bytes; the share test pins the URL round-trip.

## Assumptions

- GitHub issue forms continue to accept query-parameter prefill for
  textarea fields.
- The XDG state-directory pattern already used by Explorer is
  acceptable for Guide state.

## Related Decisions

- ADR-040
- ADR-030
- ADR-031
- ADR-032
- ADR-033
- ADR-034
- ADR-035
- ADR-027

## Related Designs

- guide-tool-surface

## Related Requirements

- rac-agent-context-guide
- rac-trust-transparency

## Dependencies

- v0.10.0 server and tool surface
