Privacy-safe observability
Bounded aggregate observability is always available through get_observability_status and discord://connector/observability. It counts completed MCP tool and Discord REST operations, errors, retries, active calls, outcome classes, and fixed duration buckets. It also maintains a bounded rolling lower bound on the 401, 403, and non-shared 429 responses that Discord defines as invalid requests, including intermediate responses that the connector safely retries. Discord's rate-limit documentation defines the IP-wide boundary and excludes shared-scope 429 responses. The snapshot publishes the documented reference limit and window, local resolution, per-status counts, and an explicit statement that traffic from other processes sharing the egress IP is unknown. It never presents a remaining-capacity estimate or uses the aggregate to alter request behavior.
The snapshot is process-local, never persisted, and includes explicit machine-readable privacy claims. Unknown operation names collapse to unknown rather than creating unbounded or attacker-controlled labels. Error labels use a closed content-free taxonomy for configuration, policy, Discord client and server responses, transport, cancellation, timeouts, local rate limiting, reviewed plan drift, replay conflicts, live evidence, identity, execution, validation, auditing, and durable coordination failures. New reviewed workflows inherit these fixed categories from their internal error family instead of silently collapsing to unknown. Categories are observational only and never authorize a retry, skip a review gate, or alter write behavior. The rolling implementation uses monotonic fixed-resolution buckets, so retained memory is bounded by the documented window rather than request volume.
Set observability.jsonLogsEnabled: true to write compact JSON records for completed operations, counted invalid responses, exporter transitions, and export results to stderr. Records use only fixed tool or REST operation names, outcome and error categories, numeric HTTP status and retry data, durations, and timestamps. The transport reduces the rate-limit scope header to a fixed shared-or-not classification before observability and no header value enters the tracker, log, metric, or snapshot. Standard connector diagnostics remain separate human-readable stderr lines.
Collector export remains inert unless observability.exportEnabled: true. The stdio runner then emits manually created OTLP/HTTP protobuf traces and metrics, including one counter for connector-observed invalid responses with only a fixed numeric status attribute. MCP tool spans parent their Discord REST spans. A tool request carrying a strict W3C version 00 _meta.traceparent continues that remote trace; a complete bounded _meta.tracestate is retained only when every normalized member validates without rewriting or loss. Malformed, unsupported, zero-ID, non-string, or oversized carriers are ignored without rejecting the MCP call or logging their values. _meta.baggage is never imported because it may contain arbitrary sensitive correlation data. The implementation does not install automatic HTTP, logging, or exception instrumentation and creates no span events or links. Tool arguments and results, Discord identifiers, raw routes and URLs, request or response bodies, headers, bot tokens, error text and stacks, plan digests, Gateway records, activity records, and raw trace carriers never enter spans, metrics, logs, or local aggregates.
The connector supports the standard OTLP endpoint, header, protocol, compression, timeout, service-name, and trace-sampler variables listed above, with explicitly configured per-signal settings taking precedence. Remote collectors require HTTPS. Plaintext HTTP is accepted only for localhost, 127.0.0.0/8, or [::1]; URLs with credentials, query strings, or fragments are rejected. Header names and percent-decoded values are bounded, newline-free, and rejected if they contain the Discord token. Service names reject snowflake-like numeric identifiers. Runtime status reports only whether endpoints or headers were configured, never their values.
Exporter failures are observational: they update fixed health counters but never fail a Discord or MCP operation. The connector uses private trace and metric providers so a preloaded global OpenTelemetry SDK cannot redirect its telemetry or contribute unrelated spans and metrics. Shutdown performs a bounded final trace and metric flush. Constructing the adapter directly, running doctor, and running setup never opens a collector connection even when export configuration is present; only the stdio runner owns exporter startup and shutdown. smoke launches that runner, exercises configured exporter startup, and performs its bounded shutdown.
Canonical source: docs/reference.md
Documentation generated for guildcontrol@0.0.0. Canonical source and edit history remain in the public repository. GuildControl is an independent project and is not affiliated with or endorsed by Discord Inc. Discord is used only to identify the platform that GuildControl connects to.