openapi: "3.1.0"
info:
  title: "PlatPhorm Trace Observatory API"
  version: "0.0.2"
  description: "Canonical PlatPhormNews observability API for W3C trace context, trace ingestion, span lifecycle, async jobs, aggregation, public-safe evidence, and MCP Trace Observatory tools. Public reads are open; protected ingestion and mutations require PLATPHORM_API_KEY."
  contact:
    name: "Michael Barbine"
    url: "https://platphormnews.com"
  license:
    name: "MIT"
    url: "https://opensource.org/licenses/MIT"
  x-logo:
    url: "https://trace.platphormnews.com/icon-512.png"
servers:
  - url: "https://trace.platphormnews.com/api/v1"
    description: "Production API"
tags:
  - name: "traces"
    description: "Trace ingestion and retrieval"
  - name: "sessions"
    description: "Session management and aggregation"
  - name: "spans"
    description: "Span lifecycle start, heartbeat, completion, failure, and late/orphan handling"
  - name: "async"
    description: "Async trace and job lifecycle APIs"
  - name: "aggregation"
    description: "Public-safe trace aggregation, latency, service, propagation, and correlation summaries"
  - name: "mcp"
    description: "JSON-RPC MCP Trace Observatory endpoint"
  - name: "analysis"
    description: "AI-powered trace analysis"
  - name: "export"
    description: "Trace export and sharing"
  - name: "live"
    description: "Real-time trace streaming"
  - name: "network"
    description: "Trusted-domain and route-compliance visibility"
  - name: "health"
    description: "API health and status"
