Skip to content

design(compass-agent): message->turn->tool trace continuity record (RIG-2508) - #649

Merged
mattwilkinsonn merged 7 commits into
mainfrom
compass-agent/rig-2508-trace-continuity-design
Aug 27, 2026
Merged

design(compass-agent): message->turn->tool trace continuity record (RIG-2508)#649
mattwilkinsonn merged 7 commits into
mainfrom
compass-agent/rig-2508-trace-continuity-design

Conversation

@rigel-mintaka

@rigel-mintaka rigel-mintaka commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

New design record for end-to-end OpenTelemetry trace continuity: linking
an inbound channel message to the loop turn it starts, to that turn's tool
calls. Follow-on to the frozen sibling record
docs/designs/platform/compass-agent-loop-otel/design.md (PR #561), which
activates the loop's native turn->tool spans and explicitly deferred the
message->turn link as a span-links / frame-sink problem.

Approach: thread a W3C traceparent STRING from the server's inbound
steer/deliver control to the turn's invoke_agent span -- true parent for
the idle 1:1 case, span links for the coalesced (N->1) flush and mid-turn
steer cases -- via a first-party bridge composing through the loop's
onSpanStart hook. Trace context crosses the transport fence and the wire as
a plain string only; no @opentelemetry/* type on any exported signature
(the agent sees a narrow OTel-type-free TurnTracer facet; cli.ts alone
holds the hook-carrying bridge). Off by default, parity with the sibling
record. Zero new deps.

All four Open Questions now RULED by Matt (2026-08-27) and folded into the
record (the ## Ruling section at the head); it freezes on merge as
(b)-shaped throughout:

  • OQ1 (load-bearing) = (b) -- server-side traceparent stamping on the
    inbound control. The turn joins the SERVER's trace for its message (one
    connected trace: creation -> routing -> delivery -> turn -> tool calls);
    the cross-lane wire contract (compass-server stamps, mirroring the
    RIG-2486 from_handle denorm) is authorized. The (a) agent-side-mint / T3'
    contingency is CLOSED.
  • OQ2 = hybrid -- true parent when one message starts an idle turn, span
    links for the coalesced (N->1) and mid-turn-steer cases.
  • OQ3 = yes -- SessionInjection carries the same traceparent string,
    folded into T4.
  • OQ4 = out of scope (confirmed) -- outbound turn -> published frames
    gets its own record if/when asked.

So the full T1->T4 set is live: T1/T2 land agent-side (topology core + the
now-FINAL traceparent: string signature), then T4 (compass-server proto +
stamp) and T3 (agent-side decode) ship as a stacked pair. The ruling also
fixes compass-server's RIG-2685 as a CONTINUATION of the stamped context
(server = trace origin), not a fresh root.

Red-teamed by the design-critic pass (no broken axis; six folds applied).

Ref: RIG-2508

Co-authored-by: Matt Wilkinson matt@rigel.build

@linear-code

linear-code Bot commented Aug 26, 2026

Copy link
Copy Markdown

RIG-2508

@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown

Compass engineering docs preview: https://compass-agent-rig-2508-trace.compass-eng-docs.pages.dev

Deployed from compass-agent/rig-2508-trace-continuity-design at 0419799.

Changed pages:

rigel-mintaka added a commit that referenced this pull request Aug 26, 2026
…inuity record (RIG-2508)

Review of #649 raised one medium (internal consistency) plus three low
precision findings; all fold into the record without preempting the
load-bearing OQ1 ruling.

- Medium: narrow the "agent-side machinery is identical under either
  ruling, lands first" claim. The topology core (onSpanStart capture +
  subagent filter, capturedInvokeAgent slot, linkActiveTurn/addLink,
  context.with wrapping, three-shapes threading, compass.message.ids
  stamping) is genuinely ruling-independent and lands inert first. But
  the traceparent:string arg threaded through steer/deliver/
  parseTraceparent is (b)-shaped -- under (a) there is no boundary
  string, the context is minted inside the bridge (T3'). Mark that one
  signature as finalizing on the OQ1 ruling so no (b)-shaped param is
  baked into the exported CompassAgentOptions/CompassAgent surface ahead
  of the fork. Updated Approach, Decision 2, Plan preamble, T2 Produces,
  and the T2 task line.
- Low: compass.message.ids is stamped DIRECTLY on the captured
  invoke_agent span via a new stampActiveTurn(setAttribute) member, not
  through onSpanStart (whose TelemetryHookContext carries no message
  ids). Added to TurnTracer, T1 members, and T2.
- Low: note the addLink post-creation sampling caveat (does not affect
  the invoke_agent sampling decision; fine under the off-by-default
  BatchSpanProcessor with no head sampler).
- Low: state that under (a) the minted compass.message.injection span is
  a local trace root (or parented to a SessionInjection observation),
  making the agent-local trace-root limitation explicit in the T3'
  fallback.

markdownlint clean; no loose equality in prose.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
rigel-mintaka added a commit that referenced this pull request Aug 26, 2026
…ovisional (RIG-2508)

Re-review of #649 noted the T2 Produces block still stated the concrete
traceparent:string signature on steer/deliver without the inline
'provisional until OQ1' caveat that the Approach, Plan preamble, and Tasks
list now carry. Not a contradiction -- the surrounding sections resolve
it -- but a reader taking Produces in isolation could read the signature
as decided. Append the (b)-shaped/provisional caveat so the block is
self-consistent standalone.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
rigel-mintaka and others added 5 commits August 26, 2026 22:58
…IG-2508)

New design record for end-to-end OpenTelemetry trace continuity: linking
an inbound channel message to the loop turn it starts, to that turn's tool
calls. Follow-on to the frozen sibling record
docs/designs/platform/compass-agent-loop-otel/design.md (PR #561), which
activates the loop's native turn->tool spans and explicitly deferred the
message->turn link as a span-links / frame-sink problem.

Approach: thread a W3C traceparent STRING from the server's inbound
steer/deliver control to the turn's invoke_agent span -- true parent for
the idle 1:1 case, span links for the coalesced (N->1) flush and mid-turn
steer cases -- via a first-party bridge composing through the loop's
onSpanStart hook. Trace context crosses the transport fence and the wire as
a plain string only; no @opentelemetry/* type on any exported signature
(the agent sees a narrow OTel-type-free TurnTracer facet; cli.ts alone
holds the hook-carrying bridge). Off by default, parity with the sibling
record. Zero new deps.

Carries one load-bearing Open Question for Matt: where trace context
originates -- agent-side minting vs server-side traceparent stamping on the
inbound control (recommended; cross-lane to compass-server, mirrors the
RIG-2486 from_handle denorm). Red-teamed by the design-critic pass (no
broken axis; six folds applied).

Co-authored-by: Matt Wilkinson <matt@rigel.build>
…inuity record (RIG-2508)

Review of #649 raised one medium (internal consistency) plus three low
precision findings; all fold into the record without preempting the
load-bearing OQ1 ruling.

- Medium: narrow the "agent-side machinery is identical under either
  ruling, lands first" claim. The topology core (onSpanStart capture +
  subagent filter, capturedInvokeAgent slot, linkActiveTurn/addLink,
  context.with wrapping, three-shapes threading, compass.message.ids
  stamping) is genuinely ruling-independent and lands inert first. But
  the traceparent:string arg threaded through steer/deliver/
  parseTraceparent is (b)-shaped -- under (a) there is no boundary
  string, the context is minted inside the bridge (T3'). Mark that one
  signature as finalizing on the OQ1 ruling so no (b)-shaped param is
  baked into the exported CompassAgentOptions/CompassAgent surface ahead
  of the fork. Updated Approach, Decision 2, Plan preamble, T2 Produces,
  and the T2 task line.
- Low: compass.message.ids is stamped DIRECTLY on the captured
  invoke_agent span via a new stampActiveTurn(setAttribute) member, not
  through onSpanStart (whose TelemetryHookContext carries no message
  ids). Added to TurnTracer, T1 members, and T2.
- Low: note the addLink post-creation sampling caveat (does not affect
  the invoke_agent sampling decision; fine under the off-by-default
  BatchSpanProcessor with no head sampler).
- Low: state that under (a) the minted compass.message.injection span is
  a local trace root (or parented to a SessionInjection observation),
  making the agent-local trace-root limitation explicit in the T3'
  fallback.

markdownlint clean; no loose equality in prose.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
…ovisional (RIG-2508)

Re-review of #649 noted the T2 Produces block still stated the concrete
traceparent:string signature on steer/deliver without the inline
'provisional until OQ1' caveat that the Approach, Plan preamble, and Tasks
list now carry. Not a contradiction -- the surrounding sections resolve
it -- but a reader taking Produces in isolation could read the signature
as decided. Append the (b)-shaped/provisional caveat so the block is
self-consistent standalone.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
… OQ1 ruling (RIG-2508)

compass-server flagged the cross-lane seam: their backlog RIG-2685 (Go
OTel message tracing -- PostMessage root + delivery consumer + gateway
control + gRPC context propagation) is the downstream consumer whose
scope the OQ1 origin ruling sets. Name it in both the T4 task and OQ1 so
the ruling's cross-lane reach is explicit in the frozen contract:

- Under (b) server-side stamping, RIG-2685's gRPC-propagation leg
  EXTRACTS+CONTINUES the traceparent T4 stamps rather than minting a
  fresh root at PostMessage -- server = trace origin, RIG-2685 =
  continuation.
- Under (a) agent-local mint, RIG-2685 mints server-side and the agent
  continues.
- Under (c) attribute-only, RIG-2685 is unaffected.

Additive naming only; does not preempt the ruling. compass-server owns
RIG-2685 and monitors RIG-2786 to align on the ruling.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
… T3/T4 (RIG-2508)

Matt ruled 2026-08-27: OQ1 = (b) server-side traceparent stamping; OQ2 =
hybrid; OQ3 = yes; OQ4 = out of scope. All four recommendations accepted, so
the record freezes (b)-shaped throughout: the (a)/T3-prime mint contingency is
closed, the traceparent-string signature on steer/deliver is FINAL, and T3/T4
are unblocked as a stacked pair. Also fixes compass-server RIG-2685 as a
continuation of the stamped context (server = trace origin).

Co-authored-by: Matt Wilkinson <matt@rigel.build>
@rigel-mintaka
rigel-mintaka force-pushed the compass-agent/rig-2508-trace-continuity-design branch from 5f66fb8 to 9345005 Compare August 27, 2026 03:00
rigel-mintaka and others added 2 commits August 26, 2026 23:06
…ntil' hedge in T2 task (RIG-2508)

Pr649RulingFoldReview flagged one gating-floor medium: the Tasks-list T2
entry still read 'FINALIZES on the OQ1 ruling -- provisional until then',
contradicting the ruling section + Plan preamble + T2 Produces block the fold
already made final. Fixed to 'FINAL under the OQ1 = (b) ruling -- no T3-prime
mint-seam contingency remains'. Also past-tensed two Decision-2 fork-analysis
hedges (L229 'gated on Matt's ruling' -> 'authorized by Matt's OQ1 = (b)
ruling'; L251 'FINALIZES only once Matt rules' -> 'was finalized by Matt's OQ1
= (b) ruling') for a tighter frozen record (the review's optional low).

Co-authored-by: Matt Wilkinson <matt@rigel.build>
…ach thesis (RIG-2508)

Re-review (Pr649FixReReview) returned ALL-CLEAR (0h/0m) and surfaced one
pre-existing non-gating low the whole-file grep caught: the bolded Approach
thesis still framed OQ1 as a pending fork ('RECOMMENDED', 'finalizes on the
OQ1 ruling'). Swept to ruled-(b) ('RULED (b) though cross-lane', 'was
finalized by the OQ1 = (b) ruling') so the thesis matches the ## Ruling
section. Last stale hedge in the frozen record; zero technical-content change.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
@mattwilkinsonn
mattwilkinsonn merged commit f468431 into main Aug 27, 2026
22 checks passed
@mattwilkinsonn
mattwilkinsonn deleted the compass-agent/rig-2508-trace-continuity-design branch August 27, 2026 21:14
rigel-mintaka added a commit that referenced this pull request Aug 27, 2026
…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 added a commit that referenced this pull request Aug 27, 2026
…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>
mattwilkinsonn added a commit that referenced this pull request Aug 28, 2026
…d trace continuity (RIG-2685) (#690)

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants