{
 "use_case": "migration-check",
 "title": "Migration check: ten support tickets triaged to JSON by the open model",
 "about": "Ten fictional support tickets for a made-up homeware shop, each with the JSON a hand-written reference gave (category, priority, refund_requested, order_id). The open model answers the same prompt; its outputs must parse against the schema and mostly agree field by field, and the sealed record must verify, recompute every stated number and fail once one example's pass mark is changed.",
 "licence": "Synthetic: 20 fictional support tickets for a made-up shop (the first 10 here). The reference outputs were written for this demo, not produced by a closed API. Written for the Decosa demo, 25 Sep 2026. Part of decosa-api, AGPL-3.0-or-later.",
 "inputs": [
  {
   "file": "inputs/examples.json",
   "what": "The logged traffic: a list of {id, input, output}, where output is what your current model answered (swap in your own logs)."
  },
  {
   "file": "inputs/prompt.json",
   "what": "The prompt your current model runs: {system, template}; {{input}} is replaced by each example's input."
  },
  {
   "file": "inputs/task.json",
   "what": "The task type and, for JSON tasks, the JSON Schema every output must meet."
  },
  {
   "file": "inputs/settings.json",
   "what": "The current model's name, the go / no-go thresholds and the output token cap (sent inline by the rehearsal)."
  }
 ],
 "steps": [
  {
   "id": "run",
   "method": "POST",
   "path": "/migration/runs",
   "timeout": 180,
   "body": {
    "title": "Rehearsal: ticket triage (synthetic)",
    "task": {
     "$file": "inputs/task.json"
    },
    "prompt": {
     "$file": "inputs/prompt.json"
    },
    "examples": {
     "$file": "inputs/examples.json"
    },
    "incumbent": {
     "model": "hand-written reference"
    },
    "thresholds": {
     "pass_rate": 0.9,
     "schema_valid": 0.98
    },
    "max_output_tokens": 200,
    "stream": false
   }
  },
  {
   "id": "verify",
   "method": "POST",
   "path": "/migration/verify",
   "auth": false,
   "body": {
    "record": {
     "$ref": "run.report.record"
    }
   }
  },
  {
   "id": "tampered",
   "method": "POST",
   "path": "/migration/verify",
   "auth": false,
   "body": {
    "record": {
     "$ref": "run.report.record"
    }
   },
   "tamper": {
    "at": "record.entries[kind=score].pass",
    "set": false
   }
  }
 ],
 "checks": [
  {
   "says": "all 10 examples were scored",
   "path": "run.examples",
   "count": 10
  },
  {
   "says": "at least 9 of 10 outputs parse against the schema",
   "path": "run.examples[valid=true]",
   "count_min": 9
  },
  {
   "says": "no model call failed",
   "path": "run.report.record.entries[kind=output,ok=false]",
   "count": 0
  },
  {
   "says": "at least 7 of 10 outputs agree with the reference on every field",
   "path": "run.examples[pass=true]",
   "count_min": 7
  },
  {
   "says": "the verdict is one of go, no-go or inconclusive",
   "path": "run.verdicts",
   "in": [
    {
     "qwen3.8-27b": "go"
    },
    {
     "qwen3.8-27b": "no-go"
    },
    {
     "qwen3.8-27b": "inconclusive"
    }
   ]
  },
  {
   "says": "the sealed record verifies",
   "path": "verify.record.ok",
   "equals": true
  },
  {
   "says": "every stated number recomputes from the per-example entries",
   "path": "verify.recompute.ok",
   "equals": true
  },
  {
   "says": "the record was issued by this server",
   "path": "verify.issued_here",
   "equals": true
  },
  {
   "says": "a record with one example's pass mark changed no longer verifies",
   "path": "tampered.ok",
   "equals": false
  },
  {
   "says": "every model call has a signed receipt",
   "receipts": "signed",
   "min": 10
  }
 ]
}