paths:
  /traces:
    get:
      tags:
        - "traces"
      summary: "List traces"
      description: "List all public traces with optional filtering"
      operationId: "listTraces"
      parameters:
        - name: "page"
          in: "query"
          schema:
            type: "integer"
            default: 1
        - name: "limit"
          in: "query"
          schema:
            type: "integer"
            default: 20
            maximum: 100
        - name: "status"
          in: "query"
          schema:
            type: "string"
            enum:
              - "running"
              - "completed"
              - "error"
              - "timeout"
        - name: "agent"
          in: "query"
          schema:
            type: "string"
          description: "Filter by agent name (partial match)"
        - name: "min_health"
          in: "query"
          schema:
            type: "integer"
            minimum: 0
            maximum: 100
        - name: "max_health"
          in: "query"
          schema:
            type: "integer"
            minimum: 0
            maximum: 100
        - name: "domain"
          in: "query"
          schema:
            type: "string"
          description: "Filter by source domain"
        - name: "tag"
          in: "query"
          schema:
            type: "string"
          description: "Filter by tag"
        - name: "q"
          in: "query"
          schema:
            type: "string"
          description: "Search name/description"
      responses:
        200:
          description: "List of traces"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TraceListResponse"
    post:
      tags:
        - "traces"
      summary: "Create trace"
      description: "Ingest a new trace. The trace envelope is stored when authenticated storage succeeds; durable span rows are written only for batches with more than one tool call."
      operationId: "createTrace"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateTraceRequest"
      responses:
        201:
          description: "Trace created"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateTraceResponse"
        400:
          description: "Invalid request body"
        429:
          description: "Rate limit exceeded"
  /sessions:
    get:
      tags:
        - "sessions"
      summary: "List sessions"
      description: "List all unique sessions with aggregated stats"
      operationId: "listSessions"
      parameters:
        - name: "page"
          in: "query"
          schema:
            type: "integer"
            default: 1
        - name: "limit"
          in: "query"
          schema:
            type: "integer"
            default: 20
            maximum: 100
        - name: "domain"
          in: "query"
          schema:
            type: "string"
          description: "Filter by source domain"
        - name: "agent"
          in: "query"
          schema:
            type: "string"
          description: "Filter by agent name"
      responses:
        200:
          description: "List of sessions"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SessionListResponse"
  /sessions/{sessionId}:
    get:
      tags:
        - "sessions"
      summary: "Get session"
      description: "Get all traces for a session with optional span data"
      operationId: "getSession"
      parameters:
        - name: "sessionId"
          in: "path"
          required: true
          schema:
            type: "string"
        - name: "include_spans"
          in: "query"
          schema:
            type: "boolean"
            default: false
        - name: "page"
          in: "query"
          schema:
            type: "integer"
            default: 1
        - name: "limit"
          in: "query"
          schema:
            type: "integer"
            default: 50
            maximum: 100
      responses:
        200:
          description: "Session details with traces"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SessionResponse"
        404:
          description: "Session not found"
  /traces/{traceId}:
    get:
      tags:
        - "traces"
      summary: "Get trace"
      description: "Get a trace with all spans, annotations, and forks"
      operationId: "getTrace"
      parameters:
        - name: "traceId"
          in: "path"
          required: true
          schema:
            type: "string"
      responses:
        200:
          description: "Trace details"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Trace"
        404:
          description: "Trace not found"
  /traces/{traceId}/spans:
    get:
      tags:
        - "spans"
      summary: "List trace spans"
      description: "List public-safe spans for a trace"
      operationId: "listTraceSpans"
      parameters:
        - name: "traceId"
          in: "path"
          required: true
          schema:
            type: "string"
      responses:
        200:
          description: "Trace spans"
        404:
          description: "Trace not found"
    post:
      tags:
        - "spans"
      summary: "Append spans"
      description: "Append spans to a running trace"
      operationId: "appendSpans"
      parameters:
        - name: "traceId"
          in: "path"
          required: true
          schema:
            type: "string"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AppendSpansRequest"
      responses:
        200:
          description: "Spans appended"
        404:
          description: "Trace not found"
  /traces/{traceId}/timeline:
    get:
      tags:
        - "traces"
      summary: "Trace timeline"
      description: "Build a timestamp-sorted timeline from real public-safe spans."
      operationId: "getTraceTimeline"
      parameters:
        - name: "traceId"
          in: "path"
          required: true
          schema:
            type: "string"
      responses:
        200:
          description: "Timeline view"
        404:
          description: "Trace not found"
  /traces/{traceId}/tree:
    get:
      tags:
        - "traces"
      summary: "Trace tree"
      description: "Build a parent-child tree from span parent relationships."
      operationId: "getTraceTree"
      parameters:
        - name: "traceId"
          in: "path"
          required: true
          schema:
            type: "string"
      responses:
        200:
          description: "Tree view"
        404:
          description: "Trace not found"
  /traces/{traceId}/waterfall:
    get:
      tags:
        - "traces"
      summary: "Trace waterfall"
      description: "Build a waterfall view from real span timing."
      operationId: "getTraceWaterfall"
      parameters:
        - name: "traceId"
          in: "path"
          required: true
          schema:
            type: "string"
      responses:
        200:
          description: "Waterfall view"
        404:
          description: "Trace not found"
  /traces/{traceId}/service-map:
    get:
      tags:
        - "aggregation"
      summary: "Trace service map"
      description: "Build public-safe service hop map from source and target span attributes."
      operationId: "getTraceServiceMap"
      parameters:
        - name: "traceId"
          in: "path"
          required: true
          schema:
            type: "string"
      responses:
        200:
          description: "Service map"
        404:
          description: "Trace not found"
  /traces/{traceId}/critical-path:
    get:
      tags:
        - "aggregation"
      summary: "Trace critical path"
      description: "Calculate critical path from real public-safe span durations."
      operationId: "getTraceCriticalPath"
      parameters:
        - name: "traceId"
          in: "path"
          required: true
          schema:
            type: "string"
      responses:
        200:
          description: "Critical path"
        404:
          description: "Trace not found"
  /traces/{traceId}/completion:
    get:
      tags:
        - "spans"
      summary: "Trace completion"
      description: "Return recomputable completion state, missing spans, pending spans, late spans, orphan spans, failed spans, and algorithm version."
      operationId: "getTraceCompletion"
      parameters:
        - name: "traceId"
          in: "path"
          required: true
          schema:
            type: "string"
      responses:
        200:
          description: "Completion state"
        404:
          description: "Trace not found"
  /traces/{traceId}/complete:
    post:
      tags:
        - "spans"
      summary: "Complete trace"
      description: "Protected recomputation and persistence of trace completion. Requires PLATPHORM_API_KEY."
      operationId: "completeTrace"
      security:
        - ApiKey:
