{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://schemas.kodemed.ch/dll_com/GetResults-1.0.schema.json",
  "title": "KodeMed COM DLL — GetResults() Return",
  "description": "Canonical return shape of `IKodeMed.GetResults()` exposed by the COM DLL (`KodeMed.Interface/IKodeMed.cs:47`). The DLL serialises this object to XML (per `KodeMed.Interface/Models/CodingResults.cs` Xml* attributes) or JSON (per `JsonProperty` attributes) depending on the partner's configured output format. Both serialisations describe the SAME data structure — this JSON Schema is the source of truth, the matching XSD (`GetResults-1.0.xsd`) is generated from the same shape.\n\n## Alignment with other flows (#640)\n\nThe top-level envelope reuses the canonical field names used by the HIS REST webhook + WebSocket envelope: `sessionId`, `instanceId`, `eventType`, `occurredAt`. The per-case array `cases[]` uses `_common/CaseResult` — same shape a WebSocket `case.coded` message carries inline. A partner that already parsed the webhook payload can re-use the same `CodingResult` parser inside each `cases[i]` here. No drift.\n\n## What changed vs the pre-#640 DLL wire\n\nThe pre-#640 DLL emitted three top-level redundancies (`applied` + `discarded` + `cancelled` bools alongside `codingAction`) and three case-data fields (`resultData` + `originalData` + `modifiedData`). All collapsed into the canonical model: `eventType` is the single outcome discriminator, `cases[i].data` is the single case payload. The original case data, if a partner needs to diff, lives in the original SessionCreate request body (the HIS still has it).",
  "type": "object",
  "_comment_required": "Pre-2026-06-02 audit (CRITICAL #4a): the XSD declared <cases> mandatory but JSON had it optional. Aligned: BOTH transports now require the cases array (it can be empty — a session with zero coded <Fall> is still a valid envelope). XSD partners and JSON partners parse the same shape.",
  "required": ["sessionId", "eventType", "occurredAt", "cases"],
  "properties": {
    "sessionId": {
      "$ref": "../_common/Identifier.schema.json",
      "description": "Server-side session handle. Echoed from the SessionResponse / WebSocket session.created event."
    },
    "instanceId": {
      "$ref": "../_common/OpaqueIdentifier.schema.json",
      "description": "HIS-supplied correlator from the original SessionCreate request, when the session was started via HIS REST. Null for stand-alone CodingClient sessions (no HIS involved)."
    },
    "eventType": {
      "allOf": [
        { "$ref": "../_common/EventType.schema.json" },
        { "enum": ["case.coded", "case.discarded", "session.expired"] }
      ],
      "description": "Outcome of the session, restricted to the GetResults-relevant subset. Valid values: `case.coded` (coder pressed Apply), `case.discarded` (coder pressed Discard), `session.expired` (timeout — equivalent to the legacy `CodingAction.Timeout`). The legacy `CodingAction` enum (Pending/Applied/Discarded/Cancelled/Timeout/Error) maps onto this discriminator + the `groupingError` field inside each case. The $ref keeps it in the canonical EventType enum (one source of truth); the enum overlay restricts the subset reachable as a GetResults outcome (#640 audit CRITICAL #3 — pre-2026-06-02 a non-terminal event like `dll.heartbeat` would have validated)."
    },
    "occurredAt": {
      "$ref": "../_common/Timestamp.schema.json",
      "description": "When the session reached the terminal state. Replaces the legacy `endTime` field (the diagnostic `startTime` / `durationMs` move to the optional `stats` object below)."
    },
    "cases": {
      "type": "array",
      "description": "Per-case bundle: SPIGES XML + grouper output for each `<Fall>` in the submitted batch. One entry per case, ordered by appearance in the input. Use `cases[].codingResult.caseId` to correlate against the SPIGES `<Fall fall_id>`.",
      "items": {
        "$ref": "../_common/CaseResult.schema.json"
      }
    },
    "stats": {
      "type": "object",
      "description": "Optional diagnostic / aggregate stats. Surfaced for partners that want to log the processing footprint; NOT part of the coded result. Mirrors the legacy DLL top-level fields (durationMs, casesProcessed, etc.) but kept under a dedicated `stats` namespace so the envelope's primary fields stay focused on the coded outcome.",
      "additionalProperties": false,
      "properties": {
        "startedAt":       { "$ref": "../_common/Timestamp.schema.json", "description": "When the DLL began processing the input." },
        "finishedAt":      { "$ref": "../_common/Timestamp.schema.json", "description": "When the DLL completed (same instant as the envelope `occurredAt` in the common case)." },
        "durationMs":      { "type": "integer", "minimum": 0, "description": "Wall-clock processing duration (milliseconds)." },
        "casesProcessed":  { "type": "integer", "minimum": 0, "description": "Number of `<Fall>` cases in the input." },
        "diagnosesCount":  { "type": "integer", "minimum": 0, "description": "Total diagnoses across all cases." },
        "treatmentsCount": { "type": "integer", "minimum": 0, "description": "Total treatments (CHOP procedures) across all cases." },
        "sitesCount":      { "type": "integer", "minimum": 0, "description": "Number of distinct sites / locations in the input (typically 1)." },
        "enterpriseId":    { "type": ["integer", "null"], "description": "BUR enterprise id from the SPIGES envelope." },
        "spiGesVersion":   { "type": ["string", "null"], "description": "SPIGES XSD version detected in the input (e.g. `SPIGES-1.5`)." },
        "success":         { "type": "boolean", "description": "Whether processing succeeded overall. False when the DLL hit a hard error; per-case grouping success lives inside each `cases[].codingResult.groupingSuccess`." },
        "errorMessage":    { "type": ["string", "null"], "description": "Top-level error message if processing failed." },
        "warnings":        { "type": "array", "items": { "type": "string" }, "description": "Top-level processing warnings (strings, free-form). Per-case validation warnings live inside `cases[].codingResult.warnings[]` with structured `code` + `message` + `severity`." }
      }
    },
    "customProperties": {
      "type": "object",
      "description": "JSON-ONLY extension point for partner-specific metadata. Free-form string → string map, reserved for forward-compatible additions. Not part of the XML transport — the C# model marks it [XmlIgnore], so it appears only in JSON output (as {} when empty) and is intentionally absent from GetResults-1.0.xsd.",
      "additionalProperties": { "type": "string" }
    }
  },
  "unevaluatedProperties": false,
  "examples": [
    {
      "sessionId":   "0f9ea092-c774-4624-bb10-8910ec03d1db",
      "instanceId":  "his-eoc-2026-06-01-12345",
      "eventType":   "case.coded",
      "occurredAt":  "2026-06-01T19:42:11Z",
      "cases": [
        {
          "format": "spiges",
          "schemaVersion": "SPIGES-1.5",
          "data": "<?xml version=\"1.0\"?><spiges><Fall fall_id=\"F001\">…</Fall></spiges>",
          "codingResult": {
            "caseId":          "F001",
            "tariff":          "SWISSDRG",
            "drg":             "G22C",
            "pccl":            3,
            "costWeight":      0.976,
            "los":             5,
            "diagnoses":       [{ "code": "K35.2", "catalog": "ICD-10-GM", "isHauptdiagnose": true }],
            "procedures":      [{ "code": "47.01", "catalog": "CHOP", "performedAt": "2026-06-01T11:30:00Z" }],
            "supplements":     [],
            "warnings":        [],
            "flags":           [],
            "grouperVersion":  "SwissDRG-15.0",
            "groupingSuccess": true,
            "groupedAt":       "2026-06-01T19:42:09Z"
          }
        }
      ],
      "stats": {
        "startedAt":       "2026-06-01T19:42:08Z",
        "finishedAt":      "2026-06-01T19:42:11Z",
        "durationMs":      3142,
        "casesProcessed":  1,
        "diagnosesCount":  1,
        "treatmentsCount": 1,
        "sitesCount":      1,
        "enterpriseId":    100000001,
        "spiGesVersion":   "SPIGES-1.5",
        "success":         true,
        "warnings":        []
      }
    }
  ]
}
