{
  "openapi": "3.1.1",
  "info": {
    "title": "CI/CD Failure Explorer API",
    "version": "1.0.0",
    "summary": "Paste CI logs from several runs: root cause per run, grouped signatures, top causes and fixes.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://cicdfailureexplorer.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Paste CI logs from several runs: root cause per run, grouped signatures, top causes and fixes.",
        "description": "Paste or upload logs of several GitHub Actions, GitLab CI or Jenkins runs (separated by \"=== run: name ===\" lines). Each run is classified by a documented pattern catalogue — test assertions (with test names), compile/type errors, dependency resolution, network/registry timeouts, OOM/exit 137, disk full, timeouts, lint, flaky retries, missing secrets/permissions — and runs are grouped by normalised error signature with counts per branch and day.\n\nMethodology:\n- Runs are split at lines \"=== run: <name> ===\" (header metadata branch=, date=, status= is honoured). ANSI colours, GitHub timestamp prefixes and GitLab section markers are stripped.\n- Platform is detected from runner markers (##[group]/##[error], \"Running with gitlab-runner\", \"[Pipeline]\"/\"Finished: …\"). Status comes from the header, then from terminal markers (Process completed with exit code, ERROR: Job failed, Finished: FAILURE/SUCCESS).\n- Every line is matched against a catalogue of documented error markers per cause. When several causes appear, the one with the highest causal priority wins: OOM/exit 137 → disk full → timeout → permission/secret → network → dependency → compile → lint → test → flaky → cancelled (e.g. a test crash after an OOM kill is reported as OOM).\n- The first matching line is the evidence; its normalised form (paths, SHAs, UUIDs, timestamps, IPs, line numbers and durations replaced by placeholders) is the signature used to group runs. Test failures are grouped by the sorted names of the failing tests.\n- Failing test names are extracted from jest/vitest (●/×), pytest (FAILED a::b), go test (--- FAIL), Maven Surefire ([ERROR] Class.method), Gradle (> … FAILED), TAP/node:test (not ok) and RSpec (rspec ./spec …).\n- Flaky suspects: tests that fail in some runs of a job but other runs of the same job (name without #number) pass, and passing runs that contain retry markers.\n- Unclassified failures are labelled with the closest match from the Error Message Translator pattern database when possible.",
        "tags": [
          "devcloud"
        ],
        "x-mcp-tool": "cicd_failure_explorer",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CicdFailureExplorerInput"
              },
              "examples": {
                "example1": {
                  "summary": "Eight runs across GitHub Actions, GitLab and Jenkins",
                  "value": {
                    "logs": "=== run: test #1841 | branch=main | date=2026-10-05T08:12:00Z ===\n2026-10-05T08:12:01.1000000Z Current runner version: '2.328.0'\n2026-10-05T08:12:03.2000000Z ##[group]Run npm test -- --ci\n2026-10-05T08:13:40.5000000Z FAIL src/cart/total.test.ts\n2026-10-05T08:13:40.5100000Z   ● Cart totals › applies discount codes\n2026-10-05T08:13:40.5200000Z     expect(received).toBe(expected) // Object.is equality\n2026-10-05T08:13:40.5300000Z     Expected: 90\n2026-10-05T08:13:40.5400000Z     Received: 100\n2026-10-05T08:13:41.0000000Z Tests:       1 failed, 211 passed, 212 total\n2026-10-05T08:13:41.2000000Z ##[error]Process completed with exit code 1.\n=== run: test #1842 | branch=feature/checkout | date=2026-10-05T11:40:00Z ===\n2026-10-05T11:40:02.0000000Z ##[group]Run npm test -- --ci\n2026-10-05T11:41:10.0000000Z FAIL src/cart/total.test.ts\n2026-10-05T11:41:10.1000000Z   ● Cart totals › applies discount codes\n2026-10-05T11:41:10.2000000Z     Expected: 90\n2026-10-05T11:41:10.3000000Z     Received: 100\n2026-10-05T11:41:11.0000000Z ##[error]Process completed with exit code 1.\n=== run: test #1843 | branch=main | date=2026-10-06T09:00:00Z ===\n2026-10-06T09:00:02.0000000Z ##[group]Run npm test -- --ci\n2026-10-06T09:01:30.0000000Z Tests:       212 passed, 212 total\n2026-10-06T09:01:31.0000000Z Process completed with exit code 0.\n=== run: build-image #77 | branch=main | date=2026-10-06T10:00:00Z ===\nRunning with gitlab-runner 18.4.0 (a1b2c3d4)\nUsing docker executor with image node:22 ...\n$ npm ci\nnpm ERR! code ETIMEDOUT\nnpm ERR! network request to https://registry.npmjs.org/react failed, reason: connect ETIMEDOUT 104.16.2.35:443\nERROR: Job failed: exit code 1\n=== run: build-image #78 | branch=main | date=2026-10-07T10:00:00Z ===\nRunning with gitlab-runner 18.4.0 (a1b2c3d4)\n$ npm ci\nnpm ERR! code ERESOLVE\nnpm ERR! ERESOLVE unable to resolve dependency tree\nnpm ERR! Could not resolve dependency: peer react@\"^18\" from react-beautiful-dnd@13.1.1\nERROR: Job failed: exit code 1\n=== run: integration | branch=release/2.4 | date=2026-10-07T22:15:00Z ===\nStarted by timer\n[Pipeline] { (Integration tests)\n+ ./gradlew integrationTest\n> Task :app:integrationTest\nGradle Test Executor 3 finished executing tests.\n/var/lib/jenkins/workspace/shop/run-tests.sh: line 12:  4121 Killed                  ./gradlew integrationTest\nscript returned exit code 137\nFinished: FAILURE\n=== run: test #1844 | branch=main | date=2026-10-08T09:00:00Z ===\n2026-10-08T09:00:02.0000000Z ##[group]Run npm test -- --ci\n2026-10-08T09:01:00.0000000Z jest-circus: retrying test \"Search › debounces input\" (attempt 2 of 3)\n2026-10-08T09:01:30.0000000Z Tests:       212 passed, 212 total\n2026-10-08T09:01:31.0000000Z Process completed with exit code 0.\n=== run: deploy #310 | branch=main | date=2026-10-08T12:00:00Z ===\n2026-10-08T12:00:05.0000000Z ##[group]Run aws-actions/configure-aws-credentials@v4\n2026-10-08T12:00:06.0000000Z ##[error]Credentials could not be loaded, please check your action inputs: Could not load credentials from any providers\n"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CicdFailureExplorerResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "CicdFailureExplorerInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "logs": {
            "title": "CI logs",
            "description": "Separate runs with a line \"=== run: <name> ===\". Optional metadata in the header: branch=…, date=YYYY-MM-DD, status=failed|passed. Without separators the whole paste is one run.",
            "type": "string",
            "maxLength": 400000
          },
          "file": {
            "title": "Or upload a log file",
            "description": "Plain-text log export (UTF-8). Combined with any pasted text. Upload as {filename, contentType?, contentBase64}. Max 2048 KiB. Accepts .txt,.log,text/plain.",
            "type": "object",
            "additionalProperties": false,
            "required": [
              "filename",
              "contentBase64"
            ],
            "properties": {
              "filename": {
                "type": "string"
              },
              "contentType": {
                "type": "string"
              },
              "contentBase64": {
                "type": "string"
              }
            }
          }
        },
        "required": []
      },
      "CicdFailureExplorerResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "runCount",
              "failedCount",
              "passedCount",
              "cancelledCount",
              "failureRate",
              "runs",
              "groups",
              "causes",
              "byBranch",
              "byDate",
              "flakySuspects"
            ],
            "properties": {
              "runCount": {
                "type": "integer",
                "minimum": 0
              },
              "failedCount": {
                "type": "integer",
                "minimum": 0
              },
              "passedCount": {
                "type": "integer",
                "minimum": 0
              },
              "cancelledCount": {
                "type": "integer",
                "minimum": 0
              },
              "failureRate": {
                "type": "number",
                "minimum": 0,
                "maximum": 1
              },
              "runs": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "name",
                    "platform",
                    "status",
                    "branch",
                    "date",
                    "cause",
                    "causeTitle",
                    "signature",
                    "evidence",
                    "evidenceLine",
                    "step",
                    "failedTests",
                    "secondaryCauses",
                    "retryMarkers",
                    "lineCount"
                  ],
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "platform": {
                      "type": "string",
                      "enum": [
                        "github-actions",
                        "gitlab-ci",
                        "jenkins",
                        "unknown"
                      ]
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "failed",
                        "passed",
                        "cancelled",
                        "unknown"
                      ]
                    },
                    "branch": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "date": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "cause": {
                      "type": "string",
                      "enum": [
                        "oom",
                        "disk-full",
                        "timeout",
                        "permission-secret",
                        "network",
                        "dependency",
                        "compile",
                        "lint",
                        "test-failure",
                        "flaky-retry",
                        "cancelled",
                        "unknown",
                        "none"
                      ]
                    },
                    "causeTitle": {
                      "type": "string"
                    },
                    "signature": {
                      "type": "string"
                    },
                    "evidence": {
                      "type": "string"
                    },
                    "evidenceLine": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "step": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "failedTests": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "secondaryCauses": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "retryMarkers": {
                      "type": "integer",
                      "minimum": 0
                    },
                    "lineCount": {
                      "type": "integer",
                      "minimum": 0
                    }
                  }
                }
              },
              "groups": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "cause",
                    "causeTitle",
                    "signature",
                    "count",
                    "runs",
                    "branches",
                    "firstSeen",
                    "lastSeen"
                  ],
                  "properties": {
                    "cause": {
                      "type": "string"
                    },
                    "causeTitle": {
                      "type": "string"
                    },
                    "signature": {
                      "type": "string"
                    },
                    "count": {
                      "type": "integer",
                      "minimum": 1
                    },
                    "runs": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "branches": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "firstSeen": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "lastSeen": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              },
              "causes": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "cause",
                    "title",
                    "count",
                    "share",
                    "fixes"
                  ],
                  "properties": {
                    "cause": {
                      "type": "string"
                    },
                    "title": {
                      "type": "string"
                    },
                    "count": {
                      "type": "integer"
                    },
                    "share": {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 1
                    },
                    "fixes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "byBranch": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "branch",
                    "runs",
                    "failed"
                  ],
                  "properties": {
                    "branch": {
                      "type": "string"
                    },
                    "runs": {
                      "type": "integer"
                    },
                    "failed": {
                      "type": "integer"
                    }
                  }
                }
              },
              "byDate": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "date",
                    "runs",
                    "failed"
                  ],
                  "properties": {
                    "date": {
                      "type": "string"
                    },
                    "runs": {
                      "type": "integer"
                    },
                    "failed": {
                      "type": "integer"
                    }
                  }
                }
              },
              "flakySuspects": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "test",
                    "job",
                    "failedRuns",
                    "passedRuns",
                    "reason"
                  ],
                  "properties": {
                    "test": {
                      "type": "string"
                    },
                    "job": {
                      "type": "string"
                    },
                    "failedRuns": {
                      "type": "integer"
                    },
                    "passedRuns": {
                      "type": "integer"
                    },
                    "reason": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}