[]
        - PlatphormApiKey:
[]
      parameters:
        - name: "traceId"
          in: "path"
          required: true
          schema:
            type: "string"
      responses:
        200:
          description: "Completion recomputed"
        401:
          description: "PLATPHORM_API_KEY required"
  /spans/start:
    post:
      tags:
        - "spans"
      summary: "Start span"
      description: "Protected span start or late-span attachment. Requires PLATPHORM_API_KEY."
      operationId: "startSpan"
      security:
        - ApiKey:
[]
        - PlatphormApiKey:
[]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SpanLifecycleRequest"
      responses:
        201:
          description: "Span started"
        401:
          description: "PLATPHORM_API_KEY required"
        503:
          description: "Storage degraded"
  /spans/complete:
    post:
      tags:
        - "spans"
      summary: "Complete span"
      description: "Protected span completion and trace lifecycle recomputation."
      operationId: "completeSpan"
      security:
        - ApiKey:
[]
        - PlatphormApiKey:
[]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SpanLifecycleRequest"
      responses:
        200:
          description: "Span completed"
        401:
          description: "PLATPHORM_API_KEY required"
  /spans/fail:
    post:
      tags:
        - "spans"
      summary: "Fail span"
      description: "Protected span failure and trace lifecycle recomputation."
      operationId: "failSpan"
      security:
        - ApiKey:
[]
        - PlatphormApiKey:
[]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SpanLifecycleRequest"
      responses:
        200:
          description: "Span failed"
        401:
          description: "PLATPHORM_API_KEY required"
  /spans/heartbeat:
    post:
      tags:
        - "spans"
      summary: "Heartbeat span"
      description: "Protected heartbeat for running spans and async workflows."
      operationId: "heartbeatSpan"
      security:
        - ApiKey:
[]
        - PlatphormApiKey:
[]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SpanLifecycleRequest"
      responses:
        200:
          description: "Heartbeat recorded"
        401:
          description: "PLATPHORM_API_KEY required"
  /spans/annotate:
    post:
      tags:
        - "spans"
      summary: "Annotate span"
      description: "Protected redacted span annotation. Requires PLATPHORM_API_KEY."
      operationId: "annotateSpan"
      security:
        - ApiKey:
[]
        - PlatphormApiKey:
[]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SpanLifecycleRequest"
      responses:
        200:
          description: "Span annotated"
        401:
          description: "PLATPHORM_API_KEY required"
  /spans/cancel:
    post:
      tags:
        - "spans"
      summary: "Cancel span"
      description: "Protected span cancellation and trace lifecycle recomputation."
      operationId: "cancelSpan"
      security:
        - ApiKey:
[]
        - PlatphormApiKey:
[]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SpanLifecycleRequest"
      responses:
        200:
          description: "Span cancelled"
        401:
          description: "PLATPHORM_API_KEY required"
  /async/traces:
    post:
      tags:
        - "async"
      summary: "Create async trace"
      description: "Protected async trace envelope. Returns poll, stream, and completion URLs when durable storage is configured."
      operationId: "createAsyncTrace"
      security:
        - ApiKey:
[]
        - PlatphormApiKey:
