{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://github.com/{owner}/multi-agent-pipeline/pipeline/schemas/complaint-analysis-spec.schema.json",
  "version": "1.0.0",
  "title": "Multi-Agent Pipeline - /multi-agent:complaint-analysis run state",
  "description": "Contract for state.complaintSpec, the run state of the customer-complaint triage command. Complaints arrive redacted (parse-complaints.sh strips PII before anything lands here), each one carries its Graylog evidence status, repo evidence rows, and a triage verdict: client / bff (our responsibility, root-cause analysis) or core (routing recommendation only) or insufficient-evidence.",
  "type": "object",
  "additionalProperties": false,
  "required": ["runName", "language", "repos", "complaints"],
  "properties": {
    "runName": {
      "type": "string",
      "minLength": 1,
      "description": "Run name supplied by the user or defaulted to complaints-<YYYYMMDD>."
    },
    "phase": {
      "type": "string",
      "enum": [
        "intake",
        "fetching_graylog",
        "correlating_repos",
        "triaging",
        "drafting",
        "awaiting_output_decision",
        "dispatching",
        "reporting",
        "done"
      ],
      "description": "Resume marker. Set after each phase boundary."
    },
    "language": {
      "type": "string",
      "enum": ["tr", "en"],
      "description": "Report body language, resolved from prefs.global.outputLanguage."
    },
    "account": {
      "type": ["string", "null"],
      "description": "Account id resolved by the account picker; null for local-only flows."
    },
    "repos": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["name", "layer"],
        "properties": {
          "name": { "type": "string", "minLength": 1 },
          "layer": {
            "type": "string",
            "enum": ["ios", "android", "web", "mobile-bff", "web-bff", "other"],
            "description": "User-confirmed layer tag (Phase 0 Step 3b). core is NOT a layer here - it is the residual verdict, not a repo."
          },
          "localPath": { "type": ["string", "null"] },
          "provider": { "type": ["string", "null"] }
        }
      },
      "description": "Repos selected in the multi-select picker, each tagged with the layer it implements."
    },
    "input": {
      "type": "object",
      "additionalProperties": false,
      "required": ["sources", "complaintCount", "redacted"],
      "properties": {
        "sources": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["type"],
            "properties": {
              "type": { "type": "string", "enum": ["file", "paste", "jira", "confluence"] },
              "ref": {
                "type": ["string", "null"],
                "description": "File path, Jira issue key, or Confluence URL. null for paste."
              },
              "format": {
                "type": ["string", "null"],
                "enum": ["csv", "xlsx", "txt", "json", "text", null]
              }
            }
          }
        },
        "complaintCount": { "type": "integer", "minimum": 0 },
        "redacted": {
          "type": "boolean",
          "description": "Must be true for any run that dispatches output; only --no-redact debug runs of parse-complaints.sh produce false."
        }
      }
    },
    "complaints": {
      "type": "array",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["id", "textRedacted"],
        "properties": {
          "id": { "type": "string", "pattern": "^C-[0-9]{2,}$" },
          "textRedacted": { "type": "string", "minLength": 1 },
          "trxId": { "type": ["string", "null"] },
          "convId": { "type": ["string", "null"] },
          "date": { "type": ["string", "null"] },
          "platformHint": { "type": ["string", "null"] },
          "skipGraylog": {
            "type": "boolean",
            "default": false,
            "description": "True when the user explicitly marked the complaint skip-graylog at the Phase 0 Step 5 id-confirmation loop."
          },
          "graylog": {
            "type": "object",
            "additionalProperties": false,
            "required": ["status"],
            "properties": {
              "status": { "type": "string", "enum": ["pending", "ok", "degraded", "skipped"] },
              "totalResults": { "type": "integer", "minimum": 0 },
              "degradeReason": { "type": ["string", "null"] },
              "environment": {
                "type": ["string", "null"],
                "enum": ["prod", "test", "override", null],
                "description": "v15.15+ - which Graylog instance answered. Test and production are separate instances; a production complaint corroborated only by test logs is insufficient-evidence, not a confirmed bff fault, so the verdict has to know where the lines came from."
              }
            }
          },
          "repoEvidence": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": ["repo", "layer", "file", "signal", "matchKind"],
              "properties": {
                "repo": { "type": "string" },
                "layer": {
                  "type": "string",
                  "enum": ["ios", "android", "web", "mobile-bff", "web-bff", "other"]
                },
                "file": { "type": "string" },
                "line": { "type": ["integer", "null"] },
                "signal": {
                  "type": "string",
                  "description": "The Graylog-derived signal that matched: endpoint path, error code, exception name, message template, or source service name."
                },
                "matchKind": { "type": "string", "enum": ["direct", "partial"] }
              }
            }
          },
          "verdict": {
            "type": "object",
            "additionalProperties": false,
            "required": ["category", "confidence", "rationale"],
            "properties": {
              "category": {
                "type": "string",
                "enum": ["client", "bff", "core", "insufficient-evidence"]
              },
              "layer": {
                "type": ["string", "null"],
                "enum": ["ios", "android", "web", "mobile-bff", "web-bff", null],
                "description": "Set for client/bff verdicts; null for core and insufficient-evidence."
              },
              "confidence": { "type": "string", "enum": ["high", "medium", "low"] },
              "rationale": { "type": "string", "minLength": 1 }
            }
          },
          "handoff": {
            "type": ["object", "null"],
            "additionalProperties": false,
            "description": "Present only for client/bff verdicts: development handoff grounded in the existing architecture (repoEvidence files as reference).",
            "properties": {
              "fixPlan": {
                "type": "array",
                "items": { "type": "string" },
                "description": "2-5 numbered steps, each referencing a cited file:line or component, reuse-first."
              },
              "devPrompt": {
                "type": ["string", "null"],
                "description": "English prompt block ready for /multi-agent or a Jira description; includes the [C-NN] id."
              }
            }
          },
          "routing": {
            "type": ["object", "null"],
            "additionalProperties": false,
            "description": "Present only for core verdicts: the routing recommendation to the backend core team. Never contains fix analysis.",
            "properties": {
              "suspectedService": {
                "type": ["string", "null"],
                "description": "Graylog message source field of the failing upstream service."
              },
              "endpoint": { "type": ["string", "null"] },
              "errorCode": { "type": ["string", "null"] },
              "evidenceExcerpt": {
                "type": ["string", "null"],
                "description": "Short redacted English excerpt from the Graylog message."
              },
              "suggestedQueue": {
                "type": ["string", "null"],
                "description": "Optional team/queue label from prefs.projects[*].routing.coreTeamLabel; null when unset."
              },
              "confidence": { "type": ["string", "null"], "enum": ["high", "medium", "low", null] }
            }
          }
        }
      }
    },
    "outputs": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "draftDir": { "type": ["string", "null"] },
        "files": { "type": "array", "items": { "type": "string" } },
        "destinations": {
          "type": "array",
          "items": { "type": "string", "enum": ["local", "confluence", "jira"] }
        },
        "confluencePageUrl": { "type": ["string", "null"] },
        "jiraIssueKey": { "type": ["string", "null"] }
      }
    }
  }
}
