Skip to content

Add traces service contract#73

Merged
haasonsaas merged 2 commits intomainfrom
codex/traces-proto-bootstrap
Apr 15, 2026
Merged

Add traces service contract#73
haasonsaas merged 2 commits intomainfrom
codex/traces-proto-bootstrap

Conversation

@haasonsaas
Copy link
Copy Markdown
Contributor

Summary

  • add traces.v1 with span, trace summary, and span-tree query models
  • define SpanIngestService RPCs for ingest, get, list, and tree reconstruction
  • generate Go, TypeScript, and Python bindings and wire tool descriptions

Testing

  • buf generate --path proto/traces/v1/traces.proto
  • go test ./... -count=1

Part of evalops/traces#5 and unblocks evalops/attribution#5.

@cursor
Copy link
Copy Markdown

cursor bot commented Apr 15, 2026

PR Summary

Medium Risk
Introduces a new public API surface (traces.v1) and large generated client/server stubs across Go/TS/Python; risk is mainly around contract correctness and downstream integration compatibility rather than runtime logic changes.

Overview
Adds a new traces.v1 protobuf API (SpanIngestService) to ingest spans and query traces, including flat trace retrieval, paginated listing, and span-tree reconstruction, plus new enums/models for span status and governance decisions.

Checks in the newly generated bindings for Go (protobuf + Connect), TypeScript (protobuf + Connect), and Python, and updates descriptions.yaml with RPC summaries. CI buf generate steps now use --timeout 10m to reduce flakiness during codegen.

Reviewed by Cursor Bugbot for commit b738498. Bugbot is set up for automated code reviews on this repo. Configure here.

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Traces descriptions split MeterService section in descriptions file
    • Moved the traces/v1 descriptions block below the full MeterService group so related entries remain contiguous.
Preview (3e750b6973)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -47,7 +47,7 @@
         with:
           go-version-file: go.mod
           # go-version: "1.22"
-      - run: buf generate
+      - run: buf generate --timeout 10m
       - name: Check generated code is up to date
         run: |
           if [ -n "$(git status --porcelain gen/)" ]; then
@@ -80,7 +80,7 @@
           node-version: 20
           cache: npm
       - run: npm ci
-      - run: buf generate
+      - run: buf generate --timeout 10m
       - name: Check generated code is up to date
         run: |
           if [ -n "$(git status --porcelain gen/)" ]; then
@@ -102,7 +102,7 @@
         with:
           python-version: "3.12"
       - run: python -m pip install --upgrade build pip
-      - run: buf generate
+      - run: buf generate --timeout 10m
       - name: Check generated code is up to date
         run: |
           if [ -n "$(git status --porcelain gen/)" ]; then

diff --git a/descriptions.yaml b/descriptions.yaml
--- a/descriptions.yaml
+++ b/descriptions.yaml
@@ -270,6 +270,21 @@
   Get a dashboard summary: total events, tokens, cost, and top-N
   breakdowns by event type, surface, model, and provider.
 
+# --- traces/v1 ---
+SpanIngestService_IngestSpans: >-
+  Record one or more execution spans for an agent trace. Stores span identity,
+  parent/child relationships, token usage, governance outcome, latency, and
+  cost metadata, then returns updated trace summaries for the affected traces.
+SpanIngestService_GetTrace: >-
+  Retrieve a trace by ID. Returns the trace summary plus the flat span list for
+  inspection or downstream tree reconstruction.
+SpanIngestService_ListTraces: >-
+  List traces by workspace, agent, surface, or time range. Returns paginated
+  trace summaries with total count metadata.
+SpanIngestService_GetSpanTree: >-
+  Retrieve a trace as a parent/child span tree. Used for execution debugging,
+  attribution, and governance review.
+
 # --- notifications/v1 ---
 NotificationService_Send: >-
   Send a notification to a recipient through their preferred channel