[]
      responses:
        201:
          description: "Async trace created"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AsyncCreateResponse"
        503:
          description: "Storage degraded"
  /async/jobs:
    get:
      tags:
        - "async"
      summary: "List async jobs"
      operationId: "listAsyncJobs"
      responses:
        200:
          description: "Public-safe async job list or degraded empty state"
    post:
      tags:
        - "async"
      summary: "Create async job"
      description: "Protected trace-linked async job creation."
      operationId: "createAsyncJob"
      security:
        - ApiKey:
[]
        - PlatphormApiKey:
[]
      responses:
        201:
          description: "Async job created"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AsyncCreateResponse"
        401:
          description: "PLATPHORM_API_KEY required"
  /jobs:
    get:
      tags:
        - "async"
      summary: "List async jobs"
      description: "Alias for /async/jobs."
      operationId: "listJobs"
      responses:
        200:
          description: "Public-safe job list or degraded empty state"
    post:
      tags:
        - "async"
      summary: "Create async job"
      description: "Alias for protected /async/jobs creation."
      operationId: "createJob"
      security:
        - ApiKey:
[]
        - PlatphormApiKey:
[]
      responses:
        201:
          description: "Async job created"
        401:
          description: "PLATPHORM_API_KEY required"
  /evidence:
    get:
      tags:
        - "export"
      summary: "List public-safe evidence"
      description: "List redacted public-safe evidence records."
      operationId: "listEvidence"
      responses:
        200:
          description: "Evidence list"
    post:
      tags:
        - "export"
      summary: "Link evidence"
      description: "Protected evidence linking. Requires PLATPHORM_API_KEY. Raw private evidence is not exposed publicly."
      operationId: "linkEvidence"
      security:
        - ApiKey:
[]
        - PlatphormApiKey:
