design(platform): compass-server + runner OTel emission and end-to-end trace continuity (RIG-2685) - #690
Merged
mattwilkinsonn merged 1 commit intoAug 28, 2026
Conversation
|
Compass engineering docs preview: https://compass-obs-rig-2685-server.compass-eng-docs.pages.dev Deployed from Changed pages: |
rigel-mintaka
force-pushed
the
compass-obs/rig-2685-server-runner-otel-design
branch
from
August 27, 2026 23:10
b7b8603 to
1f371b3
Compare
mattwilkinsonn
marked this pull request as ready for review
August 27, 2026 23:21
…d trace continuity (RIG-2685) Sibling record of the frozen observability-architecture design (#656 §T4b), covering the server + runner Go OTel emission leg and end-to-end W3C `traceparent` trace continuity across the server → runner → agent boundary. Builds on the frozen #649 propagation contract (server is origin, runner relays, agent continues). `Ledger-impact: none` (the `platform` bucket is ungoverned). ### Approach — two legs, one record - **Emission:** one `go/internal/otel` bootstrap package (the only `TracerProvider` construction site), OTLP/http-protobuf exporter, off by default and endpoint-gated on `OTEL_EXPORTER_OTLP_ENDPOINT`, wired into both `run()`s after `slog.SetDefault` and before `Serve`/`Run`. RPC spans come free from `connectrpc.com/otelconnect` interceptors on the existing chains. - **Propagation:** server-origin stamping at control-wrap (`deliverOp`/`steerOp` gain a `traceparent` param), runner relays the op verbatim, agent continues. The one genuinely new seam is the in-process events bus — `Bus.Publish` takes no ctx, so the trace context dies between `PostMessage` and the delivery consumer; bridged by a narrow `PublishCtx(ctx, payload)` used only by the message-origin publisher, stamping the traceparent onto the existing `Stamped[P]` envelope. - **Response boundary:** a `traceresponse` response-header interceptor makes the server-minted trace id readable by the UI/PostHog correlation seam (#656 T6/RIG-2874). ### Ownership compass-obs owns the emission + stamping + relay-span + e2e-test tasks (T1/T2/T3/T5/T6). The `agent.proto` `traceparent` field (T4) is compass-server's file zone — a stacked seam that lands first and unblocks compass-agent's decode (RIG-2871). compass-native owns the image rebuild the new Go deps force. ### Open Questions for the freeze gate 1. Metrics scope — recommend traces-only now, metrics a documented follow-up. 2. `traceparent` on the public `SessionInjection` observation — recommend defer (public-API surface, core does not need it; SEA-1267 gen-fence). 3. Bus bridge shape — recommend the `PublishCtx` split over a full signature cutover. 4. `traceresponse` header name — recommend the W3C draft name. 5. Origin span for agent-authored posts (red-team finding) — recommend a fresh per-call span in the hub's post arm; hard constraint that the Sessions-stream span never leaks into the publish ctx. Red-teamed by a design-critic pass; all mechanical findings folded and the two coverage-gap forks (held-deliver continuity, agent-post origin) surfaced as load-bearing Open Questions. Spec-impact: none. Refs RIG-2685 Co-authored-by: Matt Wilkinson <matt@rigel.build>
rigel-mintaka
force-pushed
the
compass-obs/rig-2685-server-runner-otel-design
branch
from
August 27, 2026 23:56
1f371b3 to
ab10025
Compare
mattwilkinsonn
approved these changes
Aug 28, 2026
mattwilkinsonn
deleted the
compass-obs/rig-2685-server-runner-otel-design
branch
August 28, 2026 01:38
rigel-mintaka
added a commit
that referenced
this pull request
Aug 28, 2026
T1 of the frozen server+runner OTel design record (`docs/designs/platform/compass-server-runner-otel/design.md`, RIG-2685, #690). Establishes the single Go OTel convention for the Compass backend — there was no Go OTel instrumentation before this; the server and runner emission wiring (T2/T3) and the propagation leg (T5) all build on it. New package `go/internal/otel`: - `Config{ServiceName, ServiceVersion, Endpoint}` + `SetupTracerProvider`/`SetupMeterProvider(ctx, cfg) (shutdown, err)` — off by default, endpoint-gated on `OTEL_EXPORTER_OTLP_ENDPOINT`: empty endpoint installs no global provider and returns a non-nil no-op shutdown (zero overhead, no network egress), mirroring the agent's `src/transport/otel-layer.ts` posture. Non-empty installs global providers whose resource carries `service.name`/`service.version`, OTLP-over-HTTP/protobuf exporters that read the endpoint env themselves (standard per-signal `/v1/traces` vs `/v1/metrics` suffixing), and the global W3C `TraceContext` propagator. - `Traceparent(ctx)` / `ContextWithTraceparent(ctx, tp)` — thin wrappers over the shared W3C propagator; empty/no-span yields `""`, malformed input returns the context unchanged. - `NewTraceResponseInterceptor()` — a connect unary interceptor that sets a `traceresponse` response header (`00-<traceid>-<spanid>-<flags>`) from the active span, the UI/PostHog trace-id correlation source; no-op when no active span. OTel Go SDK deps added at v1.46.0 (above the ≥v1.23.0 floor the record sets for `Span.AddLink`, used later by T5). ### FOD vendorHash lockstep The new Go deps move the fetched Go module set, invalidating the pinned `vendorHash` the two `buildGoModule` FODs share (`flake.nix` and `guest-image/default.nix`, both documented to carry the same value since guestd's `proxyVendor` fetches the full module graph). Left stale, the `compass-guest-image` and `flake-gate:flake-check` builds fail `hash mismatch in fixed-output derivation …-go-modules.drv`. Per the repo's gomod↔FOD lockstep convention (the same refresh Renovate's `refresh-fod-hashes.ts` rides in-PR on a dep bump), both pins are refreshed here to the SRI the build reports, so a gomod change and its FOD refresh land in one commit and main never goes red between merges. Verified locally: `moon run compass-guest-image:build flake-gate:flake-check` both pass. Built, tested (8/8), vetted, gofmt- and golangci-lint-clean. Spec-impact: none. Refs RIG-2888, RIG-2685, RIG-2895. Co-authored-by: Matt Wilkinson <matt@rigel.build>
mattwilkinsonn
added a commit
that referenced
this pull request
Aug 28, 2026
* feat(otel): add go/internal/otel bootstrap package (RIG-2888) T1 of the frozen server+runner OTel design record (`docs/designs/platform/compass-server-runner-otel/design.md`, RIG-2685, #690). Establishes the single Go OTel convention for the Compass backend — there was no Go OTel instrumentation before this; the server and runner emission wiring (T2/T3) and the propagation leg (T5) all build on it. New package `go/internal/otel`: - `Config{ServiceName, ServiceVersion, Endpoint}` + `SetupTracerProvider`/`SetupMeterProvider(ctx, cfg) (shutdown, err)` — off by default, endpoint-gated on `OTEL_EXPORTER_OTLP_ENDPOINT`: empty endpoint installs no global provider and returns a non-nil no-op shutdown (zero overhead, no network egress), mirroring the agent's `src/transport/otel-layer.ts` posture. Non-empty installs global providers whose resource carries `service.name`/`service.version`, OTLP-over-HTTP/protobuf exporters that read the endpoint env themselves (standard per-signal `/v1/traces` vs `/v1/metrics` suffixing), and the global W3C `TraceContext` propagator. - `Traceparent(ctx)` / `ContextWithTraceparent(ctx, tp)` — thin wrappers over the shared W3C propagator; empty/no-span yields `""`, malformed input returns the context unchanged. - `NewTraceResponseInterceptor()` — a connect unary interceptor that sets a `traceresponse` response header (`00-<traceid>-<spanid>-<flags>`) from the active span, the UI/PostHog trace-id correlation source; no-op when no active span. OTel Go SDK deps added at v1.46.0 (above the ≥v1.23.0 floor the record sets for `Span.AddLink`, used later by T5). ### FOD vendorHash lockstep The new Go deps move the fetched Go module set, invalidating the pinned `vendorHash` the two `buildGoModule` FODs share (`flake.nix` and `guest-image/default.nix`, both documented to carry the same value since guestd's `proxyVendor` fetches the full module graph). Left stale, the `compass-guest-image` and `flake-gate:flake-check` builds fail `hash mismatch in fixed-output derivation …-go-modules.drv`. Per the repo's gomod↔FOD lockstep convention (the same refresh Renovate's `refresh-fod-hashes.ts` rides in-PR on a dep bump), both pins are refreshed here to the SRI the build reports, so a gomod change and its FOD refresh land in one commit and main never goes red between merges. Verified locally: `moon run compass-guest-image:build flake-gate:flake-check` both pass. Built, tested (8/8), vetted, gofmt- and golangci-lint-clean. Spec-impact: none. Refs RIG-2888, RIG-2685, RIG-2895. Co-authored-by: Matt Wilkinson <matt@rigel.build> * fix(otel): address T1 review — wrap bootstrap errors, add meter + interceptor tests (RIG-2888) Review-fix commit atop the T1 bootstrap PR (#699). Addresses the low-severity findings from the review pass; the single medium (exporter-endpoint knob reconciliation) is a design decision routed separately and does not change T1 code. - **provider.go:** wrap the three bootstrap errors (resource build, trace exporter, metric exporter) with `fmt.Errorf("otel: ...: %w", err)` so a fatal startup log names the failing stage (house Go idiom). - **otel_test.go:** strengthen `TestSetupMeterProviderDisabled` with a sentinel assertion that no SDK MeterProvider is installed on the disabled path (mirrors the tracer test); add `TestSetupMeterProviderEnabled`; add `TestFormatTraceResponse` and `TestTraceResponseInterceptor` (valid-span sets header, no-span sets none, handler error passthrough) — the interceptor is a cross-task contract symbol and was previously uncovered in-package. Refs RIG-2888. Co-authored-by: Matt Wilkinson <matt@rigel.build> --------- Co-authored-by: Matt Wilkinson <matt@rigel.build>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Sibling record of the frozen observability-architecture design (#656 §T4b), covering the server + runner Go OTel emission leg and end-to-end W3C
traceparenttrace continuity across the server → runner → agent boundary. Builds on the frozen #649 propagation contract (server is origin, runner relays, agent continues).Ledger-impact: none(theplatformbucket is ungoverned).Approach — two legs, one record
go/internal/otelbootstrap package (the onlyTracerProviderconstruction site), OTLP/http-protobuf exporter, off by default and endpoint-gated onOTEL_EXPORTER_OTLP_ENDPOINT, wired into bothrun()s afterslog.SetDefaultand beforeServe/Run. RPC spans come free fromconnectrpc.com/otelconnectinterceptors on the existing chains.deliverOp/steerOpgain atraceparentparam), runner relays the op verbatim, agent continues. The one genuinely new seam is the in-process events bus —Bus.Publishtakes no ctx, so the trace context dies betweenPostMessageand the delivery consumer; bridged by a narrowPublishCtx(ctx, payload)used only by the message-origin publisher, stamping the traceparent onto the existingStamped[P]envelope.traceresponseresponse-header interceptor makes the server-minted trace id readable by the UI/PostHog correlation seam (docs(platform): observability & in-product data architecture design record #656 T6/RIG-2874).Ownership
compass-obs owns the emission + stamping + relay-span + e2e-test tasks (T1/T2/T3/T5/T6). The
agent.prototraceparentfield (T4) is compass-server's file zone — a stacked seam that lands first and unblocks compass-agent's decode (RIG-2871). compass-native owns the image rebuild the new Go deps force.Open Questions for the freeze gate
traceparenton the publicSessionInjectionobservation — recommend defer (public-API surface, core does not need it; SEA-1267 gen-fence).PublishCtxsplit over a full signature cutover.traceresponseheader name — recommend the W3C draft name.Red-teamed by a design-critic pass; all mechanical findings folded and the two coverage-gap forks (held-deliver continuity, agent-post origin) surfaced as load-bearing Open Questions.
Spec-impact: none. Refs RIG-2685
Co-authored-by: Matt Wilkinson matt@rigel.build