diff --git a/gen/go/traces/v1/traces.pb.go b/gen/go/traces/v1/traces.pb.go
new file mode 100644
--- /dev/null
+++ b/gen/go/traces/v1/traces.pb.go
@@ -1,0 +1,1148 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.11
+// 	protoc        (unknown)
+// source: traces/v1/traces.proto
+
+package tracesv1
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	structpb "google.golang.org/protobuf/types/known/structpb"
+	timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+	reflect "reflect"
+	sync "sync"
+	unsafe "unsafe"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type SpanStatus int32
+
+const (
+	SpanStatus_SPAN_STATUS_UNSPECIFIED SpanStatus = 0
+	SpanStatus_SPAN_STATUS_OK          SpanStatus = 1
+	SpanStatus_SPAN_STATUS_ERROR       SpanStatus = 2
+	SpanStatus_SPAN_STATUS_CANCELLED   SpanStatus = 3
+)
+
+// Enum value maps for SpanStatus.
+var (
+	SpanStatus_name = map[int32]string{
+		0: "SPAN_STATUS_UNSPECIFIED",
+		1: "SPAN_STATUS_OK",
+		2: "SPAN_STATUS_ERROR",
+		3: "SPAN_STATUS_CANCELLED",
+	}
+	SpanStatus_value = map[string]int32{
+		"SPAN_STATUS_UNSPECIFIED": 0,
+		"SPAN_STATUS_OK":          1,
+		"SPAN_STATUS_ERROR":       2,
+		"SPAN_STATUS_CANCELLED":   3,
+	}
+)
+
+func (x SpanStatus) Enum() *SpanStatus {
+	p := new(SpanStatus)
+	*p = x
+	return p
+}
+
+func (x SpanStatus) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (SpanStatus) Descriptor() protoreflect.EnumDescriptor {
+	return file_traces_v1_traces_proto_enumTypes[0].Descriptor()
+}
+
+func (SpanStatus) Type() protoreflect.EnumType {
+	return &file_traces_v1_traces_proto_enumTypes[0]
+}
+
+func (x SpanStatus) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use SpanStatus.Descriptor instead.
+func (SpanStatus) EnumDescriptor() ([]byte, []int) {
+	return file_traces_v1_traces_proto_rawDescGZIP(), []int{0}
+}
+
+type GovernanceDecision int32
+
+const (
+	GovernanceDecision_GOVERNANCE_DECISION_UNSPECIFIED      GovernanceDecision = 0
+	GovernanceDecision_GOVERNANCE_DECISION_ALLOW            GovernanceDecision = 1
+	GovernanceDecision_GOVERNANCE_DECISION_DENY             GovernanceDecision = 2
+	GovernanceDecision_GOVERNANCE_DECISION_REQUIRE_APPROVAL GovernanceDecision = 3
+	GovernanceDecision_GOVERNANCE_DECISION_AUTO_APPROVED    GovernanceDecision = 4
+)
+
+// Enum value maps for GovernanceDecision.
+var (
+	GovernanceDecision_name = map[int32]string{
+		0: "GOVERNANCE_DECISION_UNSPECIFIED",
+		1: "GOVERNANCE_DECISION_ALLOW",
+		2: "GOVERNANCE_DECISION_DENY",
+		3: "GOVERNANCE_DECISION_REQUIRE_APPROVAL",
+		4: "GOVERNANCE_DECISION_AUTO_APPROVED",
+	}
+	GovernanceDecision_value = map[string]int32{
+		"GOVERNANCE_DECISION_UNSPECIFIED":      0,
+		"GOVERNANCE_DECISION_ALLOW":            1,
+		"GOVERNANCE_DECISION_DENY":             2,
+		"GOVERNANCE_DECISION_REQUIRE_APPROVAL": 3,
+		"GOVERNANCE_DECISION_AUTO_APPROVED":    4,
+	}
+)
+
+func (x GovernanceDecision) Enum() *GovernanceDecision {
+	p := new(GovernanceDecision)
+	*p = x
+	return p
+}
+
+func (x GovernanceDecision) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (GovernanceDecision) Descriptor() protoreflect.EnumDescriptor {
+	return file_traces_v1_traces_proto_enumTypes[1].Descriptor()
+}
+
+func (GovernanceDecision) Type() protoreflect.EnumType {
+	return &file_traces_v1_traces_proto_enumTypes[1]
+}
+
+func (x GovernanceDecision) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use GovernanceDecision.Descriptor instead.
+func (GovernanceDecision) EnumDescriptor() ([]byte, []int) {
+	return file_traces_v1_traces_proto_rawDescGZIP(), []int{1}
+}
+
+type Span struct {
+	state              protoimpl.MessageState `protogen:"open.v1"`
+	TraceId            string                 `protobuf:"bytes,1,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"`
+	SpanId             string                 `protobuf:"bytes,2,opt,name=span_id,json=spanId,proto3" json:"span_id,omitempty"`
+	ParentSpanId       string                 `protobuf:"bytes,3,opt,name=parent_span_id,json=parentSpanId,proto3" json:"parent_span_id,omitempty"`
+	WorkspaceId        string                 `protobuf:"bytes,4,opt,name=workspace_id,json=workspaceId,proto3" json:"workspace_id,omitempty"`
+	OrganizationId     string                 `protobuf:"bytes,5,opt,name=organization_id,json=organizationId,proto3" json:"organization_id,omitempty"`
+	AgentId            string                 `protobuf:"bytes,6,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"`
+	Surface            string                 `protobuf:"bytes,7,opt,name=surface,proto3" json:"surface,omitempty"`
+	Name               string                 `protobuf:"bytes,8,opt,name=name,proto3" json:"name,omitempty"`
+	Kind               string                 `protobuf:"bytes,9,opt,name=kind,proto3" json:"kind,omitempty"`
+	Model              string                 `protobuf:"bytes,10,opt,name=model,proto3" json:"model,omitempty"`
+	Provider           string                 `protobuf:"bytes,11,opt,name=provider,proto3" json:"provider,omitempty"`
+	TokenInput         int64                  `protobuf:"varint,12,opt,name=token_input,json=tokenInput,proto3" json:"token_input,omitempty"`
+	TokenOutput        int64                  `protobuf:"varint,13,opt,name=token_output,json=tokenOutput,proto3" json:"token_output,omitempty"`
+	LatencyMs          int64                  `protobuf:"varint,14,opt,name=latency_ms,json=latencyMs,proto3" json:"latency_ms,omitempty"`
+	Status             SpanStatus             `protobuf:"varint,15,opt,name=status,proto3,enum=traces.v1.SpanStatus" json:"status,omitempty"`
+	GovernanceDecision GovernanceDecision     `protobuf:"varint,16,opt,name=governance_decision,json=governanceDecision,proto3,enum=traces.v1.GovernanceDecision" json:"governance_decision,omitempty"`
+	CostUsd            float64                `protobuf:"fixed64,17,opt,name=cost_usd,json=costUsd,proto3" json:"cost_usd,omitempty"`
+	Attributes         *structpb.Struct       `protobuf:"bytes,18,opt,name=attributes,proto3" json:"attributes,omitempty"`
+	StartedAt          *timestamppb.Timestamp `protobuf:"bytes,19,opt,name=started_at,json=startedAt,proto3" json:"started_at,omitempty"`
+	EndedAt            *timestamppb.Timestamp `protobuf:"bytes,20,opt,name=ended_at,json=endedAt,proto3" json:"ended_at,omitempty"`
+	unknownFields      protoimpl.UnknownFields
+	sizeCache          protoimpl.SizeCache
+}
+
+func (x *Span) Reset() {
+	*x = Span{}
+	mi := &file_traces_v1_traces_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Span) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Span) ProtoMessage() {}
+
+func (x *Span) ProtoReflect() protoreflect.Message {
+	mi := &file_traces_v1_traces_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Span.ProtoReflect.Descriptor instead.
+func (*Span) Descriptor() ([]byte, []int) {
+	return file_traces_v1_traces_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Span) GetTraceId() string {
+	if x != nil {
+		return x.TraceId
+	}
+	return ""
+}
+
+func (x *Span) GetSpanId() string {
+	if x != nil {
+		return x.SpanId
+	}
+	return ""
+}
+
+func (x *Span) GetParentSpanId() string {
+	if x != nil {
+		return x.ParentSpanId
+	}
+	return ""
+}
+
+func (x *Span) GetWorkspaceId() string {
+	if x != nil {
+		return x.WorkspaceId
+	}
+	return ""
+}
+
+func (x *Span) GetOrganizationId() string {
+	if x != nil {
+		return x.OrganizationId
+	}
+	return ""
+}
+
+func (x *Span) GetAgentId() string {
+	if x != nil {
+		return x.AgentId
+	}
+	return ""
+}
+
+func (x *Span) GetSurface() string {
+	if x != nil {
+		return x.Surface
+	}
+	return ""
+}
+
+func (x *Span) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *Span) GetKind() string {
+	if x != nil {
+		return x.Kind
+	}
+	return ""
+}
+
+func (x *Span) GetModel() string {
+	if x != nil {
+		return x.Model
+	}
+	return ""
+}
+
+func (x *Span) GetProvider() string {
+	if x != nil {
+		return x.Provider
+	}
+	return ""
+}
+
+func (x *Span) GetTokenInput() int64 {
+	if x != nil {
+		return x.TokenInput
+	}
+	return 0
+}
+
+func (x *Span) GetTokenOutput() int64 {
+	if x != nil {
+		return x.TokenOutput
+	}
+	return 0
+}
+
+func (x *Span) GetLatencyMs() int64 {
+	if x != nil {
+		return x.LatencyMs
+	}
+	return 0
+}
+
+func (x *Span) GetStatus() SpanStatus {
+	if x != nil {
+		return x.Status
+	}
+	return SpanStatus_SPAN_STATUS_UNSPECIFIED
+}
+
+func (x *Span) GetGovernanceDecision() GovernanceDecision {
+	if x != nil {
+		return x.GovernanceDecision
+	}
+	return GovernanceDecision_GOVERNANCE_DECISION_UNSPECIFIED
+}
+
+func (x *Span) GetCostUsd() float64 {
+	if x != nil {
+		return x.CostUsd
+	}
+	return 0
+}
+
+func (x *Span) GetAttributes() *structpb.Struct {
+	if x != nil {
+		return x.Attributes
+	}
+	return nil
+}
+
+func (x *Span) GetStartedAt() *timestamppb.Timestamp {
+	if x != nil {
+		return x.StartedAt
+	}
+	return nil
+}
+
+func (x *Span) GetEndedAt() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EndedAt
+	}
+	return nil
+}
+
+type TraceSummary struct {
+	state            protoimpl.MessageState `protogen:"open.v1"`
+	TraceId          string                 `protobuf:"bytes,1,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"`
+	WorkspaceId      string                 `protobuf:"bytes,2,opt,name=workspace_id,json=workspaceId,proto3" json:"workspace_id,omitempty"`
+	OrganizationId   string                 `protobuf:"bytes,3,opt,name=organization_id,json=organizationId,proto3" json:"organization_id,omitempty"`
+	AgentId          string                 `protobuf:"bytes,4,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"`
+	Surface          string                 `protobuf:"bytes,5,opt,name=surface,proto3" json:"surface,omitempty"`
+	RootSpanName     string                 `protobuf:"bytes,6,opt,name=root_span_name,json=rootSpanName,proto3" json:"root_span_name,omitempty"`
+	TotalSpans       int32                  `protobuf:"varint,7,opt,name=total_spans,json=totalSpans,proto3" json:"total_spans,omitempty"`
+	TotalTokenInput  int64                  `protobuf:"varint,8,opt,name=total_token_input,json=totalTokenInput,proto3" json:"total_token_input,omitempty"`
+	TotalTokenOutput int64                  `protobuf:"varint,9,opt,name=total_token_output,json=totalTokenOutput,proto3" json:"total_token_output,omitempty"`
+	TotalCostUsd     float64                `protobuf:"fixed64,10,opt,name=total_cost_usd,json=totalCostUsd,proto3" json:"total_cost_usd,omitempty"`
+	TotalLatencyMs   int64                  `protobuf:"varint,11,opt,name=total_latency_ms,json=totalLatencyMs,proto3" json:"total_latency_ms,omitempty"`
+	StartedAt        *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=started_at,json=startedAt,proto3" json:"started_at,omitempty"`
+	EndedAt          *timestamppb.Timestamp `protobuf:"bytes,13,opt,name=ended_at,json=endedAt,proto3" json:"ended_at,omitempty"`
+	unknownFields    protoimpl.UnknownFields
+	sizeCache        protoimpl.SizeCache
+}
+
+func (x *TraceSummary) Reset() {
+	*x = TraceSummary{}
+	mi := &file_traces_v1_traces_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *TraceSummary) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TraceSummary) ProtoMessage() {}
+
+func (x *TraceSummary) ProtoReflect() protoreflect.Message {
+	mi := &file_traces_v1_traces_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use TraceSummary.ProtoReflect.Descriptor instead.
+func (*TraceSummary) Descriptor() ([]byte, []int) {
+	return file_traces_v1_traces_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *TraceSummary) GetTraceId() string {
+	if x != nil {
+		return x.TraceId
+	}
+	return ""
+}
+
+func (x *TraceSummary) GetWorkspaceId() string {
+	if x != nil {
+		return x.WorkspaceId
+	}
+	return ""
+}
+
+func (x *TraceSummary) GetOrganizationId() string {
+	if x != nil {
+		return x.OrganizationId
+	}
+	return ""
+}
+
+func (x *TraceSummary) GetAgentId() string {
+	if x != nil {
+		return x.AgentId
+	}
+	return ""
+}
+
+func (x *TraceSummary) GetSurface() string {
+	if x != nil {
+		return x.Surface
+	}
+	return ""
+}
+
+func (x *TraceSummary) GetRootSpanName() string {
+	if x != nil {
+		return x.RootSpanName
+	}
+	return ""
+}
+
+func (x *TraceSummary) GetTotalSpans() int32 {
+	if x != nil {
+		return x.TotalSpans
+	}
+	return 0
+}
+
+func (x *TraceSummary) GetTotalTokenInput() int64 {
+	if x != nil {
+		return x.TotalTokenInput
+	}
+	return 0
+}
+
+func (x *TraceSummary) GetTotalTokenOutput() int64 {
+	if x != nil {
+		return x.TotalTokenOutput
+	}
+	return 0
+}
+
+func (x *TraceSummary) GetTotalCostUsd() float64 {
+	if x != nil {
+		return x.TotalCostUsd
+	}
+	return 0
+}
+
+func (x *TraceSummary) GetTotalLatencyMs() int64 {
+	if x != nil {
+		return x.TotalLatencyMs
+	}
+	return 0
+}
+
+func (x *TraceSummary) GetStartedAt() *timestamppb.Timestamp {
+	if x != nil {
+		return x.StartedAt
+	}
+	return nil
+}
+
+func (x *TraceSummary) GetEndedAt() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EndedAt
+	}
+	return nil
+}
+
+type IngestSpansRequest struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Spans         []*Span                `protobuf:"bytes,1,rep,name=spans,proto3" json:"spans,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *IngestSpansRequest) Reset() {
+	*x = IngestSpansRequest{}
+	mi := &file_traces_v1_traces_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *IngestSpansRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*IngestSpansRequest) ProtoMessage() {}
+
+func (x *IngestSpansRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_traces_v1_traces_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use IngestSpansRequest.ProtoReflect.Descriptor instead.
+func (*IngestSpansRequest) Descriptor() ([]byte, []int) {
+	return file_traces_v1_traces_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *IngestSpansRequest) GetSpans() []*Span {
+	if x != nil {
+		return x.Spans
+	}
+	return nil
+}
+
+type IngestSpansResponse struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	IngestedCount int32                  `protobuf:"varint,1,opt,name=ingested_count,json=ingestedCount,proto3" json:"ingested_count,omitempty"`
+	Traces        []*TraceSummary        `protobuf:"bytes,2,rep,name=traces,proto3" json:"traces,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *IngestSpansResponse) Reset() {
+	*x = IngestSpansResponse{}
+	mi := &file_traces_v1_traces_proto_msgTypes[3]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *IngestSpansResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*IngestSpansResponse) ProtoMessage() {}
+
+func (x *IngestSpansResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_traces_v1_traces_proto_msgTypes[3]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use IngestSpansResponse.ProtoReflect.Descriptor instead.
+func (*IngestSpansResponse) Descriptor() ([]byte, []int) {
+	return file_traces_v1_traces_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *IngestSpansResponse) GetIngestedCount() int32 {
+	if x != nil {
+		return x.IngestedCount
+	}
+	return 0
+}
+
+func (x *IngestSpansResponse) GetTraces() []*TraceSummary {
+	if x != nil {
+		return x.Traces
+	}
+	return nil
+}
+
+type GetTraceRequest struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	TraceId       string                 `protobuf:"bytes,1,opt,name=trace_id,json=traceId,proto3" json:"trace_id,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *GetTraceRequest) Reset() {
+	*x = GetTraceRequest{}
+	mi := &file_traces_v1_traces_proto_msgTypes[4]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *GetTraceRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetTraceRequest) ProtoMessage() {}
+
+func (x *GetTraceRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_traces_v1_traces_proto_msgTypes[4]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetTraceRequest.ProtoReflect.Descriptor instead.
+func (*GetTraceRequest) Descriptor() ([]byte, []int) {
+	return file_traces_v1_traces_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *GetTraceRequest) GetTraceId() string {
+	if x != nil {
+		return x.TraceId
+	}
+	return ""
+}
+
+type GetTraceResponse struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Trace         *TraceSummary          `protobuf:"bytes,1,opt,name=trace,proto3" json:"trace,omitempty"`
+	Spans         []*Span                `protobuf:"bytes,2,rep,name=spans,proto3" json:"spans,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *GetTraceResponse) Reset() {
+	*x = GetTraceResponse{}
+	mi := &file_traces_v1_traces_proto_msgTypes[5]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *GetTraceResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetTraceResponse) ProtoMessage() {}
+
+func (x *GetTraceResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_traces_v1_traces_proto_msgTypes[5]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetTraceResponse.ProtoReflect.Descriptor instead.
+func (*GetTraceResponse) Descriptor() ([]byte, []int) {
+	return file_traces_v1_traces_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *GetTraceResponse) GetTrace() *TraceSummary {
+	if x != nil {
+		return x.Trace
+	}
+	return nil
+}
+
+func (x *GetTraceResponse) GetSpans() []*Span {
+	if x != nil {
+		return x.Spans
+	}
+	return nil
+}
+
+type ListTracesRequest struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	WorkspaceId   string                 `protobuf:"bytes,1,opt,name=workspace_id,json=workspaceId,proto3" json:"workspace_id,omitempty"`
+	AgentId       string                 `protobuf:"bytes,2,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"`
+	Surface       string                 `protobuf:"bytes,3,opt,name=surface,proto3" json:"surface,omitempty"`
+	StartTime     *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"`
+	EndTime       *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=end_time,json=endTime,proto3" json:"end_time,omitempty"`
+	Limit         int32                  `protobuf:"varint,6,opt,name=limit,proto3" json:"limit,omitempty"`
+	Offset        int32                  `protobuf:"varint,7,opt,name=offset,proto3" json:"offset,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *ListTracesRequest) Reset() {
+	*x = ListTracesRequest{}
+	mi := &file_traces_v1_traces_proto_msgTypes[6]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *ListTracesRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ListTracesRequest) ProtoMessage() {}
+
+func (x *ListTracesRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_traces_v1_traces_proto_msgTypes[6]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ListTracesRequest.ProtoReflect.Descriptor instead.
+func (*ListTracesRequest) Descriptor() ([]byte, []int) {
+	return file_traces_v1_traces_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *ListTracesRequest) GetWorkspaceId() string {
+	if x != nil {
+		return x.WorkspaceId
+	}
+	return ""
+}
+
+func (x *ListTracesRequest) GetAgentId() string {
+	if x != nil {
+		return x.AgentId
+	}
+	return ""
+}
+
+func (x *ListTracesRequest) GetSurface() string {
+	if x != nil {
+		return x.Surface
+	}
+	return ""
+}
+
+func (x *ListTracesRequest) GetStartTime() *timestamppb.Timestamp {
+	if x != nil {
+		return x.StartTime
+	}
+	return nil
+}
+
+func (x *ListTracesRequest) GetEndTime() *timestamppb.Timestamp {
+	if x != nil {
+		return x.EndTime
+	}
+	return nil
+}
+
... diff truncated: showing 800 of 2200 lines

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit b634ac1. Configure here.

Comment thread descriptions.yaml
trace summaries with total count metadata.
SpanIngestService_GetSpanTree: >-
Retrieve a trace as a parent/child span tree. Used for execution debugging,
attribution, and governance review.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Traces descriptions split MeterService section in descriptions file

Low Severity

The new traces/v1 descriptions block is inserted between MeterService_GetUsageSummary and MeterService_GetMeterSummary, splitting the MeterService entries into two non-contiguous groups. All other service sections in this file keep their RPCs grouped together under a comment header. This breaks the organizational convention and makes it easy for future editors to miss that some MeterService entries live below the traces block.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b634ac1. Configure here.

@haasonsaas haasonsaas merged commit 52685f7 into main Apr 15, 2026
10 of 11 checks passed
@haasonsaas haasonsaas deleted the codex/traces-proto-bootstrap branch April 15, 2026 08:50
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.

1 participant