[]
      responses:
        201:
          description: "Evidence linked"
        401:
          description: "PLATPHORM_API_KEY required"
  /search:
    get:
      tags:
        - "traces"
      summary: "Search Trace records"
      description: "Search public-safe traces, spans, evidence, and playbooks."
      operationId: "searchTraceRecords"
      parameters:
        - name: "q"
          in: "query"
          schema:
            type: "string"
      responses:
        200:
          description: "Search results or degraded empty state"
  /observatory:
    get:
      tags:
        - "health"
      summary: "Trace truth model"
      description: "Homepage truth model with value, source, sourceUrl, fetchedAt, state, and nextAction for every metric."
      operationId: "getTraceTruthModel"
      responses:
        200:
          description: "Trace truth model"
  /integrations/status:
    get:
      tags:
        - "network"
      summary: "Integration status"
      description: "Phase 4 integration matrix. Observed means persisted public-safe spans exist; registered and unknown do not count as connected."
      operationId: "getIntegrationStatus"
      responses:
        200:
          description: "Integration matrix"
  /playbooks:
    get:
      tags:
        - "analysis"
      summary: "Debugging playbooks"
      description: "Deterministic Trace debugging playbooks with checks, commands, linked tools, and evidence to collect."
      operationId: "listDebuggingPlaybooks"
      responses:
        200:
          description: "Playbook list"
  /reports/trace-summary:
    post:
      tags:
        - "export"
      summary: "Create trace summary report"
      description: "Create a public-safe report from persisted Trace evidence. Missing evidence is reported as missing, not fabricated."
      operationId: "createTraceSummaryReport"
      responses:
        200:
          description: "Public-safe report"
  /aggregate/summary:
    get:
      tags:
        - "aggregation"
      summary: "Trace aggregate summary"
      description: "Lifecycle, ingestion, latency, service, propagation, and JA4 hashed/redacted correlation coverage."
      operationId: "getAggregateSummary"
      responses:
        200:
          description: "Aggregate summary"
  /mcp:
    post:
      tags:
        - "mcp"
      summary: "MCP JSON-RPC endpoint"
      description: "JSON-RPC 2.0 endpoint supporting initialize, ping, tools/list, tools/call, resources/list, resources/read, prompts/list, and prompts/get."
      operationId: "mcpJsonRpc"
      responses:
        200:
          description: "JSON-RPC response"
  /traces/{traceId}/analyze:
    post:
      tags:
        - "analysis"
      summary: "Analyze trace"
      description: "Run AI analysis on a trace"
      operationId: "analyzeTrace"
      parameters:
        - name: "traceId"
          in: "path"
          required: true
          schema:
            type: "string"
      responses:
        200:
          description: "Analysis results"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AnalysisResult"
  /traces/{traceId}/fork:
    post:
      tags:
        - "analysis"
      summary: "Fork trace"
      description: "Create a time-travel fork from a specific span"
      operationId: "forkTrace"
      parameters:
        - name: "traceId"
          in: "path"
          required: true
          schema:
            type: "string"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ForkRequest"
      responses:
        201:
          description: "Fork created"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ForkResponse"
  /traces/{traceId}/export:
    get:
      tags:
        - "export"
      summary: "Export trace"
      description: "Export trace in various formats"
      operationId: "exportTrace"
      parameters:
        - name: "traceId"
          in: "path"
          required: true
          schema:
            type: "string"
        - name: "format"
          in: "query"
          schema:
            type: "string"
            enum:
              - "json"
              - "markdown"
              - "postmortem"
              - "otel"
            default: "json"
        - name: "plain_english"
          in: "query"
          schema:
            type: "boolean"
            default: false
      responses:
        200:
          description: "Exported trace"
          content:
            application/json:

            text/markdown:

  /traces/{traceId}/annotations:
    post:
      tags:
        - "traces"
      summary: "Add annotation"
      description: "Add a collaborative annotation to a trace"
      operationId: "addAnnotation"
      parameters:
        - name: "traceId"
          in: "path"
          required: true
          schema:
            type: "string"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateAnnotationRequest"
      responses:
        201:
          description: "Annotation added"
  /traces/compare:
    get:
      tags:
        - "analysis"
      summary: "Compare traces"
      description: "Compare two traces side-by-side"
      operationId: "compareTraces"
      parameters:
        - name: "trace_a"
          in: "query"
          required: true
          schema:
            type: "string"
        - name: "trace_b"
          in: "query"
          required: true
          schema:
            type: "string"
      responses:
        200:
          description: "Comparison results"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompareResult"
  /live:
    get:
      tags:
        - "live"
      summary: "Live feed"
      description: "Get real-time trace feed with network stats"
      operationId: "getLiveFeed"
      responses:
        200:
          description: "Live feed data"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LiveFeedResponse"
  /stats:
    get:
      tags:
        - "health"
      summary: "Network stats"
      description: "Get network-wide statistics"
      operationId: "getStats"
      responses:
        200:
          description: "Statistics"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/StatsResponse"
  /network/route-compliance/run:
    post:
      tags:
        - "network"
      summary: "Run route compliance probe"
      description: "Protected bounded route probe for one trusted *.platphormnews.com domain. Results are returned and may be cached ephemerally when durable route-compliance storage is not configured."
      operationId: "runRouteComplianceProbe"
      security:
        - ApiKey:
[]
        - PlatphormApiKey:
[]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                slug:
                  type: "string"
                domain:
                  type: "string"
                timeoutMs:
                  type: "integer"
                  minimum: 1000
                  maximum: 10000
                concurrency:
                  type: "integer"
                  minimum: 1
                  maximum: 6
              anyOf:
                - required:
                    - "slug"
                - required:
                    - "domain"
      responses:
        202:
          description: "Route probe completed with public-safe route evidence."
          content:
            application/json:
              schema:
                type: "object"
        400:
          description: "Invalid or untrusted probe target"
        401:
          description: "PLATPHORM_API_KEY required"
