| Model | Parser | Pass | Fail | Skip | Total | Status |
|---|---|---|---|---|---|---|
| mlx-community/Qwen3.5-35B-A3B-4bit | auto | 401 | 3 | 0 | ❌ [details] | |
| mlx-community/Qwen3.5-35B-A3B-4bit | qwen3_xml | 398 | 6 | 0 | ❌ [details] |
| # | Test | Group | Coverage | Status | Duration | Details |
|---|---|---|---|---|---|---|
| 1 | buildChoiceLogprobs returns nil for empty input | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 2 | multi-chunk think tags extracted correctly | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 3 | finishReason is stop when stopped by sequence | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 4 | collects logprobs from stream chunks | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 5 | toJinjaCompatible() strips null elements from arrays | NullableSchema | unit smoke standard full | PASS | 0.1s | pass |
| 6 | empty stream produces nil content | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 7 | stream with only think tags and no visible content | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 8 | buildChoiceLogprobs converts ResolvedLogprob to ChoiceLogprobs | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 9 | collects timing and token stats from final chunk | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 10 | toJinjaCompatible() preserves all non-null types | NullableSchema | unit smoke standard full | PASS | 0.1s | pass |
| 11 | toJinjaCompatible() strips null keys from dicts — Jinja accepts it | NullableSchema | unit smoke standard full | PASS | 0.1s | pass |
| 12 | toJinjaCompatible() deeply nested nulls — Jinja accepts them | NullableSchema | unit smoke standard full | PASS | 0.1s | pass |
| 13 | finishReason is stop by default | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 14 | toJinjaCompatible() result survives ToolSpec → Jinja Value round-trip | NullableSchema | unit smoke standard full | PASS | 0.1s | pass |
| 15 | think extraction with tool calls returns nil content and reasoning | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 16 | finishReason is tool_calls when tool calls present | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 17 | toAny() wraps null as NSNull — Jinja throws on it | NullableSchema | unit smoke standard full | PASS | 0.1s | pass |
| 18 | toAny() dict with null value — Jinja throws | NullableSchema | unit smoke standard full | PASS | 0.1s | pass |
| 19 | toAny() result in ToolSpec — Jinja throws (proves the bug) | NullableSchema | unit smoke standard full | PASS | 0.1s | pass |
| 20 | truncateToOffset on empty cache is no-op | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 21 | BaseKVCache truncateToOffset is safe no-op on MambaCache | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 22 | FileDeleteResponse defaults | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 23 | no think extraction when disabled | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 24 | BatchResultLine with error encodes correctly | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 25 | finishReason is length when max tokens reached | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 26 | BatchListResponse encodes with has_more field | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 27 | BatchCompletionRequest decodes array of requests | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 28 | extracts think tags into reasoningContent | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 29 | runtime parses adaptive xml JSON fallback | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 30 | RotatingKVCache is NOT batch-eligible | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 31 | BatchObject encodes with all fields | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 32 | runtime emits placeholder then final replacement for XML tool call | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 33 | runtime salvages incomplete tool call at stream end | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 34 | FileObject encodes with snake_case keys | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 35 | runtime preserves nulls in adaptive xml JSON fallback | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 36 | BatchResultLine round-trips through JSON | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 37 | MambaCache mask returns nil after state is set (non-prefill) | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 38 | createSSMMask delegates to MambaCache.makeMask | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 39 | createAttentionMask delegates to BatchKVCacheSimple.makeMask | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 40 | KVCacheSimple and ArraysCache are batch-eligible | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 41 | truncateToOffset is no-op when offset matches array size | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 42 | Batched prefill cache creation matches expected pattern for mixed layers | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 43 | state getter returns raw refs after truncateToOffset (fast path) | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 44 | truncateToOffset physically shrinks arrays to offset | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 45 | MambaCache without leftPadding returns nil mask | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 46 | BatchInputLine decodes from JSONL line | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 47 | truncateToOffset after multiple trim cycles | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 48 | BatchCreateRequest decodes with snake_case keys | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 49 | BatchKVCacheSimple update stores KV for all sequences | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 50 | NoSystemMessageGenerator includes name for tool messages | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 51 | user message has no name field in dict | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 52 | system messages filtered by NoSystemMessageGenerator | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 53 | tool message without name omits name from dict | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 54 | tool message with name includes name in dict | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 55 | BatchScheduler stop helper emits stopped chunk on exact stop match | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 56 | BatchScheduler emits delta chunks before completed tool call chunks | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 57 | MLXServiceError.serviceShuttingDown has descriptive message | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 58 | decodeXMLEntities passes through bare & without entity suffix | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 59 | multiple parameters with same non-empty value keeps first | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 60 | coerces string to negative integer | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 61 | does not coerce when property not in schema | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 62 | does not fill non-required missing params | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 63 | bare JSON that's not a tool call doesn't match | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 64 | XMLParser path drops unclosed parameter (no bare < to trigger fallback) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 65 | preserves content outside tool calls | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 66 | normalizeToolCalls assigns sequential indices from startIndex | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 67 | write tool with real newlines is NOT affected by decodeJSONEscapes | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 68 | BatchScheduler default max concurrent is 8 | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 69 | mixed: write content has real newlines, edit oldString has escaped — both decoded correctly | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 70 | coerceStringValue returns nil for unknown schema type | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 71 | BatchScheduler emits only completed tool calls from slot runtime events | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 72 | decodeXMLEntities handles entities at string boundaries | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 73 | handles mixed XML and JSON in separate <tool_call> blocks | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 74 | RequestSlot IDs are unique across instances | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 75 | handles duplicate parameters (keeps first non-empty) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 76 | fills missing required boolean param with false | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 77 | leaves already-correct types alone (string stays string) | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 78 | StreamChunk carries cached token count | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 79 | RequestSlot appendContent accumulates text | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 80 | coerceStringValue handles empty string for all types | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 81 | coerceStringValue coerces '0.0' to Int 0 for number type (whole number) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 82 | preserves JSON object parameter values | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 83 | BatchKVCacheSimple mask with uniform padding (same-length sequences) | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 84 | BatchScheduler emits incremental tool call deltas from slot runtime events | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 85 | TopKProcessor is no-op when k >= vocabSize | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 86 | TopKProcessor works with 1D logits [vocabSize] | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 87 | handles multiple parameters with mixed string and JSON types | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 88 | BatchKVCacheSimple mask with asymmetric padding (different-length sequences) | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 89 | StreamChunk defaults: only text, everything else nil | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 90 | JSON-in-XML with invalid JSON falls through | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 91 | decodeJSONEscapes handles \t escapes | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 92 | BatchInputLine handles messages with special characters | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 93 | BatchInputLine handles optional body fields | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 94 | MambaCache leftPadding creates correct SSM mask | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 95 | BatchScheduler helper extraction keeps tool call streams isolated per event list | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 96 | skips empty parameter values | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 97 | decodeJSONEscapes preserves values that already have real newlines | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 98 | JSONL with blank lines are skipped | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 99 | MLXServiceError.noModelLoaded has descriptive message | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 100 | Multiple JSONL lines parse independently | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 101 | bash tool with special characters | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 102 | BatchInputLine handles system + user messages | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 103 | RequestSlot initializes with unique ID and zero content | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 104 | JSON-in-XML with missing name returns no tool calls | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 105 | coerces whole-number string to Int for 'number' type | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 106 | listBatches returns all batches | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 107 | getSlotIds returns empty for nonexistent batch | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 108 | BatchScheduler stop helper does not stop while still inside think block | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 109 | StreamChunk carries timing info | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 110 | parses Mistral [TOOL_CALLS] with multiple items in array | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 111 | markBatchInProgress transitions status and stores slot IDs | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 112 | requiredParamNames returns empty for tool with no required array | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 113 | getFileData returns nil for nonexistent file | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 114 | GrammarLogitProcessor works with 2D logits | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 115 | recordResult increments failed count for error results | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 116 | MambaCache batched state can be sliced per-sequence | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 117 | BatchScheduler stop helper buffers partial stop across chunk boundaries | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 118 | coerceStringValue returns nil for non-numeric string with number type | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 119 | completed tool call parsing preserves remaining non-tool text | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 120 | coerceStringValue handles negative numbers | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 121 | getFile returns stored file metadata | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 122 | RepetitionContext works with 1D logits | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 123 | GrammarLogitProcessor with nil mask is passthrough | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 124 | deleteFile removes the file | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 125 | getFileData returns raw data | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 126 | decodeXMLEntities handles multiple < in Python code | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 127 | question tool: array of objects with typed fields (OpenCode pattern) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 128 | BatchKVCacheSimple extend merges prefill batch with existing decode batch | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 129 | PresenceContext works with 1D logits | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 130 | PresenceContext works with 2D logits | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 131 | decodeJSONEscapes unescapes literal \n and \" when no real newlines present | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 132 | createBatch returns ID with correct prefix and initial state | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 133 | markBatchCancelling and markBatchCancelled transitions | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 134 | deleteFile returns false for nonexistent file | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 135 | coerces string to object | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 136 | coerces string to array | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 137 | regex fallback handles bare < in parameter value | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 138 | GrammarLogitProcessor works with 1D logits | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 139 | markBatchFailed sets status and error | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 140 | getFile returns nil for nonexistent file | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 141 | Full extraction round-trip: batch → individual → KVCacheSimple | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 142 | coerceStringValue returns nil for float string with integer type | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 143 | TopKProcessor works with 2D logits [B, vocabSize] | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 144 | Left-padding stacks variable-length token arrays correctly | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 145 | TopKProcessor is no-op when k <= 0 | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 146 | recordResult increments completed count | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 147 | MinPProcessor works with 2D logits | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 148 | fills missing required integer param with 0 | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 149 | Multiple files have unique IDs | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 150 | empty <tool_call></tool_call> block returns no calls | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 151 | does NOT coerce 'yes'/'no'/'1'/'0' to boolean | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 152 | getBatch returns nil for nonexistent batch | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 153 | storeFile creates file with correct metadata | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 154 | parses Mistral [TOOL_CALLS] func_name[ARGS]{...} format | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 155 | regex fallback salvages unclosed parameter (max_tokens truncation) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 156 | coerceStringValue coerces '0' to Int 0 for integer type | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 157 | requiredParamNames preserves client schema order (not alphabetical) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 158 | decodeJSONEscapes preserves real backslashes (\\n stays as \n literal) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 159 | Output JSONL file contains all results | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 160 | handles multiple tool calls | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 161 | bare JSON with 'parameters' key instead of 'arguments' | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 162 | does not coerce non-string values | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 163 | BatchKVCacheSimple decode mask with padding (n=1) | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 164 | text content before and after tool call is preserved | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 165 | recordResult drops results for cancelled batch | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 166 | parses bare JSON tool call without wrapper tags | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 167 | coerceStringValue returns nil for invalid JSON with object type | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 168 | PresenceContext with empty tokens is no-op | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 169 | preserves JSON array parameter values | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 170 | Extracted cache can be loaded into KVCacheSimple for radix save | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 171 | decodeJSONEscapes handles empty string | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 172 | Batch auto-completes when all requests are done | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 173 | EBNF grammar handles tool with no required params | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 174 | decodeXMLEntities handles consecutive entities | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 175 | normalizeToolCall remaps keys before coercing values | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 176 | edit tool with JSON-escaped oldString gets decoded (model pre-escaping bug) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 177 | coerces string to integer | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 178 | parses JSON-in-XML format with 'parameters' key | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 179 | handles parameter values with special characters in Python code | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 180 | returns unchanged when tool name not found in tools list | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 181 | EBNF grammar generates named required param rules for bash tool | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 182 | recordResult drops results for cancelling batch | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 183 | recordResult still works for in_progress batch | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 184 | decodeXMLEntities decodes all 5 standard entities | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 185 | parses JSON-in-XML format with 'arguments' key | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 186 | CompositeLogitProcessor chains processors correctly with 2D logits | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 187 | EBNF grammar generates named required param rules for edit tool | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 188 | coerces boolean case-insensitively (TRUE, True, FALSE) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 189 | Gemma4 parser preserves commas inside escaped strings | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 190 | coerceStringValue returns nil for invalid JSON with array type | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 191 | extractToolCallsFallback parses Gemma4 wrapper blocks | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 192 | parses basic XML tool call | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 193 | decodeJSONEscapes full edit oldString from real Qwen3-Coder output | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 194 | JSON format switch mid-conversation (Qwen3-Coder-Next common error) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 195 | Gemma4 parser leaves nested-looking values as raw strings | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 196 | JSON-in-XML with no arguments key still parses name | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 197 | streaming runtime fallback parses completed Gemma4 tool call | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 198 | coerceStringValue returns nil for non-numeric string with integer type | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 199 | decodes XML entities in parameter values via XMLParser | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 200 | EBNF grammar allows extra optional params after required ones | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 201 | does NOT fill missing required string param (let client report missing) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 202 | decodeXMLEntities handles empty string | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 203 | BatchKVCacheSimple extract returns correct per-sequence KV | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 204 | Gemma4 parser follows documented wrapper and call syntax | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 205 | bash tool with JSON-escaped command gets decoded | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 206 | returns unchanged when tools is nil | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 207 | decodeXMLEntities handles double-encoded entities: &lt; → < | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 208 | EBNF grammar param_value uses permissive pv_char rule | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 209 | strips <think></think> tags from remaining text | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 210 | decodeJSONEscapes passes through plain text without escapes | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 211 | returns nil for content without <function=...> tag | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 212 | parses Mistral [TOOL_CALLS] JSON array format | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 213 | coerces string to number (float) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 214 | returns unchanged when tools is empty | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 215 | decodeJSONEscapes handles only \" without \n | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 216 | decodeXMLEntities passes through strings without entities | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 217 | handles multiline parameter values | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 218 | returns empty array and original text when no tool calls found | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 219 | returns unchanged when arguments JSON is invalid | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 220 | completed tool call parsing resolves adaptive XML tool names against offered tools | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 221 | insert: empty tokens is no-op | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 222 | write file with Python containing comparison operators (OpenCode pattern) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 223 | mixed coercion: some params coerced, some left alone | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 224 | Separate processor instances have independent state | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 225 | coerces string to boolean true and false | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 226 | RepetitionContext applies multiplicative penalty to negative logits | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 227 | MinPProcessor works with 1D logits | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 228 | Conversation fork: both branches survive and are findable | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 229 | insert: partial edge split with remaining tokens | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 230 | LRU eviction at capacity evicts oldest | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 231 | insert: multiple inserts grow the tree (multi-turn) | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 232 | insert: new edge (no matching child) | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 233 | Count tracks insertions, evictions, and invalidation | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 234 | findPrefix: query shorter than cached edge | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 235 | RepetitionContext works with 2D logits | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 236 | didSample updates only the called processor's state | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 237 | KVCacheEntry stores tokens and layerStates | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 238 | invalidateAll clears everything | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 239 | findPrefix: exact match returns full prefix | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 240 | insert: exact match — node had no prior cache | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 241 | insert: partial edge split at exact split point | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 242 | CompositeLogitProcessor chains processors correctly with 1D logits | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 243 | findPrefix: query longer than cached — partial prefix hit | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 244 | findPrefix: no child for next token — miss at root | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 245 | findPrefix: deepest cached node wins over shallower | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 246 | compactUpward merges single-child node after sibling eviction | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 247 | KVCacheEntry touch updates access time | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 248 | findPrefix: traverses nodes but no cached node found | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 249 | invalidateAll with debugLogging | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 250 | insert with debugLogging exercises log branches | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 251 | findPrefix: miss with matched > 0 and debugLogging | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 252 | findPrefix: empty cache — miss | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 253 | Multiple evictions on single insert (maxEntries=1) | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 254 | findPrefix: miss with matched == 0 and debugLogging | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 255 | findPrefix: partial edge match divergence mid-edge — returns cached state | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 256 | Touch via findPrefix prevents eviction | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 257 | insert snapshots MLXArray views into independent storage | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 258 | findPrefix with debugLogging exercises all log branches | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 259 | Eviction with debugLogging | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 260 | insert: exact match update — node already has cache | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 261 | RadixNode isLeaf and hasCachedState | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 262 | BatchStore handles concurrent batch creates safely | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 263 | RequestSlot is thread-safe under concurrent writes | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 264 | BatchStore handles concurrent file operations safely | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 265 | Cancel nonexistent batch returns 404 | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 266 | Cancel batch on non-in_progress returns 400 | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 267 | Cancel batch transitions to cancelled | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 268 | BatchCompletionsController sets grammar downgrade header when strict tools present | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 269 | BatchCompletionsController sanitizes fenced JSON in non-streaming results | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 270 | BatchCompletionsController skips grammar downgrade header for unsupported strict tool grammar | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 271 | Accepts valid method and url | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 272 | Rejects line with wrong method | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 273 | Rejects line with wrong url | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 274 | RequestSlot elapsedTime increases over time | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 275 | BatchAPIController response includes reasoningContent when model supports thinking | UnitTest | unit smoke standard full | PASS | 0.7s | pass |
| 276 | BatchAPIController response includes tool_calls with correct finish_reason | UnitTest | unit smoke standard full | PASS | 0.7s | pass |
| 277 | BatchAPIController response includes logprobs when provided in stream | UnitTest | unit smoke standard full | PASS | 0.7s | pass |
| 278 | Binary exists at .build/arm64-apple-macosx/release/afm | Preflight | unit smoke standard full | PASS | 0.0s | file exists |
| 279 | Server reachable at http://127.0.0.1:9998 | Preflight | unit smoke standard full | PASS | 0.0s | 200 OK |
| 280 | /v1/models contains model ID | Lifecycle | unit smoke standard full | PASS | 0.0s | model in response |
| 281 | Basic completion returns content | Lifecycle | unit smoke standard full | PASS | 6.7s | non-empty content or reasoning |
| 282 | Stop string '5' absent from output | Stop | unit smoke standard full | PASS | 2.2s | no '5' in content |
| 283 | finish_reason is 'stop' with stop sequence | Stop | unit smoke standard full | PASS | 0.0s | stop |
| 284 | Multi-word stop 'and' truncates correctly | Stop | unit smoke standard full | PASS | 2.2s | no 'and' in output |
| 285 | Stop on newline produces single line | Stop | unit smoke standard full | PASS | 1.9s | single line |
| 286 | Multiple stop sequences [7, 12] | Stop | unit smoke standard full | PASS | 2.2s | neither found |
| 287 | Empty stop array is no-op | Stop | unit smoke standard full | PASS | 5.2s | valid output |
| 288 | Streaming: stop string '5' absent | Stop | unit smoke standard full | PASS | 2.3s | no '5' in stream |
| 289 | Stop sequence '3.' truncates list | Stop | standard full | PASS | 1.2s | no '3.' in output |
| 290 | Stop 'stopped' doesn't fire on 'stopping' | Stop | standard full | PASS | 2.1s | output produced |
| 291 | Stop 'llo' fires mid-word in 'hello' | Stop | standard full | PASS | 1.9s | no 'llo' |
| 292 | ChoiceLogprobs JSON schema valid | Logprobs | smoke standard full | PASS | 0.3s | valid schema |
| 293 | top_logprobs count <= requested (5) | Logprobs | smoke standard full | PASS | 0.2s | count valid |
| 294 | logprobs=false returns null | Logprobs | smoke standard full | PASS | 0.1s | null logprobs |
| 295 | top_logprobs=99 returns 400 | Logprobs | smoke standard full | PASS | 0.0s | 400 |
| 296 | Streaming logprobs present and valid | Logprobs | standard full | PASS | 0.2s | valid |
| 297 | top_logprobs=0 returns empty arrays | Logprobs | standard full | PASS | 0.2s | empty top_logprobs |
| 298 | reasoning_content present in response | Think | smoke standard full | PASS | 0.0s | present |
| 299 | No <think> tags in content field | Think | smoke standard full | PASS | 0.0s | clean content |
| 300 | Streaming: reasoning_content in deltas | Think | smoke standard full | PASS | 1.1s | present |
| 301 | Stop sequence doesn't break think extraction | Think | smoke standard full | PASS | 2.1s | response ok |
| 302 | reasoning_content has meaningful length (>5 chars) | Think | smoke standard full | PASS | 0.0s | >5 chars |
| 303 | Basic tool call: finish_reason=tool_calls, valid args | Tools | smoke standard full | PASS | 2.0s | valid |
| 304 | tool_choice=none suppresses tool calls | Tools | smoke standard full | PASS | 1.1s | no tool calls |
| 305 | Tool arguments are valid JSON dict | Tools | standard full | PASS | 1.0s | valid JSON |
| 306 | Streaming: tool calls with finish_reason | Tools | standard full | PASS | 1.2s | valid |
| 307 | Multi-tool: at least 1 tool call with 2 tools | Tools | standard full | PASS | 1.8s | >=1 calls |
| 308 | Array param: todos is JSON array (not string) | Tools | standard full | PASS | 1.6s | array |
| 309 | Nullable param: anyOf [string, null] does not crash | Tools | standard full | PASS | 1.4s | no crash |
| 310 | Multi-turn: tool result produces valid follow-up | Tools | standard full | PASS | 3.1s | text response |
| 311 | Multi-turn nullable: full round-trip (anyOf params) | Tools | standard full | PASS | 3.7s | valid follow-up |
| 312 | No tools: normal text response | Tools | standard full | PASS | 0.3s | text response |
| 313 | First unique request: uncached suffix remains | Cache | standard full | PASS | 0.4s | cached_tokens < prompt_tokens |
| 314 | Shared-prefix request: cached_tokens>0 | Cache | standard full | PASS | 0.3s | >0 |
| 315 | Exact replay: cached response matches cold response | Cache | standard full | PASS | 0.4s | same content |
| 316 | Different unique prompt: uncached suffix remains | Cache | standard full | PASS | 0.4s | cached_tokens < prompt_tokens |
| 317 | Streaming shared-prefix: cached_tokens>0 in usage chunk | Cache | standard full | PASS | 0.8s | >0 |
| 318 | Streaming replay: content matches non-streaming warmup | Cache | standard full | PASS | 0.9s | same content |
| 319 | Concurrent x8 shared-prefix: uncached suffix remains on every branch | Cache | standard full | FAIL | 3.8s | Expected: 0 < cached_tokens < prompt_tokens for all 8\nActual: FAIL: 2:0/59, 3:0/59, 4:0/59, 5:0/59, 6:0/59, 7:0/59, 8:0/59 |
| 320 | Concurrent x8 shared-prefix: divergent suffix responses stay isolated | Cache | standard full | FAIL | 3.8s | Expected: each of 8 responses keeps only its own marker\nActual: FAIL: 1:error=Expecting value: line 1 column 1 (char 0); 2:error=Expecting value: line 1 column 1 (char 0); 3:error=Expecting value: line 1 column 1 (char 0); 4:error=Expecting value: line 1 column 1 (char 0); 5:error=Expecting value: line 1 column 1 (char 0); 6:error=Expecting value: line 1 column 1 (char 0); 7:error=Expecting value: line 1 column 1 (char 0); 8:error=Expecting value: line 1 column 1 (char 0) |
| 321 | Two simultaneous requests: both 200 | Concurrent | standard full | PASS | 0.3s | 200+200 |
| 322 | Three simultaneous requests: all 200 | Concurrent | standard full | PASS | 0.4s | all 200 |
| 323 | Empty messages → 400 | Error | smoke standard full | PASS | 0.0s | 400 |
| 324 | Malformed JSON → 400 | Error | smoke standard full | PASS | 0.0s | 400 |
| 325 | Missing messages field → 400 | Error | smoke standard full | PASS | 0.0s | 400 |
| 326 | response_format json_object returns valid JSON | Error | smoke standard full | PASS | 0.3s | valid JSON |
| 327 | max_tokens=5 is respected | Error | smoke standard full | PASS | 0.1s | <=10 tokens |
| 328 | OPTIONS /v1/chat/completions → 200 (CORS) | Error | smoke standard full | PASS | 0.0s | 200 |
| 329 | developer role accepted (mapped to system) | Error | smoke standard full | PASS | 5.3s | valid response |
| 330 | enable_thinking=false disables thinking | Kwargs | standard full | PASS | 0.2s | no_think |
| 331 | Streaming: enable_thinking=false disables thinking | Kwargs | standard full | PASS | 0.2s | no_think |
| 332 | Default (no kwargs) retains thinking | Kwargs | standard full | PASS | 1.8s | thinking |
| 333 | enable_thinking=false (2K tokens) returns content | Kwargs | standard full | PASS | 0.2s | content present, no reasoning |
| 334 | enable_thinking=true explicitly keeps thinking | Kwargs | standard full | PASS | 1.8s | thinking |
| 335 | Prefix cache reuse across requests | Cache | standard full | PASS | 0.4s | valid response on cache hit |
| 336 | Issue #32: sequential guided-json → nullable tool (no crash) | Cache | standard full | PASS | 4.2s | both succeed |
| 337 | Sequential: 3 nullable tool calls (cache reuse) | Cache | standard full | PASS | 4.8s | 3/3 succeed |
| 338 | Multi-turn: 5-msg tool conversation with prefix cache | Cache | standard full | PASS | 2.4s | valid response |
| 339 | Long system prompt: 3 sequential requests (prefix reuse) | Cache | standard full | PASS | 6.7s | 3/3 succeed |
| 340 | Sequential stress: 5 mixed requests (text/tool/json/stream/nullable) | Cache | standard full | PASS | 4.9s | 5/5 succeed |
| 341 | Multi-turn: 5-turn growing conversation (prefix reuse) | Cache | standard full | PASS | 5.3s | 5/5 turns |
| 342 | Streaming + non-streaming sequential (shared prefix) | Cache | standard full | PASS | 1.2s | 3/3 succeed |
| 343 | Issue #32 comprehensive: nullable tool + multi-turn + prefix | Cache | standard full | PASS | 3.1s | valid response |
| 344 | json_schema produces valid schema-matching JSON | Structured | standard full | PASS | 0.4s | valid JSON |
| 345 | TTFT < 5s | Perf | full | PASS | 0.6s | <5000ms |
| 346 | tok/s > 1 (83.3 tok/s) | Perf | full | PASS | 0.6s | >1 |
| 347 | Long context (~2K tokens) no crash | Perf | full | PASS | 6.1s | valid response |
| 348 | Very long context (~4K tokens) no NaN/garbage | Perf | full | PASS | 8.3s | clean output |
| 349 | Function name correctly extracted | XMLTools | standard full | PASS | 1.9s | get_weather |
| 350 | Parameter values are correct string types | XMLTools | standard full | PASS | 1.6s | strings |
| 351 | Mixed-type params (string+bool+int) parse correctly | XMLTools | standard full | PASS | 1.9s | valid types |
| 352 | Nested object param survives XML parsing | XMLTools | standard full | PASS | 2.1s | valid dict |
| 353 | tool_choice=required forces tool call | XMLTools | standard full | PASS | 1.5s | tool_calls |
| 354 | tool_choice={function: get_time} calls correct function | XMLTools | standard full | PASS | 1.5s | get_time |
| 355 | Tool call IDs are unique | XMLTools | standard full | PASS | 2.3s | unique IDs |
| 356 | Streaming: XML tool call assembles valid JSON args | XMLTools | standard full | PASS | 1.0s | valid |
| 357 | Streaming: array param is JSON array (not string) | XMLTools | standard full | PASS | 1.6s | array |
| 358 | Tool call matches OpenAI schema (id, type, function.name, function.arguments) | XMLTools | standard full | PASS | 1.9s | valid schema |
| 359 | Normal XML tool call works with afm_adaptive_xml | AdaptiveXML | standard full | PASS | 1.7s | valid tool call |
| 360 | Streaming tool call emits valid deltas | AdaptiveXML | standard full | PASS | 1.5s | name + JSON args |
| 361 | Multi-turn: model responds after tool result | AdaptiveXML | standard full | PASS | 0.9s | non-empty content |
| 362 | tool_choice=none suppresses tool calls | AdaptiveXML | standard full | PASS | 2.2s | no tool_calls |
| 363 | Multiple tools: correct function selected | AdaptiveXML | standard full | PASS | 1.4s | get_time |
| 364 | Argument types coerced (string, bool, int) | AdaptiveXML | standard full | PASS | 1.9s | correct types |
| 365 | Tool call valid (with or without grammar constraints) | AdaptiveXML | standard full | PASS | 1.9s | valid |
| 366 | Array of objects coercion (question tool pattern) | AdaptiveXML | standard full | PASS | 3.2s | array of dicts |
| 367 | Number (float) and boolean coercion | AdaptiveXML | standard full | PASS | 1.7s | correct types |
| 368 | Nested object with typed fields coercion | AdaptiveXML | standard full | PASS | 1.8s | correct types |
| 369 | Streaming array coercion (incremental path) | AdaptiveXML | standard full | PASS | 1.6s | array in stream |
| 370 | XML entity decoding in tool call values | AdaptiveXML | standard full | PASS | 3.0s | decoded |
| 371 | EBNF grammar enforces all required params present | AdaptiveXML | standard full | PASS | 1.4s | command + description |
| 372 | EBNF structured params: array gets json_array constraint | AdaptiveXML | standard full | PASS | 2.2s | tags is array |
| 373 | Calculator tool call (non-streaming) | Grammar | standard full | PASS | 1.8s | calculate(expression) |
| 374 | Calculator tool call (streaming) | Grammar | standard full | PASS | 1.1s | calculate(expression) via SSE |
| 375 | Two tools: grammar allows correct selection | Grammar | standard full | PASS | 2.0s | get_weather selected |
| 376 | Two tools: grammar selects calculate | Grammar | standard full | PASS | 1.0s | calculate selected |
| 377 | Grammar enforces 3 required params (send_email) | Grammar | standard full | PASS | 2.4s | to + subject + body |
| 378 | Grammar constrains array param at generation time | Grammar | standard full | PASS | 2.4s | tags is array |
| 379 | Grammar array param via streaming | Grammar | standard full | PASS | 2.1s | tags is array (SSE) |
| 380 | Complex schema: string + int + array + object | Grammar | standard full | PASS | 3.8s | correct types |
| 381 | Header absent when grammar enabled (tool strict:true) | StrictWiring | smoke standard full | PASS | 1.3s | no header |
| 382 | Header absent when grammar enabled (schema strict:true) | StrictWiring | smoke standard full | PASS | 0.4s | no header |
| 383 | No header when strict absent | StrictWiring | smoke standard full | PASS | 0.8s | no header |
| 384 | Streaming json_schema strict:true returns valid JSON | StrictWiring | smoke standard full | PASS | 0.3s | valid JSON with name+age |
| 385 | Streaming tool strict:true returns valid tool call | StrictWiring | smoke standard full | PASS | 1.9s | get_weather(location) |
| 386 | strict:false does not error (best-effort) | StrictWiring | smoke standard full | PASS | 1.5s | valid response |
| 387 | POST /v1/files upload returns file ID | Batch | standard full | PASS | 0.0s | file-* |
| 388 | GET /v1/files/:id returns file metadata | Batch | standard full | PASS | 0.0s | file object |
| 389 | POST /v1/batches creates batch | Batch | standard full | PASS | 0.0s | in_progress/completed |
| 390 | GET /v1/batches/:id polls to completed | Batch | standard full | PASS | 2.1s | completed |
| 391 | Output JSONL contains both results (2/2) | Batch | standard full | PASS | 0.0s | assert-1 + assert-2 |
| 392 | GET /v1/batches lists completed batch | Batch | standard full | PASS | 0.0s | list with ≥1 batch |
| 393 | DELETE /v1/files/:id removes uploaded file | Batch | standard full | PASS | 0.0s | deleted=true |
| 394 | SSE multiplex: 2 non-streaming requests tagged with custom_id | Batch | standard full | PASS | 0.3s | sse-a + sse-b + [DONE] |
| 395 | SSE multiplex: streaming interleaved with finish_reason | Batch | standard full | PASS | 0.4s | str-x + str-y chunks + stop + [DONE] |
| 396 | SSE multiplex rejects duplicate custom_ids | Batch | standard full | PASS | 0.0s | 400 |
| 397 | SSE multiplex rejects empty requests | Batch | standard full | PASS | 0.0s | 400 |
| 398 | batch + top_k + streaming | PairwiseSmoke | standard full | PASS | 0.3s | content present |
| 399 | batch + presence_penalty + non-streaming | PairwiseSmoke | standard full | PASS | 0.3s | finish_reason present |
| 400 | batch + repetition_penalty + logprobs | PairwiseSmoke | standard full | PASS | 0.2s | response valid |
| 401 | batch + all sampling params combined | PairwiseSmoke | standard full | PASS | 0.2s | response valid |
| 402 | streaming parity (same seed → same output) | PairwiseSmoke | standard full | PASS | 0.3s | match |
| 403 | cache idempotency (same seed → same output) | PairwiseSmoke | standard full | PASS | 0.3s | match |
| # | Test | Group | Coverage | Status | Duration | Details |
|---|---|---|---|---|---|---|
| 1 | buildChoiceLogprobs returns nil for empty input | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 2 | empty stream produces nil content | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 3 | finishReason is stop by default | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 4 | stream with only think tags and no visible content | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 5 | finishReason is tool_calls when tool calls present | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 6 | extracts think tags into reasoningContent | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 7 | multi-chunk think tags extracted correctly | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 8 | BatchListResponse encodes with has_more field | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 9 | collects timing and token stats from final chunk | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 10 | BatchResultLine with error encodes correctly | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 11 | buildChoiceLogprobs converts ResolvedLogprob to ChoiceLogprobs | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 12 | BatchObject encodes with all fields | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 13 | BatchInputLine handles optional body fields | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 14 | truncateToOffset on empty cache is no-op | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 15 | BatchCompletionRequest decodes array of requests | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 16 | BatchInputLine handles messages with special characters | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 17 | Multiple JSONL lines parse independently | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 18 | no think extraction when disabled | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 19 | BatchInputLine decodes from JSONL line | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 20 | BaseKVCache truncateToOffset is safe no-op on MambaCache | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 21 | JSONL with blank lines are skipped | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 22 | finishReason is stop when stopped by sequence | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 23 | FileObject encodes with snake_case keys | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 24 | finishReason is length when max tokens reached | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 25 | BatchInputLine handles system + user messages | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 26 | think extraction with tool calls returns nil content and reasoning | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 27 | FileDeleteResponse defaults | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 28 | collects logprobs from stream chunks | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 29 | Gemma4 parser follows documented wrapper and call syntax | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 30 | streaming runtime fallback parses completed Gemma4 tool call | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 31 | BatchResultLine round-trips through JSON | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 32 | extractToolCallsFallback parses Gemma4 wrapper blocks | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 33 | PresenceContext with empty tokens is no-op | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 34 | truncateToOffset is no-op when offset matches array size | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 35 | truncateToOffset physically shrinks arrays to offset | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 36 | state getter returns raw refs after truncateToOffset (fast path) | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 37 | MinPProcessor works with 2D logits | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 38 | GrammarLogitProcessor works with 1D logits | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 39 | truncateToOffset after multiple trim cycles | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 40 | GrammarLogitProcessor works with 2D logits | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 41 | createSSMMask delegates to MambaCache.makeMask | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 42 | recordResult still works for in_progress batch | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 43 | recordResult drops results for cancelled batch | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 44 | recordResult drops results for cancelling batch | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 45 | MinPProcessor works with 1D logits | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 46 | TopKProcessor works with 2D logits [B, vocabSize] | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 47 | GrammarLogitProcessor with nil mask is passthrough | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 48 | RotatingKVCache is NOT batch-eligible | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 49 | RepetitionContext works with 1D logits | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 50 | TopKProcessor works with 1D logits [vocabSize] | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 51 | BatchKVCacheSimple update stores KV for all sequences | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 52 | PresenceContext works with 2D logits | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 53 | Batched prefill cache creation matches expected pattern for mixed layers | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 54 | RepetitionContext applies multiplicative penalty to negative logits | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 55 | MambaCache mask returns nil after state is set (non-prefill) | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 56 | KVCacheSimple and ArraysCache are batch-eligible | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 57 | Gemma4 parser preserves commas inside escaped strings | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 58 | TopKProcessor is no-op when k <= 0 | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 59 | Gemma4 parser leaves nested-looking values as raw strings | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 60 | TopKProcessor is no-op when k >= vocabSize | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 61 | MambaCache without leftPadding returns nil mask | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 62 | CompositeLogitProcessor chains processors correctly with 2D logits | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 63 | PresenceContext works with 1D logits | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 64 | BatchKVCacheSimple mask with uniform padding (same-length sequences) | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 65 | createAttentionMask delegates to BatchKVCacheSimple.makeMask | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 66 | BatchCreateRequest decodes with snake_case keys | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 67 | RepetitionContext works with 2D logits | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 68 | CompositeLogitProcessor chains processors correctly with 1D logits | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 69 | MLXServiceError.serviceShuttingDown has descriptive message | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 70 | runtime parses adaptive xml JSON fallback | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 71 | runtime emits placeholder then final replacement for XML tool call | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 72 | runtime salvages incomplete tool call at stream end | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 73 | runtime preserves nulls in adaptive xml JSON fallback | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 74 | RequestSlot appendContent accumulates text | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 75 | BatchScheduler emits incremental tool call deltas from slot runtime events | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 76 | BatchScheduler stop helper buffers partial stop across chunk boundaries | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 77 | tool message with name includes name in dict | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 78 | system messages filtered by NoSystemMessageGenerator | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 79 | StreamChunk defaults: only text, everything else nil | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 80 | StreamChunk carries timing info | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 81 | BatchScheduler default max concurrent is 8 | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 82 | user message has no name field in dict | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 83 | Extracted cache can be loaded into KVCacheSimple for radix save | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 84 | tool message without name omits name from dict | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 85 | NoSystemMessageGenerator includes name for tool messages | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 86 | BatchScheduler emits delta chunks before completed tool call chunks | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 87 | BatchScheduler stop helper emits stopped chunk on exact stop match | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 88 | RequestSlot initializes with unique ID and zero content | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 89 | StreamChunk carries cached token count | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 90 | BatchScheduler helper extraction keeps tool call streams isolated per event list | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 91 | BatchScheduler emits only completed tool calls from slot runtime events | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 92 | RequestSlot IDs are unique across instances | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 93 | MLXServiceError.noModelLoaded has descriptive message | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 94 | BatchScheduler stop helper does not stop while still inside think block | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 95 | parses bare JSON tool call without wrapper tags | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 96 | JSON-in-XML with missing name returns no tool calls | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 97 | coerces boolean case-insensitively (TRUE, True, FALSE) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 98 | strips <think></think> tags from remaining text | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 99 | requiredParamNames returns empty for tool with no required array | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 100 | preserves JSON array parameter values | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 101 | bare JSON that's not a tool call doesn't match | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 102 | coerceStringValue coerces '0.0' to Int 0 for number type (whole number) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 103 | decodeXMLEntities handles consecutive entities | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 104 | edit tool with JSON-escaped oldString gets decoded (model pre-escaping bug) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 105 | bare JSON with 'parameters' key instead of 'arguments' | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 106 | decodeJSONEscapes handles \t escapes | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 107 | write file with Python containing comparison operators (OpenCode pattern) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 108 | decodeXMLEntities decodes all 5 standard entities | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 109 | write tool with real newlines is NOT affected by decodeJSONEscapes | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 110 | returns nil for content without <function=...> tag | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 111 | question tool: array of objects with typed fields (OpenCode pattern) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 112 | XMLParser path drops unclosed parameter (no bare < to trigger fallback) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 113 | bash tool with JSON-escaped command gets decoded | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 114 | decodeXMLEntities handles double-encoded entities: &lt; → < | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 115 | coerces string to boolean true and false | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 116 | handles mixed XML and JSON in separate <tool_call> blocks | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 117 | mixed coercion: some params coerced, some left alone | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 118 | parses JSON-in-XML format with 'parameters' key | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 119 | decodeJSONEscapes unescapes literal \n and \" when no real newlines present | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 120 | coerceStringValue handles empty string for all types | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 121 | normalizeToolCall remaps keys before coercing values | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 122 | JSON-in-XML with invalid JSON falls through | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 123 | does not fill non-required missing params | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 124 | text content before and after tool call is preserved | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 125 | handles multiline parameter values | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 126 | parses Mistral [TOOL_CALLS] JSON array format | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 127 | EBNF grammar generates named required param rules for edit tool | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 128 | decodes XML entities in parameter values via XMLParser | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 129 | EBNF grammar handles tool with no required params | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 130 | returns empty array and original text when no tool calls found | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 131 | decodeJSONEscapes preserves values that already have real newlines | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 132 | JSON format switch mid-conversation (Qwen3-Coder-Next common error) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 133 | coerceStringValue handles negative numbers | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 134 | returns unchanged when tools is nil | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 135 | bash tool with special characters | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 136 | decodeXMLEntities handles empty string | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 137 | parses Mistral [TOOL_CALLS] with multiple items in array | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 138 | handles parameter values with special characters in Python code | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 139 | decodeXMLEntities passes through bare & without entity suffix | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 140 | EBNF grammar allows extra optional params after required ones | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 141 | coerces string to negative integer | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 142 | coerceStringValue returns nil for invalid JSON with object type | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 143 | coerceStringValue returns nil for non-numeric string with integer type | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 144 | decodeJSONEscapes handles empty string | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 145 | completed tool call parsing preserves remaining non-tool text | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 146 | multiple parameters with same non-empty value keeps first | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 147 | coerceStringValue returns nil for unknown schema type | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 148 | coerces string to integer | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 149 | parses Mistral [TOOL_CALLS] func_name[ARGS]{...} format | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 150 | preserves JSON object parameter values | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 151 | normalizeToolCalls assigns sequential indices from startIndex | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 152 | coerceStringValue returns nil for float string with integer type | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 153 | parses JSON-in-XML format with 'arguments' key | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 154 | does not coerce non-string values | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 155 | MambaCache leftPadding creates correct SSM mask | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 156 | returns unchanged when tools is empty | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 157 | completed tool call parsing resolves adaptive XML tool names against offered tools | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 158 | fills missing required boolean param with false | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 159 | coerces string to number (float) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 160 | does NOT fill missing required string param (let client report missing) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 161 | didSample updates only the called processor's state | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 162 | regex fallback handles bare < in parameter value | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 163 | findPrefix: empty cache — miss | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 164 | empty <tool_call></tool_call> block returns no calls | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 165 | coerces whole-number string to Int for 'number' type | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 166 | insert: new edge (no matching child) | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 167 | insert: empty tokens is no-op | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 168 | Separate processor instances have independent state | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 169 | fills missing required integer param with 0 | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 170 | skips empty parameter values | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 171 | BatchKVCacheSimple mask with asymmetric padding (different-length sequences) | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 172 | findPrefix: query shorter than cached edge | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 173 | requiredParamNames preserves client schema order (not alphabetical) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 174 | BatchKVCacheSimple extend merges prefill batch with existing decode batch | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 175 | returns unchanged when tool name not found in tools list | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 176 | handles multiple parameters with mixed string and JSON types | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 177 | decodeXMLEntities handles multiple < in Python code | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 178 | JSON-in-XML with no arguments key still parses name | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 179 | MambaCache batched state can be sliced per-sequence | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 180 | findPrefix: query longer than cached — partial prefix hit | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 181 | EBNF grammar param_value uses permissive pv_char rule | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 182 | coerceStringValue returns nil for invalid JSON with array type | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 183 | insert: exact match update — node already has cache | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 184 | coerceStringValue coerces '0' to Int 0 for integer type | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 185 | findPrefix: miss with matched > 0 and debugLogging | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 186 | insert: multiple inserts grow the tree (multi-turn) | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 187 | findPrefix: deepest cached node wins over shallower | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 188 | regex fallback salvages unclosed parameter (max_tokens truncation) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 189 | coerceStringValue returns nil for non-numeric string with number type | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 190 | Full extraction round-trip: batch → individual → KVCacheSimple | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 191 | insert: partial edge split at exact split point | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 192 | findPrefix: partial edge match divergence mid-edge — returns cached state | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 193 | findPrefix with debugLogging exercises all log branches | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 194 | LRU eviction at capacity evicts oldest | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 195 | handles multiple tool calls | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 196 | does not coerce when property not in schema | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 197 | returns unchanged when arguments JSON is invalid | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 198 | Left-padding stacks variable-length token arrays correctly | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 199 | Eviction with debugLogging | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 200 | handles duplicate parameters (keeps first non-empty) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 201 | decodeJSONEscapes preserves real backslashes (\\n stays as \n literal) | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 202 | decodeXMLEntities passes through strings without entities | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 203 | insert: exact match — node had no prior cache | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 204 | invalidateAll clears everything | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 205 | mixed: write content has real newlines, edit oldString has escaped — both decoded correctly | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 206 | parses basic XML tool call | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 207 | coerces string to object | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 208 | preserves content outside tool calls | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 209 | Count tracks insertions, evictions, and invalidation | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 210 | Touch via findPrefix prevents eviction | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 211 | Conversation fork: both branches survive and are findable | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 212 | insert snapshots MLXArray views into independent storage | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 213 | compactUpward merges single-child node after sibling eviction | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 214 | decodeXMLEntities handles entities at string boundaries | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 215 | findPrefix: miss with matched == 0 and debugLogging | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 216 | coerces string to array | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 217 | decodeJSONEscapes passes through plain text without escapes | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 218 | decodeJSONEscapes handles only \" without \n | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 219 | BatchKVCacheSimple decode mask with padding (n=1) | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 220 | EBNF grammar generates named required param rules for bash tool | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 221 | leaves already-correct types alone (string stays string) | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 222 | decodeJSONEscapes full edit oldString from real Qwen3-Coder output | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 223 | does NOT coerce 'yes'/'no'/'1'/'0' to boolean | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 224 | toJinjaCompatible() strips null elements from arrays | NullableSchema | unit smoke standard full | PASS | 0.0s | pass |
| 225 | BatchKVCacheSimple extract returns correct per-sequence KV | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 226 | findPrefix: traverses nodes but no cached node found | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 227 | invalidateAll with debugLogging | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 228 | insert: partial edge split with remaining tokens | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 229 | insert with debugLogging exercises log branches | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 230 | RadixNode isLeaf and hasCachedState | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 231 | KVCacheEntry stores tokens and layerStates | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 232 | findPrefix: no child for next token — miss at root | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 233 | findPrefix: exact match returns full prefix | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 234 | Multiple evictions on single insert (maxEntries=1) | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 235 | recordResult increments completed count | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 236 | Multiple files have unique IDs | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 237 | deleteFile removes the file | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 238 | markBatchCancelling and markBatchCancelled transitions | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 239 | deleteFile returns false for nonexistent file | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 240 | KVCacheEntry touch updates access time | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 241 | toJinjaCompatible() deeply nested nulls — Jinja accepts them | NullableSchema | unit smoke standard full | PASS | 0.0s | pass |
| 242 | toJinjaCompatible() strips null keys from dicts — Jinja accepts it | NullableSchema | unit smoke standard full | PASS | 0.0s | pass |
| 243 | listBatches returns all batches | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 244 | toJinjaCompatible() result survives ToolSpec → Jinja Value round-trip | NullableSchema | unit smoke standard full | PASS | 0.0s | pass |
| 245 | createBatch returns ID with correct prefix and initial state | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 246 | getFileData returns nil for nonexistent file | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 247 | getSlotIds returns empty for nonexistent batch | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 248 | toJinjaCompatible() preserves all non-null types | NullableSchema | unit smoke standard full | PASS | 0.0s | pass |
| 249 | getFile returns stored file metadata | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 250 | Batch auto-completes when all requests are done | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 251 | markBatchFailed sets status and error | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 252 | getFile returns nil for nonexistent file | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 253 | recordResult increments failed count for error results | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 254 | markBatchInProgress transitions status and stores slot IDs | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 255 | storeFile creates file with correct metadata | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 256 | getBatch returns nil for nonexistent batch | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 257 | Output JSONL file contains all results | XMLParsing | unit smoke standard full | PASS | 0.0s | pass |
| 258 | getFileData returns raw data | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 259 | toAny() wraps null as NSNull — Jinja throws on it | NullableSchema | unit smoke standard full | PASS | 0.0s | pass |
| 260 | toAny() result in ToolSpec — Jinja throws (proves the bug) | NullableSchema | unit smoke standard full | PASS | 0.0s | pass |
| 261 | toAny() dict with null value — Jinja throws | NullableSchema | unit smoke standard full | PASS | 0.0s | pass |
| 262 | RequestSlot is thread-safe under concurrent writes | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 263 | BatchStore handles concurrent batch creates safely | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 264 | BatchStore handles concurrent file operations safely | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 265 | Cancel batch on non-in_progress returns 400 | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 266 | Cancel nonexistent batch returns 404 | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 267 | Cancel batch transitions to cancelled | UnitTest | unit smoke standard full | PASS | 0.0s | pass |
| 268 | BatchCompletionsController sanitizes fenced JSON in non-streaming results | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 269 | BatchCompletionsController skips grammar downgrade header for unsupported strict tool grammar | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 270 | BatchCompletionsController sets grammar downgrade header when strict tools present | XMLParsing | unit smoke standard full | PASS | 0.1s | pass |
| 271 | Rejects line with wrong url | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 272 | Accepts valid method and url | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 273 | Rejects line with wrong method | UnitTest | unit smoke standard full | PASS | 0.1s | pass |
| 274 | RequestSlot elapsedTime increases over time | UnitTest | unit smoke standard full | PASS | 0.2s | pass |
| 275 | BatchAPIController response includes reasoningContent when model supports thinking | UnitTest | unit smoke standard full | PASS | 0.8s | pass |
| 276 | BatchAPIController response includes logprobs when provided in stream | UnitTest | unit smoke standard full | PASS | 0.8s | pass |
| 277 | BatchAPIController response includes tool_calls with correct finish_reason | UnitTest | unit smoke standard full | PASS | 0.8s | pass |
| 278 | Binary exists at .build/arm64-apple-macosx/release/afm | Preflight | unit smoke standard full | PASS | 0.0s | file exists |
| 279 | Server reachable at http://127.0.0.1:9998 | Preflight | unit smoke standard full | PASS | 0.0s | 200 OK |
| 280 | /v1/models contains model ID | Lifecycle | unit smoke standard full | PASS | 0.0s | model in response |
| 281 | Basic completion returns content | Lifecycle | unit smoke standard full | PASS | 4.6s | non-empty content or reasoning |
| 282 | Stop string '5' absent from output | Stop | unit smoke standard full | PASS | 2.2s | no '5' in content |
| 283 | finish_reason is 'stop' with stop sequence | Stop | unit smoke standard full | PASS | 0.0s | stop |
| 284 | Multi-word stop 'and' truncates correctly | Stop | unit smoke standard full | PASS | 2.2s | no 'and' in output |
| 285 | Stop on newline produces single line | Stop | unit smoke standard full | PASS | 1.9s | single line |
| 286 | Multiple stop sequences [7, 12] | Stop | unit smoke standard full | PASS | 2.2s | neither found |
| 287 | Empty stop array is no-op | Stop | unit smoke standard full | PASS | 2.7s | valid output |
| 288 | Streaming: stop string '5' absent | Stop | unit smoke standard full | PASS | 2.2s | no '5' in stream |
| 289 | Stop sequence '3.' truncates list | Stop | standard full | PASS | 1.1s | no '3.' in output |
| 290 | Stop 'stopped' doesn't fire on 'stopping' | Stop | standard full | PASS | 2.1s | output produced |
| 291 | Stop 'llo' fires mid-word in 'hello' | Stop | standard full | PASS | 2.0s | no 'llo' |
| 292 | ChoiceLogprobs JSON schema valid | Logprobs | smoke standard full | PASS | 0.2s | valid schema |
| 293 | top_logprobs count <= requested (5) | Logprobs | smoke standard full | PASS | 0.2s | count valid |
| 294 | logprobs=false returns null | Logprobs | smoke standard full | PASS | 0.1s | null logprobs |
| 295 | top_logprobs=99 returns 400 | Logprobs | smoke standard full | PASS | 0.0s | 400 |
| 296 | Streaming logprobs present and valid | Logprobs | standard full | PASS | 0.2s | valid |
| 297 | top_logprobs=0 returns empty arrays | Logprobs | standard full | PASS | 0.2s | empty top_logprobs |
| 298 | reasoning_content present in response | Think | smoke standard full | PASS | 0.0s | present |
| 299 | No <think> tags in content field | Think | smoke standard full | PASS | 0.0s | clean content |
| 300 | Streaming: reasoning_content in deltas | Think | smoke standard full | PASS | 1.1s | present |
| 301 | Stop sequence doesn't break think extraction | Think | smoke standard full | PASS | 2.2s | response ok |
| 302 | reasoning_content has meaningful length (>5 chars) | Think | smoke standard full | PASS | 0.0s | >5 chars |
| 303 | Basic tool call: finish_reason=tool_calls, valid args | Tools | smoke standard full | PASS | 1.0s | valid |
| 304 | tool_choice=none suppresses tool calls | Tools | smoke standard full | PASS | 1.1s | no tool calls |
| 305 | Tool arguments are valid JSON dict | Tools | standard full | PASS | 1.0s | valid JSON |
| 306 | Streaming: tool calls with finish_reason | Tools | standard full | PASS | 1.0s | valid |
| 307 | Multi-tool: at least 1 tool call with 2 tools | Tools | standard full | PASS | 1.2s | >=1 calls |
| 308 | Array param: todos is JSON array (not string) | Tools | standard full | PASS | 1.5s | array |
| 309 | Nullable param: anyOf [string, null] does not crash | Tools | standard full | PASS | 0.9s | no crash |
| 310 | Multi-turn: tool result produces valid follow-up | Tools | standard full | PASS | 3.8s | text response |
| 311 | Multi-turn nullable: full round-trip (anyOf params) | Tools | standard full | PASS | 2.0s | valid follow-up |
| 312 | No tools: normal text response | Tools | standard full | PASS | 0.3s | text response |
| 313 | First unique request: uncached suffix remains | Cache | standard full | PASS | 0.4s | cached_tokens < prompt_tokens |
| 314 | Shared-prefix request: cached_tokens>0 | Cache | standard full | FAIL | 0.4s | Expected: >0\nActual: FAIL: cached_tokens=0 |
| 315 | Exact replay: cached response matches cold response | Cache | standard full | PASS | 0.4s | same content |
| 316 | Different unique prompt: uncached suffix remains | Cache | standard full | PASS | 0.4s | cached_tokens < prompt_tokens |
| 317 | Streaming shared-prefix: cached_tokens>0 in usage chunk | Cache | standard full | FAIL | 0.9s | Expected: >0\nActual: FAIL: no cached_tokens>0 in stream usage |
| 318 | Streaming replay: content matches non-streaming warmup | Cache | standard full | PASS | 1.0s | same content |
| 319 | Concurrent x8 shared-prefix: uncached suffix remains on every branch | Cache | standard full | FAIL | 3.8s | Expected: 0 < cached_tokens < prompt_tokens for all 8\nActual: FAIL: 1:0/59, 2:0/59, 3:0/59, 4:0/59, 5:0/59, 6:0/59, 7:0/59, 8:0/59 |
| 320 | Concurrent x8 shared-prefix: divergent suffix responses stay isolated | Cache | standard full | FAIL | 3.8s | Expected: each of 8 responses keeps only its own marker\nActual: FAIL: 1:error=Expecting value: line 1 column 1 (char 0); 2:error=Expecting value: line 1 column 1 (char 0); 3:error=Expecting value: line 1 column 1 (char 0); 4:error=Expecting value: line 1 column 1 (char 0); 5:error=Expecting value: line 1 column 1 (char 0); 6:error=Expecting value: line 1 column 1 (char 0); 7:error=Expecting value: line 1 column 1 (char 0); 8:error=Expecting value: line 1 column 1 (char 0) |
| 321 | Two simultaneous requests: both 200 | Concurrent | standard full | PASS | 0.3s | 200+200 |
| 322 | Three simultaneous requests: all 200 | Concurrent | standard full | PASS | 0.4s | all 200 |
| 323 | Empty messages → 400 | Error | smoke standard full | PASS | 0.0s | 400 |
| 324 | Malformed JSON → 400 | Error | smoke standard full | PASS | 0.0s | 400 |
| 325 | Missing messages field → 400 | Error | smoke standard full | PASS | 0.0s | 400 |
| 326 | response_format json_object returns valid JSON | Error | smoke standard full | PASS | 0.3s | valid JSON |
| 327 | max_tokens=5 is respected | Error | smoke standard full | PASS | 0.2s | <=10 tokens |
| 328 | OPTIONS /v1/chat/completions → 200 (CORS) | Error | smoke standard full | PASS | 0.0s | 200 |
| 329 | developer role accepted (mapped to system) | Error | smoke standard full | PASS | 5.2s | valid response |
| 330 | enable_thinking=false disables thinking | Kwargs | standard full | PASS | 0.1s | no_think |
| 331 | Streaming: enable_thinking=false disables thinking | Kwargs | standard full | PASS | 0.1s | no_think |
| 332 | Default (no kwargs) retains thinking | Kwargs | standard full | PASS | 1.8s | thinking |
| 333 | enable_thinking=false (2K tokens) returns content | Kwargs | standard full | PASS | 0.1s | content present, no reasoning |
| 334 | enable_thinking=true explicitly keeps thinking | Kwargs | standard full | PASS | 1.8s | thinking |
| 335 | Prefix cache reuse across requests | Cache | standard full | PASS | 0.4s | valid response on cache hit |
| 336 | Issue #32: sequential guided-json → nullable tool (no crash) | Cache | standard full | PASS | 3.7s | both succeed |
| 337 | Sequential: 3 nullable tool calls (cache reuse) | Cache | standard full | PASS | 3.5s | 3/3 succeed |
| 338 | Multi-turn: 5-msg tool conversation with prefix cache | Cache | standard full | PASS | 1.8s | valid response |
| 339 | Long system prompt: 3 sequential requests (prefix reuse) | Cache | standard full | PASS | 7.0s | 3/3 succeed |
| 340 | Sequential stress: 5 mixed requests (text/tool/json/stream/nullable) | Cache | standard full | PASS | 4.1s | 5/5 succeed |
| 341 | Multi-turn: 5-turn growing conversation (prefix reuse) | Cache | standard full | PASS | 6.1s | 5/5 turns |
| 342 | Streaming + non-streaming sequential (shared prefix) | Cache | standard full | PASS | 1.3s | 3/3 succeed |
| 343 | Issue #32 comprehensive: nullable tool + multi-turn + prefix | Cache | standard full | PASS | 2.6s | valid response |
| 344 | json_schema produces valid schema-matching JSON | Structured | standard full | PASS | 0.4s | valid JSON |
| 345 | TTFT < 5s | Perf | full | PASS | 0.6s | <5000ms |
| 346 | tok/s > 1 (81.2 tok/s) | Perf | full | PASS | 0.6s | >1 |
| 347 | Long context (~2K tokens) no crash | Perf | full | PASS | 6.0s | valid response |
| 348 | Very long context (~4K tokens) no NaN/garbage | Perf | full | PASS | 8.1s | clean output |
| 349 | Function name correctly extracted | XMLTools | standard full | PASS | 1.1s | get_weather |
| 350 | Parameter values are correct string types | XMLTools | standard full | FAIL | 0.8s | Expected: strings\nActual: FAIL: location=str(), unit=str() |
| 351 | Mixed-type params (string+bool+int) parse correctly | XMLTools | standard full | PASS | 1.2s | valid types |
| 352 | Nested object param survives XML parsing | XMLTools | standard full | PASS | 1.2s | valid dict |
| 353 | tool_choice=required forces tool call | XMLTools | standard full | PASS | 1.1s | tool_calls |
| 354 | tool_choice={function: get_time} calls correct function | XMLTools | standard full | PASS | 0.9s | get_time |
| 355 | Tool call IDs are unique | XMLTools | standard full | PASS | 1.2s | unique IDs |
| 356 | Streaming: XML tool call assembles valid JSON args | XMLTools | standard full | PASS | 1.1s | valid |
| 357 | Streaming: array param is JSON array (not string) | XMLTools | standard full | PASS | 1.4s | array |
| 358 | Tool call matches OpenAI schema (id, type, function.name, function.arguments) | XMLTools | standard full | PASS | 1.1s | valid schema |
| 359 | Normal XML tool call works with afm_adaptive_xml | AdaptiveXML | standard full | PASS | 1.1s | valid tool call |
| 360 | Streaming tool call emits valid deltas | AdaptiveXML | standard full | PASS | 1.1s | name + JSON args |
| 361 | Multi-turn: model responds after tool result | AdaptiveXML | standard full | PASS | 2.4s | non-empty content |
| 362 | tool_choice=none suppresses tool calls | AdaptiveXML | standard full | PASS | 2.2s | no tool_calls |
| 363 | Multiple tools: correct function selected | AdaptiveXML | standard full | PASS | 1.0s | get_time |
| 364 | Argument types coerced (string, bool, int) | AdaptiveXML | standard full | PASS | 1.2s | correct types |
| 365 | Tool call valid (with or without grammar constraints) | AdaptiveXML | standard full | PASS | 1.1s | valid |
| 366 | Array of objects coercion (question tool pattern) | AdaptiveXML | standard full | PASS | 1.6s | array of dicts |
| 367 | Number (float) and boolean coercion | AdaptiveXML | standard full | PASS | 1.1s | correct types |
| 368 | Nested object with typed fields coercion | AdaptiveXML | standard full | PASS | 1.3s | correct types |
| 369 | Streaming array coercion (incremental path) | AdaptiveXML | standard full | PASS | 2.3s | array in stream |
| 370 | XML entity decoding in tool call values | AdaptiveXML | standard full | PASS | 3.2s | decoded |
| 371 | EBNF grammar enforces all required params present | AdaptiveXML | standard full | PASS | 1.2s | command + description |
| 372 | EBNF structured params: array gets json_array constraint | AdaptiveXML | standard full | PASS | 1.2s | tags is array |
| 373 | Calculator tool call (non-streaming) | Grammar | standard full | PASS | 1.8s | calculate(expression) |
| 374 | Calculator tool call (streaming) | Grammar | standard full | PASS | 1.6s | calculate(expression) via SSE |
| 375 | Two tools: grammar allows correct selection | Grammar | standard full | PASS | 1.1s | get_weather selected |
| 376 | Two tools: grammar selects calculate | Grammar | standard full | PASS | 1.2s | calculate selected |
| 377 | Grammar enforces 3 required params (send_email) | Grammar | standard full | PASS | 1.5s | to + subject + body |
| 378 | Grammar constrains array param at generation time | Grammar | standard full | PASS | 1.4s | tags is array |
| 379 | Grammar array param via streaming | Grammar | standard full | PASS | 1.3s | tags is array (SSE) |
| 380 | Complex schema: string + int + array + object | Grammar | standard full | PASS | 2.0s | correct types |
| 381 | Header absent when grammar enabled (tool strict:true) | StrictWiring | smoke standard full | PASS | 1.0s | no header |
| 382 | Header absent when grammar enabled (schema strict:true) | StrictWiring | smoke standard full | PASS | 0.5s | no header |
| 383 | No header when strict absent | StrictWiring | smoke standard full | PASS | 0.8s | no header |
| 384 | Streaming json_schema strict:true returns valid JSON | StrictWiring | smoke standard full | PASS | 0.4s | valid JSON with name+age |
| 385 | Streaming tool strict:true returns valid tool call | StrictWiring | smoke standard full | PASS | 1.0s | get_weather(location) |
| 386 | strict:false does not error (best-effort) | StrictWiring | smoke standard full | PASS | 0.8s | valid response |
| 387 | POST /v1/files upload returns file ID | Batch | standard full | PASS | 0.0s | file-* |
| 388 | GET /v1/files/:id returns file metadata | Batch | standard full | PASS | 0.0s | file object |
| 389 | POST /v1/batches creates batch | Batch | standard full | PASS | 0.0s | in_progress/completed |
| 390 | GET /v1/batches/:id polls to completed | Batch | standard full | PASS | 2.1s | completed |
| 391 | Output JSONL contains both results (2/2) | Batch | standard full | PASS | 0.0s | assert-1 + assert-2 |
| 392 | GET /v1/batches lists completed batch | Batch | standard full | PASS | 0.0s | list with ≥1 batch |
| 393 | DELETE /v1/files/:id removes uploaded file | Batch | standard full | PASS | 0.0s | deleted=true |
| 394 | SSE multiplex: 2 non-streaming requests tagged with custom_id | Batch | standard full | PASS | 0.3s | sse-a + sse-b + [DONE] |
| 395 | SSE multiplex: streaming interleaved with finish_reason | Batch | standard full | PASS | 0.4s | str-x + str-y chunks + stop + [DONE] |
| 396 | SSE multiplex rejects duplicate custom_ids | Batch | standard full | PASS | 0.0s | 400 |
| 397 | SSE multiplex rejects empty requests | Batch | standard full | PASS | 0.0s | 400 |
| 398 | batch + top_k + streaming | PairwiseSmoke | standard full | PASS | 0.2s | content present |
| 399 | batch + presence_penalty + non-streaming | PairwiseSmoke | standard full | PASS | 0.2s | finish_reason present |
| 400 | batch + repetition_penalty + logprobs | PairwiseSmoke | standard full | PASS | 0.2s | response valid |
| 401 | batch + all sampling params combined | PairwiseSmoke | standard full | PASS | 0.2s | response valid |
| 402 | streaming parity (same seed → same output) | PairwiseSmoke | standard full | PASS | 0.3s | match |
| 403 | cache idempotency (same seed → same output) | PairwiseSmoke | standard full | PASS | 0.3s | match |