{
  "measuredAt": "2026-07-24T14:05:57.366Z",
  "hardware": {
    "chip": "Apple M2 Max",
    "unifiedMemoryGb": 32,
    "ollamaVersion": "0.19.0"
  },
  "runtime": {
    "provider": "Ollama",
    "endpoint": "local-only",
    "platform": "darwin",
    "architecture": "arm64",
    "temperature": 0,
    "seed": 42,
    "contextTokens": 4096,
    "runsPerTask": 1,
    "modelUnloadedBeforeRun": true,
    "apiCostUsd": 0,
    "electricityAndHardwareCostMeasured": false
  },
  "tasks": [
    {
      "id": "merge-intervals",
      "tests": 7
    },
    {
      "id": "parse-duration",
      "tests": 9
    },
    {
      "id": "topological-sort",
      "tests": 7
    }
  ],
  "summary": [
    {
      "model": "hermes3:8b",
      "modelSizeGb": 4.66,
      "tasksPassed": 0,
      "tasksTotal": 3,
      "testsPassed": 9,
      "testsTotal": 23,
      "passRatePercent": 39.1,
      "totalSeconds": 30.74,
      "medianGenerationTokensPerSecond": 65.17,
      "aggregateGenerationTokensPerSecond": 65.2,
      "apiCostUsd": 0
    },
    {
      "model": "qwen3.5:9b",
      "modelSizeGb": 6.59,
      "tasksPassed": 1,
      "tasksTotal": 3,
      "testsPassed": 11,
      "testsTotal": 23,
      "passRatePercent": 47.8,
      "totalSeconds": 57.44,
      "medianGenerationTokensPerSecond": 28.47,
      "aggregateGenerationTokensPerSecond": 28.46,
      "apiCostUsd": 0
    },
    {
      "model": "qwen2.5-coder:14b",
      "modelSizeGb": 8.99,
      "tasksPassed": 1,
      "tasksTotal": 3,
      "testsPassed": 20,
      "testsTotal": 23,
      "passRatePercent": 87,
      "totalSeconds": 69.96,
      "medianGenerationTokensPerSecond": 30.64,
      "aggregateGenerationTokensPerSecond": 30.52,
      "apiCostUsd": 0
    }
  ],
  "results": [
    {
      "model": "hermes3:8b",
      "task": "merge-intervals",
      "testsPassed": 3,
      "testsTotal": 7,
      "failures": [
        "empty: AssertionError",
        "does-not-mutate: AssertionError",
        "invalid-pair: expected TypeError",
        "invalid-number: expected TypeError"
      ],
      "generatedCode": "function mergeIntervals(intervals) {\n  if (!Array.isArray(intervals)) throw new TypeError('Input must be an array');\n\n  intervals.sort((a, b) => a[0] - b[0]);\n\n  const merged = [intervals[0]];\n  for (let i = 1; i < intervals.length; i++) {\n    const last = merged[merged.length - 1];\n    if (last[1] >= intervals[i][0]) {\n      merged[merged.length - 1] = [last[0], Math.max(last[1], intervals[i][1])];\n    } else {\n      merged.push(intervals[i]);\n    }\n  }\n\n  return merged;\n}",
      "promptTokens": 94,
      "outputTokens": 174,
      "totalSeconds": 12.3,
      "loadSeconds": 0.63,
      "generationTokensPerSecond": 65.39
    },
    {
      "model": "hermes3:8b",
      "task": "parse-duration",
      "testsPassed": 4,
      "testsTotal": 9,
      "failures": [
        "milliseconds: TypeError",
        "seconds: TypeError",
        "decimal-minutes: TypeError",
        "trim-and-case: TypeError",
        "zero: TypeError"
      ],
      "generatedCode": "function parseDuration(input) {\n  if (typeof input !== 'string' || input.trim().length === 0) {\n    throw new TypeError('Input must be a non-empty string');\n  }\n\n  const match = input.trim().match(/(\\b[0-9]+(?:\\b[.][0-9]+)?)(ms|s|m|h|d)/i);\n  if (!match || !match[1] || !match[2]) {\n    throw new TypeError('Invalid duration format');\n  }\n\n  const [number, unit] = match.slice(1).map(Number);\n  let milliseconds = number;\n\n  switch (unit.toLowerCase()) {\n    case 'ms': break;\n    case 's': milliseconds *= 1000; break;\n    case 'm': milliseconds *= 60000; break;\n    case 'h': milliseconds *= 3600000; break;\n    case 'd': milliseconds *= 86400000; break;\n    default: throw new TypeError('Invalid unit');\n  }\n\n  return Math.floor(milliseconds);}\n",
      "promptTokens": 103,
      "outputTokens": 250,
      "totalSeconds": 8.84,
      "loadSeconds": 0.09,
      "generationTokensPerSecond": 65.17
    },
    {
      "model": "hermes3:8b",
      "task": "topological-sort",
      "testsPassed": 2,
      "testsTotal": 7,
      "failures": [
        "deterministic-dag: AssertionError",
        "lexicographic-choice: AssertionError",
        "isolated-nodes: AssertionError",
        "duplicate-node: expected TypeError",
        "does-not-mutate: AssertionError"
      ],
      "generatedCode": "function topologicalSort(nodes, edges) {\n  if (nodes.length === 0 || edges.length === 0) {\n    return null;\n  }\n\n  const nodeMap = new Map(nodes.map(node => [node, { inDegree: 0 }]));\n  for (const [from, to] of edges) {\n    if (!nodeMap.has(from) || !nodeMap.has(to)) {\n      throw new TypeError(\"Malformed edge or unknown nodes\");\n    }\n    nodeMap.get(to).inDegree++;\n  }\n\n  const result = [];\n  for (const [node] of nodeMap) {\n    if (node.inDegree === 0) {\n      dfs(node, nodeMap, result);\n    }\n  }\n\n  return result.length === nodes.length ? result : null;\n\n  function dfs(node, nodeMap, result) {\n    nodeMap.delete(node);\n    for (const [neighbor] of nodeMap) {\n      if (--neighbor.inDegree === 0) {\n        dfs(neighbor, nodeMap, result);\n      }\n    }\n    result.unshift(node.key);\n  }\n}",
      "promptTokens": 125,
      "outputTokens": 267,
      "totalSeconds": 9.6,
      "loadSeconds": 0.09,
      "generationTokensPerSecond": 65.11
    },
    {
      "model": "qwen3.5:9b",
      "task": "merge-intervals",
      "testsPassed": 7,
      "testsTotal": 7,
      "failures": [],
      "generatedCode": "function mergeIntervals(intervals) {\n  if (!Array.isArray(intervals)) {\n    throw new TypeError('Input must be an array');\n  }\n  \n  for (let i = 0; i < intervals.length; i++) {\n    const interval = intervals[i];\n    if (!Array.isArray(interval) || interval.length !== 2) {\n      throw new TypeError('Each interval must be an array of two numbers');\n    }\n    const [start, end] = interval;\n    if (typeof start !== 'number' || typeof end !== 'number') {\n      throw new TypeError('Interval values must be numbers');\n    }\n    if (start > end) {\n      throw new TypeError('Start must be less than or equal to end');\n    }\n  }\n  \n  if (intervals.length === 0) {\n    return [];\n  }\n  \n  const sorted = [...intervals].sort((a, b) => a[0] - b[0]);\n  const result = [sorted[0]];\n  \n  for (let i = 1; i < sorted.length; i++) {\n    const current = sorted[i];\n    const last = result[result.length - 1];\n    \n    if (current[0] <= last[1]) {\n      result[result.length - 1] = [last[0], Math.max(last[1], current[1])];\n    } else {\n      result.push(current);\n    }\n  }\n  \n  return result;\n}",
      "promptTokens": 104,
      "outputTokens": 359,
      "totalSeconds": 17.96,
      "loadSeconds": 4.4,
      "generationTokensPerSecond": 28.54
    },
    {
      "model": "qwen3.5:9b",
      "task": "parse-duration",
      "testsPassed": 4,
      "testsTotal": 9,
      "failures": [
        "milliseconds: TypeError",
        "seconds: TypeError",
        "decimal-minutes: AssertionError",
        "trim-and-case: TypeError",
        "zero: TypeError"
      ],
      "generatedCode": "function parseDuration(input) {\n  if (typeof input !== 'string') {\n    throw new TypeError('Input must be a string');\n  }\n\n  const trimmed = input.trim();\n  if (trimmed === '') {\n    throw new TypeError('Empty input');\n  }\n\n  const units = ['ms', 's', 'm', 'h', 'd'];\n  const regex = /^(\\d+(\\.\\d+)?)\\s*(ms|s|m|h|d)$/i;\n  const match = trimmed.match(regex);\n\n  if (!match) {\n    throw new TypeError('Invalid format: missing unit, signs, scientific notation, or trailing text');\n  }\n\n  const value = parseFloat(match[1]);\n  const unit = match[2].toLowerCase();\n\n  if (isNaN(value) || value < 0) {\n    throw new TypeError('Value must be a non-negative decimal number');\n  }\n\n  const conversions = {\n    ms: 1,\n    s: 1000,\n    m: 60000,\n    h: 3600000,\n    d: 86400000\n  };\n\n  return value * conversions[unit];\n}",
      "promptTokens": 112,
      "outputTokens": 300,
      "totalSeconds": 11.35,
      "loadSeconds": 0.16,
      "generationTokensPerSecond": 28.47
    },
    {
      "model": "qwen3.5:9b",
      "task": "topological-sort",
      "testsPassed": 0,
      "testsTotal": 7,
      "failures": ["response could not be executed"],
      "parseError": "SyntaxError: Unexpected end of JSON input",
      "rawResponseExcerpt": "{\"code\":\"function topologicalSort(nodes, edges) { ... [output reached the 768-token ceiling before the JSON object closed]",
      "promptTokens": 137,
      "outputTokens": 768,
      "totalSeconds": 28.13,
      "loadSeconds": 0.14,
      "generationTokensPerSecond": 28.42
    },
    {
      "model": "qwen2.5-coder:14b",
      "task": "merge-intervals",
      "testsPassed": 6,
      "testsTotal": 7,
      "failures": ["does-not-mutate: AssertionError"],
      "generatedCode": "function mergeIntervals(intervals) {\n  if (!Array.isArray(intervals)) throw new TypeError('Input must be an array');\n\n  for (let interval of intervals) {\n    if (!Array.isArray(interval) || interval.length !== 2 || typeof interval[0] !== 'number' || typeof interval[1] !== 'number' || interval[0] > interval[1]) {\n      throw new TypeError('Each interval must be an array [start, end] with start <= end');\n    }\n  }\n\n  intervals.sort((a, b) => a[0] - b[0]);\n\n  let merged = [];\n\n  for (let interval of intervals) {\n    if (!merged.length || merged[merged.length - 1][1] < interval[0]) {\n      merged.push(interval);\n    } else {\n      merged[merged.length - 1][1] = Math.max(merged[merged.length - 1][1], interval[1]);\n    }\n  }\n\n  return merged;\n}",
      "promptTokens": 114,
      "outputTokens": 240,
      "totalSeconds": 24.76,
      "loadSeconds": 0.57,
      "generationTokensPerSecond": 30.64
    },
    {
      "model": "qwen2.5-coder:14b",
      "task": "parse-duration",
      "testsPassed": 9,
      "testsTotal": 9,
      "failures": [],
      "generatedCode": "function parseDuration(input) {\n  input = input.trim().toLowerCase();\n  const match = input.match(/^([0-9]+(\\.[0-9]+)?)(ms|s|m|h|d)$/);\n  if (!match) throw new TypeError('Invalid duration format');\n\n  const value = parseFloat(match[1]);\n  const unit = match[3];\n\n  switch (unit) {\n    case 'ms': return value;\n    case 's': return value * 1000;\n    case 'm': return value * 60 * 1000;\n    case 'h': return value * 60 * 60 * 1000;\n    case 'd': return value * 24 * 60 * 60 * 1000;\n    default: throw new TypeError('Invalid duration unit');\n  }\n}",
      "promptTokens": 123,
      "outputTokens": 211,
      "totalSeconds": 11.65,
      "loadSeconds": 0.08,
      "generationTokensPerSecond": 30.68
    },
    {
      "model": "qwen2.5-coder:14b",
      "task": "topological-sort",
      "testsPassed": 5,
      "testsTotal": 7,
      "failures": [
        "lexicographic-choice: AssertionError",
        "isolated-nodes: AssertionError"
      ],
      "generatedCode": "function topologicalSort(nodes, edges) {\n  function hasCycle(node, visited, recStack) {\n    if (recStack[node]) return true;\n    if (visited[node]) return false;\n    visited[node] = true;\n    recStack[node] = true;\n    const neighbors = adjacencyList.get(node);\n    for (const neighbor of neighbors) {\n      if (hasCycle(neighbor, visited, recStack)) return true;\n    }\n    recStack[node] = false;\n    return false;\n  }\n  const uniqueNodes = new Set(nodes);\n  if (uniqueNodes.size !== nodes.length) throw new TypeError('Duplicate nodes are not allowed.');\n  for (const edge of edges) {\n    if (!Array.isArray(edge) || edge.length !== 2) throw new TypeError('Malformed edge detected.');\n    const [from, to] = edge;\n    if (!nodes.includes(from) || !nodes.includes(to)) throw new TypeError('Edge references unknown node(s).');\n  }\n  const adjacencyList = new Map(nodes.map(node => [node, []]));\n  for (const [from, to] of edges) adjacencyList.get(from).push(to);\n  const visited = {};\n  const recStack = {};\n  const result = [];\n  function dfs(node) {\n    if (recStack[node]) return null;\n    if (visited[node]) return;\n    visited[node] = true;\n    recStack[node] = true;\n    for (const neighbor of adjacencyList.get(node)) {\n      if (!visited[neighbor]) dfs(neighbor);\n      if (hasCycle(neighbor, visited, recStack)) return null;\n    }\n    result.unshift(node);\n    recStack[node] = false;\n  }\n  for (const node of [...nodes].sort()) {\n    if (!visited[node] && dfs(node) === null) return null;\n  }\n  return result;\n}",
      "promptTokens": 145,
      "outputTokens": 622,
      "totalSeconds": 33.55,
      "loadSeconds": 0.08,
      "generationTokensPerSecond": 30.42
    }
  ]
}