components:
  schemas:
    Trace:
      type: "object"
      properties:
        trace_id:
          type: "string"
        name:
          type: "string"
        description:
          type: "string"
          nullable: true
        agent_name:
          type: "string"
          nullable: true
        model_name:
          type: "string"
          nullable: true
        status:
          type: "string"
          enum:
            - "running"
            - "completed"
            - "error"
            - "timeout"
        start_time:
          type: "string"
          format: "date-time"
        end_time:
          type: "string"
          format: "date-time"
          nullable: true
        duration_ms:
          type: "integer"
          nullable: true
        total_spans:
          type: "integer"
        total_tool_calls:
          type: "integer"
        error_count:
          type: "integer"
        ai_health_score:
          type: "integer"
          minimum: 0
          maximum: 100
          nullable: true
        ai_summary:
          type: "string"
          nullable: true
        tags:
          type: "array"
          items:
            type: "string"
        spans:
          type: "array"
          items:
            $ref: "#/components/schemas/Span"
        annotations:
          type: "array"
          items:
            $ref: "#/components/schemas/Annotation"
    Span:
      type: "object"
      properties:
        span_id:
          type: "string"
        parent_span_id:
          type: "string"
          nullable: true
        name:
          type: "string"
        kind:
          type: "string"
        start_time:
          type: "string"
          format: "date-time"
        end_time:
          type: "string"
          format: "date-time"
          nullable: true
        duration_ms:
          type: "integer"
          nullable: true
        status:
          type: "string"
          enum:
            - "ok"
            - "error"
            - "unset"
        gen_ai_tool_name:
          type: "string"
          nullable: true
        gen_ai_tool_call_arguments:
          type: "object"
          nullable: true
        gen_ai_tool_call_result:
          type: "object"
          nullable: true
    SpanLifecycleRequest:
      type: "object"
      required:
        - "traceId"
      properties:
        traceId:
          type: "string"
          description: "Trace ID or W3C trace ID."
        spanId:
          type: "string"
          description: "Span ID. W3C span IDs are accepted."
        parentSpanId:
          type: "string"
          nullable: true
        name:
          type: "string"
        kind:
          type: "string"
          enum:
            - "internal"
            - "server"
            - "client"
            - "producer"
            - "consumer"
            - "tool"
            - "api"
            - "browser"
            - "sandbox"
            - "eval"
            - "agent"
            - "workflow"
        sourceSite:
          type: "string"
        targetSite:
          type: "string"
        startTime:
          type: "string"
          format: "date-time"
        endTime:
          type: "string"
          format: "date-time"
        deadlineAt:
          type: "string"
          format: "date-time"
        heartbeatAt:
          type: "string"
          format: "date-time"
        isExpected:
          type: "boolean"
        isOptional:
          type: "boolean"
        isLate:
          type: "boolean"
        metadata:
          type: "object"
          description: "Redacted before public display. Do not include secrets."
    TraceCompletion:
      type: "object"
      properties:
        completionStatus:
          type: "string"
          enum:
            - "pending"
            - "active"
            - "waiting_for_spans"
            - "partially_complete"
            - "completed"
            - "failed"
            - "cancelled"
            - "timed_out"
            - "degraded"
            - "orphaned"
            - "unknown"
        reason:
          type: "string"
        algorithmVersion:
          type: "string"
        expectedSpans:
          type: "array"
          items:
            type: "string"
        missingSpans:
          type: "array"
          items:
            type: "string"
        lateSpans:
          type: "array"
          items:
            type: "string"
        orphanSpans:
          type: "array"
          items:
            type: "string"
        failedSpans:
          type: "array"
          items:
            type: "string"
    AsyncCreateResponse:
      type: "object"
      properties:
        ok:
          type: "boolean"
        data:
          type: "object"
          properties:
            id:
              type: "string"
            status:
              type: "string"
              enum:
                - "queued"
                - "claimed"
                - "running"
                - "waiting"
                - "completed"
                - "failed"
                - "cancelled"
                - "timed_out"
                - "degraded"
            traceId:
              type: "string"
            pollUrl:
              type: "string"
            streamUrl:
              type: "string"
            completionUrl:
              type: "string"
            expiresAt:
              type: "string"
              nullable: true
    Annotation:
      type: "object"
      properties:
        id:
          type: "string"
        span_id:
          type: "string"
          nullable: true
        author_name:
          type: "string"
        content:
          type: "string"
        annotation_type:
          type: "string"
          enum:
            - "comment"
            - "issue"
            - "suggestion"
            - "ai_generated"
        is_resolved:
          type: "boolean"
        created_at:
          type: "string"
          format: "date-time"
    Session:
      type: "object"
      properties:
        session_id:
          type: "string"
        source_domain:
          type: "string"
          nullable: true
        started_at:
          type: "string"
          format: "date-time"
          nullable: true
        last_activity:
          type: "string"
          format: "date-time"
          nullable: true
        stats:
          $ref: "#/components/schemas/SessionStats"
        agents:
          type: "array"
          items:
            type: "string"
        models:
          type: "array"
          items:
            type: "string"
    SessionStats:
      type: "object"
      properties:
        trace_count:
          type: "integer"
        total_spans:
          type: "integer"
        total_tool_calls:
          type: "integer"
        total_tokens:
          type: "integer"
        total_errors:
          type: "integer"
        avg_health_score:
          type: "integer"
          nullable: true
        status_breakdown:
          type: "object"
          properties:
            running:
              type: "integer"
            completed:
              type: "integer"
            error:
              type: "integer"
            timeout:
              type: "integer"
    SessionListResponse:
      type: "object"
      properties:
        success:
          type: "boolean"
        data:
          type: "array"
          items:
            $ref: "#/components/schemas/Session"
        pagination:
          type: "object"
          properties:
            page:
              type: "integer"
            limit:
              type: "integer"
            total:
              type: "integer"
            total_pages:
              type: "integer"
            has_more:
              type: "boolean"
    SessionResponse:
      type: "object"
      properties:
        success:
          type: "boolean"
        data:
          type: "object"
          properties:
            session:
              $ref: "#/components/schemas/Session"
            stats:
              $ref: "#/components/schemas/SessionStats"
            traces:
              type: "array"
              items:
                $ref: "#/components/schemas/Trace"
        pagination:
          type: "object"
          properties:
            page:
              type: "integer"
            limit:
              type: "integer"
            total:
              type: "integer"
            total_pages:
              type: "integer"
            has_more:
              type: "boolean"
    CreateTraceRequest:
      type: "object"
      required:
        - "name"
        - "startTime"
      properties:
        name:
          type: "string"
        description:
          type: "string"
        agentName:
          type: "string"
        modelName:
          type: "string"
        startTime:
          type: "string"
          format: "date-time"
        endTime:
          type: "string"
          format: "date-time"
        status:
          type: "string"
          enum:
            - "running"
            - "completed"
            - "error"
            - "timeout"
          default: "running"
        spans:
          type: "array"
          description: "Received spans are evaluated by the multi-tool persistence policy. Durable span rows are written only when the batch contains more than one tool call."
          items:
            $ref: "#/components/schemas/CreateSpanRequest"
        tags:
          type: "array"
          items:
            type: "string"
        metadata:
          type: "object"
    CreateSpanRequest:
      type: "object"
      required:
        - "name"
        - "startTime"
      properties:
        name:
          type: "string"
        startTime:
          type: "string"
          format: "date-time"
        endTime:
          type: "string"
          format: "date-time"
        kind:
          type: "string"
          default: "INTERNAL"
        genAiToolName:
          type: "string"
        genAiToolCallArguments:
          type: "object"
        genAiToolCallResult:
          type: "object"
        status:
          type: "string"
          enum:
            - "ok"
            - "error"
            - "unset"
          default: "unset"
        errorMessage:
          type: "string"
    CreateTraceResponse:
      type: "object"
      properties:
        success:
          type: "boolean"
        data:
          type: "object"
          properties:
            trace_id:
              type: "string"
            share_token:
              type: "string"
            share_url:
              type: "string"
            status:
              type: "string"
            spans_ingested:
              type: "integer"
              description: "Durable span rows persisted under the multi-tool span policy."
            spans_received:
              type: "integer"
              description: "Total spans accepted in the request payload."
            spans_skipped:
              type: "integer"
              description: "Spans accepted but intentionally not persisted as durable span rows."
            span_persistence_policy:
              type: "string"
            span_persistence_reason:
              type: "string"
    TraceListResponse:
      type: "object"
      properties:
        success:
          type: "boolean"
        data:
          type: "object"
          properties:
            traces:
              type: "array"
              items:
                $ref: "#/components/schemas/Trace"
            pagination:
              type: "object"
              properties:
                page:
                  type: "integer"
                limit:
                  type: "integer"
                total:
                  type: "integer"
                hasMore:
                  type: "boolean"
    AppendSpansRequest:
      type: "object"
      required:
        - "spans"
      properties:
        spans:
          type: "array"
          items:
            $ref: "#/components/schemas/CreateSpanRequest"
    ForkRequest:
      type: "object"
      required:
        - "span_id"
      properties:
        span_id:
          type: "string"
        changes:
          type: "object"
          properties:
            arguments:
              type: "object"
    ForkResponse:
      type: "object"
      properties:
        success:
          type: "boolean"
        data:
          type: "object"
          properties:
            fork_id:
              type: "string"
            forked_trace_id:
              type: "string"
            comparison_url:
              type: "string"
    AnalysisResult:
      type: "object"
      properties:
        health_score:
          type: "integer"
          minimum: 0
          maximum: 100
        summary:
          type: "string"
        anomalies:
          type: "array"
          items:
            type: "object"
        suggestions:
          type: "array"
          items:
            type: "string"
        network_percentile:
          type: "integer"
    CompareResult:
      type: "object"
      properties:
        trace_a:
          $ref: "#/components/schemas/Trace"
        trace_b:
          $ref: "#/components/schemas/Trace"
        differences:
          type: "array"
          items:
            type: "object"
        summary:
          type: "string"
    CreateAnnotationRequest:
      type: "object"
      required:
        - "content"
        - "author_name"
      properties:
        span_id:
          type: "string"
        author_name:
          type: "string"
        content:
          type: "string"
        annotation_type:
          type: "string"
          enum:
            - "comment"
            - "issue"
            - "suggestion"
          default: "comment"
    LiveFeedResponse:
      type: "object"
      properties:
        traces:
          type: "array"
          items:
            $ref: "#/components/schemas/Trace"
        stats:
          type: "object"
          properties:
            active_traces:
              type: "integer"
            traces_per_minute:
              type: "number"
            avg_health_score:
              type: "number"
            error_rate:
              type: "number"
    StatsResponse:
      type: "object"
      properties:
        network:
          type: "object"
          properties:
            total_sites:
              type: "integer"
            mcp_enabled_sites:
              type: "integer"
            tools:
              type: "integer"
            resources:
              type: "integer"
            prompts:
              type: "integer"
        traces:
          type: "object"
          properties:
            total:
              type: "integer"
            today:
              type: "integer"
            avg_health_score:
              type: "number"
            avg_duration_ms:
              type: "number"
  securitySchemes:
    ApiKey:
      type: "http"
      scheme: "bearer"
      description: "Protected actions use Authorization: Bearer $PLATPHORM_API_KEY"
    PlatphormApiKey:
      type: "apiKey"
      in: "header"
      name: "X-PlatPhorm-API-Key"
      description: "Protected actions may also use X-PlatPhorm-API-Key: $PLATPHORM_API_KEY"
security:
  - 
  - ApiKey:
[]
