.mini FORMAT — family 'cls' v1 (Multi-label text classification outputs)
Classifier outputs: the label set is written in full and the predicted labels carry *, so both the label space and the prediction are self-describing.
Rules:
- Plain UTF-8 text. The FIRST line is the header: 'cls|d=<str>?, l=<str>?, model=<str>?, k=<int>?, n=<int>'. n is mandatory and must equal the exact number of record lines.
- After the header, ONE line per record and nothing else (no comments, no code fences, no blank lines in between).
- Each record has these fields in THIS order, separated by '|' (position is the semantics; field names are never written):
  1. id: str
  2. text: str
  3. labels: ','-separated list of str; at least one element carries the suffix * (selected)
  4. conf: float [0..1]
  5. rationale: str (optional)
- If a list element contains the separator ',', enclose the element in double quotes CSV-style ("impact, justice and evidence"; the * marker goes after the closing quote) or escape the separator as '\,'. A literal trailing asterisk is written '\*'.
- Escapes valid in any value: '\|' for a literal vertical bar, '\\' for a backslash, '\n' for a line break.
- Numbers unquoted; booleans true/false. Scalar fields are never quoted.
- An empty field means null (allowed only for optional fields).
- Record: 5 core fields.

TASK: write a deterministic Python parser for family 'cls'. It must: validate the header and n; validate the arity of every record; process lists, tuples and the * marker; apply the escapes; and return the canonical JSON object shaped {'prefix', 'header', 'messages': [records]} where each record is an object keyed by the field names above; a marked list is returned as two sibling keys of the record: the element list and the selected index (or indices), named as the contract states (e.g. 'options' and 'correct'). When the marker rule is exactly_one/at_most_one the selected value is a single 0-based index (or null); when it is at_least_one/any it is always a list of ascending 0-based indices, even when only one element is marked.
Reject any invalid document with an exception that reports the line. No external libraries.

--- fixture: valid.mini ---
cls|n=12|d=20260603|l=en|model=cls-support-2026|k=6
m1|The quiz froze after question 4, is that a known issue?|question*,feedback,bug*,request,praise,other|0.91|reports a malfunction and asks
m2|Great flashcards, they saved my week!|question,feedback,bug,request,praise*,other|0.97|
m3|Could you add export to Anki?|question,feedback,bug,request*,praise,other|0.94|feature request
m4|Transcription missed the last ten minutes of the lecture.|question,feedback,bug*,request,praise,other|0.9|
m5|How is my level computed?|question*,feedback,bug,request,praise,other|0.95|
m6|The map view is confusing but the summaries are excellent.|question,feedback*,bug,request,praise*,other|0.82|mixed sentiment
m7|Please support PDF slides as input.|question,feedback,bug,request*,praise,other|0.93|
m8|Nothing to report.|question,feedback,bug,request,praise,other*|0.7|
m9|Why does the same question repeat twice?|question*,feedback,bug*,request,praise,other|0.86|possible exposure-control bug
m10|Love the adaptive difficulty, keep it up.|question,feedback*,bug,request,praise*,other|0.9|
m11|Credits were deducted twice for one upload.|question,feedback,bug*,request,praise,other|0.96|billing bug
m12|Can I share a class with a friend?|question*,feedback,bug,request*,praise,other|0.88|


--- fixture: escaping.mini ---
cls|n=1|d=20260603|l=en|model=cls-support-2026|k=6
m1|pipe \| and back\\slash, comma, "quotes", star* and newline\nend|a\, b \| c \\ d\**,feedback,bug*,request,praise,other|0.91|reports a malfunction and asks


Deliver a single Python 3 file defining `def parse(text: str) -> dict` (raise ValueError on invalid input, mentioning the line number). No third-party imports. Do not include tests or a main block. OUTPUT: only the Python code, no markdown fences, no explanations.