{
 "day": 26,
 "generated": "2026-10-09T13:39:45Z",
 "commit": null,
 "host": "ноутбук владельца, Apple M3 Max, 128 ГБ",
 "model": "qwen3.8:27b (Q4_K_M)",
 "runner": "0.33.3",
 "repeats": 1,
 "options": {
  "num_ctx": 16384,
  "temperature": 0,
  "seed": 42
 },
 "think": false,
 "notes": [
  "В ADR недели у дня 26 было шесть ступеней; прогон сделан восемью задачами, и таблица показывает фактические восемь, а не шесть.",
  "ADR планировал три повтора при temperature 1; прогон сделан при temperature 0 и seed 42, по одному прогону на запрос (решение Р5).",
  "Модели-судьи в этом прогоне не было: верность ставили код и человек, и способ стоит у каждой строки.",
  "Режим «рассуждение включено» прогнан отдельной серией дня 29 — это второй прогон того же запроса, а не вторая задача.",
  "Mac был в обычной работе владельца (Chrome, load average ≈5,4). Это не изолированный стенд: повтор того же запроса в серии дня 29 дал разброс 3,2 %."
 ],
 "prompts": [
  {
   "id": "t1_fact",
   "label": "Факт одной фразой (EN)",
   "level": 1,
   "mode": null,
   "verdict": "верно",
   "scored_by": "механически",
   "reason": "Год 1889 совпал с эталоном.",
   "prompt": "In what year was the Eiffel Tower completed? Answer in one short sentence, nothing else.",
   "answer": "The Eiffel Tower was completed in 1889.",
   "expected": "1889",
   "ttft_s": 3.44,
   "ttft_answer_s": 3.44,
   "tps": 10.48,
   "prompt_tokens": 31,
   "answer_tokens": 14,
   "done_reason": "stop",
   "series": "прогон дня 26",
   "note": "Первый запрос после выгрузки модели: во время до первого токена входит загрузка весов — load_duration 2.8 с."
  },
  {
   "id": "t2_translate",
   "label": "Перевод абзаца EN→RU",
   "level": 2,
   "mode": null,
   "verdict": "верно",
   "scored_by": "вручную",
   "reason": "Перевод сверен по смыслу человеком: пропусков и отсебятины нет.",
   "prompt": "Переведи на русский язык следующий абзац. Выдай только перевод, без комментариев.\n\nRate limiting is the practice of capping how many requests a client may send in a given window of time. A public endpoint backed by a paid API key needs it not as a nicety but as a budget control: without a cap, a single visitor with a script can exhaust a daily allowance in minutes. The usual answer is a counter keyed by client address, checked before the upstream call is made rather than after, so that a rejected request costs nothing but a database read.",
   "answer": "Ограничение частоты запросов — это практика установления верхнего предела количества запросов, которые клиент может отправить за определённый промежуток времени. Публичный эндпоинт, работающий на основе платного API-ключа, нуждается в этом не как в удобном дополнении, а как в механизме контроля бюджета: без ограничения один посетитель со скриптом может исчерпать дневную квоту за считанные минуты. Стандартное решение — счётчик, привязанный к адресу клиента, который проверяется до выполнения запроса к вышестоящему сервису, а не после, чтобы отклонённый запрос обходился лишь в чтение из базы данных.",
   "expected": null,
   "ttft_s": 1.294,
   "ttft_answer_s": 1.294,
   "tps": 6.68,
   "prompt_tokens": 128,
   "answer_tokens": 143,
   "done_reason": "stop",
   "series": "прогон дня 26"
  },
  {
   "id": "t3_arithmetic",
   "label": "Арифметика в несколько шагов",
   "level": 3,
   "mode": null,
   "verdict": "верно",
   "scored_by": "механически",
   "reason": "Ответ 14022 совпал с независимым расчётом на Python.",
   "prompt": "Склад получил 1250 ящиков. 18% из них повреждены и списаны. Из оставшихся ящиков 2/5 отправлены в филиал А, остальные — в филиал Б. Каждый ящик в филиале Б содержит 24 единицы товара, из которых 5% — брак. Сколько исправных единиц товара в филиале Б? В последней строке напиши только целое число.",
   "answer": "Сначала определим количество ящиков, которые не были повреждены.\nВсего ящиков: 1250.\nПовреждено: 18%.\nКоличество поврежденных ящиков: $1250 \\times 0.18 = 225$.\nКоличество исправных ящиков: $1250 - 225 = 1025$.\n\nДалее распределим исправные ящики между филиалами.\nВ филиал А отправлено $\\frac{2}{5}$ от исправных ящиков.\nЗначит, в филиал Б отправлено $1 - \\frac{2}{5} = \\frac{3}{5}$ от исправных ящиков.\nКоличество ящиков в филиале Б: $1025 \\times \\frac{3}{5}$.\n$1025 / 5 = 205$.\n$205 \\times 3 = 615$ ящиков.\n\nТеперь рассчитаем количество единиц товара в филиале Б.\nВ каждом ящике по 24 единицы.\nОбщее количество единиц товара в филиале Б: $615 \\times 24$.\n$615 \\times 24 = 14760$ единиц.\n\nНаконец, определим количество исправных единиц товара.\nБрак составляет 5% от общего количества единиц.\nЗначит, доля исправных единиц составляет $100\\% - 5\\% = 95\\%$.\nКоличество исправных единиц: $14760 \\times 0.95$.\n$14760 \\times 0.95 = 14760 \\times (1 - 0.05) = 14760 - (14760 \\times 0.05)$.\n$14760 \\times 0.05 = 738$.\n$14760 - 738 = 14022$.\n\n14022",
   "expected": "14022",
   "ttft_s": 1.244,
   "ttft_answer_s": 1.244,
   "tps": 10.03,
   "prompt_tokens": 103,
   "answer_tokens": 461,
   "done_reason": "stop",
   "series": "прогон дня 26"
  },
  {
   "id": "t4_calendar",
   "label": "Календарная арифметика",
   "level": 3,
   "mode": "рассуждение выключено",
   "verdict": "частично",
   "scored_by": "механически",
   "reason": "Дата 2027-01-17 верна, день недели нет: модель приняла 9 октября 2026 за четверг (на самом деле пятница) и выдала субботу вместо воскресенья. Смещение 100 дней = 14 недель + 2 дня посчитано верно — подвело знание опорного дня недели, а не счёт.",
   "prompt": "Какая дата будет через 100 дней после 9 октября 2026 года? Назови дату и день недели. В последней строке — только дата в формате ГГГГ-ММ-ДД и день недели через запятую.",
   "answer": "Чтобы определить дату через 100 дней после 9 октября 2026 года, выполним пошаговый подсчет:\n\n1.  **Остаток дней в октябре 2026 года:**\n    В октябре 31 день.\n    Дней осталось в октябре: $31 - 9 = 22$ дня.\n    Осталось добавить: $100 - 22 = 78$ дней.\n\n2.  **Ноябрь 2026 года:**\n    В ноябре 30 дней.\n    Вычитаем эти дни: $78 - 30 = 48$ дней.\n\n3.  **Декабрь 2026 года:**\n    В декабре 31 день.\n    Вычитаем эти дни: $48 - 31 = 17$ дней.\n\n4.  **Январь 2027 года:**\n    Оставшиеся 17 дней приходятся на январь 2027 года.\n    Значит, дата будет **17 января 2027 года**.\n\nТеперь определим день недели.\n9 октября 2026 года — это **четверг** (можно проверить по календарю или формуле).\n\nПосчитаем количество дней между 9 октября 2026 и 17 января 2027:\nВсего дней: 100.\n$100 \\div 7 = 14$ недель и $2$ дня остатка.\n\nЧетверг + 2 дня = **суббота**.\n\nПроверка:\n- 9 октября 2026 — Четверг\n- 10 октября — Пятница\n- 11 октября — Суббота\n...\n- 17 января 2027 — Суббота\n\nОтвет:\n2027-01-17, суббота",
   "expected": "2027-01-17, воскресенье",
   "ttft_s": 0.805,
   "ttft_answer_s": 0.805,
   "tps": 9.08,
   "prompt_tokens": 67,
   "answer_tokens": 433,
   "done_reason": "stop",
   "series": "прогон дня 26"
  },
  {
   "id": "t4_calendar_think",
   "label": "Календарная арифметика",
   "level": 3,
   "mode": "рассуждение включено",
   "verdict": "верно",
   "scored_by": "механически",
   "reason": "С включённым рассуждением модель сама исправила опорный день недели: 2027-01-17, воскресенье — совпало с расчётом datetime.",
   "prompt": "Какая дата будет через 100 дней после 9 октября 2026 года? Назови дату и день недели. В последней строке — только дата в формате ГГГГ-ММ-ДД и день недели через запятую.",
   "answer": "## Подсчёт\n\n**Исходная дата:** 9 октября 2026 г. (пятница)\n\nДобавляем 100 дней:\n\n| Месяц | Дней в месяце | Остаток после вычитания |\n|-------|--------------|------------------------|\n| Октябрь (с 9-го) | 22 дня (до 31.10) | 100 − 22 = 78 |\n| Ноябрь | 30 дней | 78 − 30 = 48 |\n| Декабрь | 31 день | 48 − 31 = 17 |\n| Январь | 17-е число | **17 января 2027** |\n\n**День недели:** 100 mod 7 = 2 → пятница + 2 = **воскресенье**.\n\nПроверка: 1 января 2027 — пятница; 17 января = +16 дней; 16 mod 7 = 2; пятница + 2 = воскресенье. ✓\n\n2027-01-17, воскресенье",
   "expected": "2027-01-17, воскресенье",
   "ttft_s": 0.154,
   "ttft_answer_s": 81.205,
   "tps": 9.6,
   "prompt_tokens": 65,
   "answer_tokens": 1063,
   "done_reason": null,
   "series": "серия «рассуждение» дня 29",
   "note": "Прогнано отдельной серией дня 29, не этим прогоном. Честная пара внутри той же серии: с выключенным рассуждением — 0.9 с до ответа, 8.79 ток/с, 433 токенов ответа и тот же неверный день недели; с включённым — 81.2 с до первого видимого токена, 9.6 ток/с, 1063 токенов ответа и верный ответ. Поток при включённом рассуждении начинается через 0.15 с, но до первого токена видимого ответа проходит 81.2 с: всё это время идут токены рассуждения."
  },
  {
   "id": "t8_ru_question",
   "label": "Вопрос по-русски: 429 против 503",
   "level": 3,
   "mode": null,
   "verdict": "верно",
   "scored_by": "вручную",
   "reason": "Смысл 429 и 503 передан верно, Retry-After упомянут; сверено человеком.",
   "prompt": "Чем отличается HTTP-код 429 от 503? Ответь двумя короткими абзацами: когда уместен каждый и что должен сделать клиент.",
   "answer": "Код 429 (Too Many Requests) используется, когда клиент отправляет слишком много запросов за определённый период времени, превышая лимиты сервера. В этом случае клиенту следует временно прекратить отправку запросов и повторить попытку позже, ориентируясь на заголовок `Retry-After`, если он присутствует.\n\nКод 503 (Service Unavailable) означает, что сервер временно не может обработать запрос из-за перегрузки или планового обслуживания. Здесь клиенту также рекомендуется подождать и повторить запрос, но без изменения частоты отправки, так как проблема связана с состоянием сервера, а не с поведением клиента.",
   "expected": null,
   "ttft_s": 0.829,
   "ttft_answer_s": 0.829,
   "tps": 7.22,
   "prompt_tokens": 48,
   "answer_tokens": 143,
   "done_reason": "stop",
   "series": "прогон дня 26"
  },
  {
   "id": "t5_code_js",
   "label": "Функция на JS",
   "level": 4,
   "mode": null,
   "verdict": "верно",
   "scored_by": "механически",
   "reason": "Код записан в файл и запущен в Node 22 против 8 наборов, включая краевые: 8 из 8.",
   "prompt": "Напиши на JavaScript функцию `compress(input)`, которая выполняет run-length encoding строки: подряд идущие одинаковые символы заменяются на символ и число повторов, но одиночный символ остаётся без числа. Примеры: compress(\"aaabccddd\") === \"a3bc2d3\"; compress(\"abc\") === \"abc\"; compress(\"\") === \"\". Выдай только код функции, объявленной как `function compress(input) { ... }`, без пояснений, без markdown-разметки, без примеров использования.",
   "answer": "function compress(input) {\n    if (!input) return \"\";\n    let result = \"\";\n    let count = 1;\n    for (let i = 1; i <= input.length; i++) {\n        if (i < input.length && input[i] === input[i - 1]) {\n            count++;\n        } else {\n            result += input[i - 1];\n            if (count > 1) {\n                result += count;\n            }\n            count = 1;\n        }\n    }\n    return result;\n}",
   "expected": null,
   "ttft_s": 1.26,
   "ttft_answer_s": 1.26,
   "tps": 11.55,
   "prompt_tokens": 122,
   "answer_tokens": 124,
   "done_reason": "stop",
   "series": "прогон дня 26"
  },
  {
   "id": "t7_json",
   "label": "JSON по схеме",
   "level": 4,
   "mode": null,
   "verdict": "верно",
   "scored_by": "механически",
   "reason": "JSON разобран и проверен против схемы: типы, required, minItems/maxItems, лишних полей нет.",
   "prompt": "Придумай три вымышленных новости о стартапах в сфере fintech и верни их строго по заданной JSON-схеме. Год — целое число. Ответ — только JSON.",
   "answer": "{\n  \"sphere\": \"fintech\",\n  \"items\": [\n    {\n      \"title\": \"Стартап NeoPay привлёк $50 млн для развития ИИ-ассистента по управлению личными финансами\",\n      \"company\": \"NeoPay\",\n      \"year\": 2023,\n      \"tags\": [\n        \"AI\",\n        \"Personal Finance\"\n      ]\n    },\n    {\n      \"title\": \"FinTech-компания CryptoBridge запустила первый в мире мост для мгновенных переводов между 10 блокчейнами\",\n      \"company\": \"CryptoBridge\",\n      \"year\": 2024,\n      \"tags\": [\n        \"Blockchain\",\n        \"Cross-border Payments\"\n      ]\n    },\n    {\n      \"title\": \"InsureTech-стартап HealthGuard представил динамическое страхование здоровья на основе носимых устройств\",\n      \"company\": \"HealthGuard\",\n      \"year\": 2022,\n      \"tags\": [\n        \"Insurance\",\n        \"Wearables\"\n      ]\n    }\n  ]\n}",
   "expected": null,
   "ttft_s": 0.865,
   "ttft_answer_s": 0.865,
   "tps": 7.1,
   "prompt_tokens": 53,
   "answer_tokens": 267,
   "done_reason": "stop",
   "series": "прогон дня 26"
  },
  {
   "id": "t6_summarize",
   "label": "Выжимка документа на 4,5 тыс. токенов входа",
   "level": 5,
   "mode": null,
   "verdict": "верно",
   "scored_by": "вручную",
   "reason": "Все пять пунктов выжимки найдены в исходном документе человеком; выдумок нет.",
   "prompt": "Ниже — документ об архитектуре проекта. Сделай выжимку: ровно 5 пунктов списка, каждый не длиннее двух строк, только о том, что реально сказано в документе. Не добавляй ничего, чего в тексте нет.\n\n---\n\n# Архитектура\n\n## Обзор\n\nМонорепозиторий: одно задание челленджа — один каталог `days/dayN/` — один контейнер. Единственный VPS с Caddy принимает `challenge.zpq.ai` и маршрутизирует префикс пути в к\n\n[... документ целиком: agent_docs/architecture.md, 12985 символов ...]",
   "answer": "1. Монорепозиторий с изолированными днями в контейнерах, деплой через GitHub Actions и GHCR на VPS с Caddy.\n2. Архитектура включает сервисы `router`, `agents`, `mcp` и `rag` для управления LLM-провайдерами, агентами и поиском.\n3. Контроль расхода API-ключей реализован через лимиты на процесс и общие секреты на сервере, а не на стороне клиента.\n4. Изоляция сетей compose для разных сервисов ограничивает доступность внутренних компонентов, таких как Ollama и агенты.\n5. Новые дни добавляются путем создания каталога, настройки маршрутов в Caddy и сервиса в compose.yml.",
   "expected": null,
   "ttft_s": 35.19,
   "ttft_answer_s": 35.19,
   "tps": 5.8,
   "prompt_tokens": 4505,
   "answer_tokens": 165,
   "done_reason": "stop",
   "series": "прогон дня 26",
   "note": "Вход 4505 токенов обработан за 35.1 с — это ≈128 токенов входа в секунду, и дольше, чем вся генерация ответа. Параметрами генерации это не лечится."
  }
 ],
 "access": [
  {
   "label": "CLI ollama run",
   "answer_ok": true,
   "ttft_s": null,
   "ttft_answer_s": null,
   "tps": 11.02,
   "prompt_tokens": 31,
   "answer_tokens": 14,
   "engine_durations": true,
   "gives": "сводка в конце: counts, длительности, eval rate и число кэшированных токенов входа. Времени до первого токена нет — ответ приходит целиком.",
   "reasoning_chars": null
  },
  {
   "label": "HTTP /api/generate",
   "answer_ok": true,
   "ttft_s": 3.764,
   "ttft_answer_s": 3.764,
   "tps": 8.4,
   "prompt_tokens": 31,
   "answer_tokens": 14,
   "engine_durations": true,
   "gives": "полный набор: prompt_eval_count, eval_count, prompt_eval_cached_count, все *_duration и load_duration. Время до первого токена считается по потоку.",
   "reasoning_chars": null
  },
  {
   "label": "HTTP /v1/chat/completions, по умолчанию",
   "answer_ok": true,
   "ttft_s": 8.35,
   "ttft_answer_s": 11.893,
   "tps": null,
   "prompt_tokens": 29,
   "answer_tokens": 48,
   "engine_durations": false,
   "gives": "только usage: prompt_tokens, completion_tokens, cached_tokens. Длительностей от движка нет — скорость считается лишь по стенным часам.",
   "reasoning_chars": 121
  },
  {
   "label": "HTTP /v1/chat/completions, reasoning_effort: none",
   "answer_ok": true,
   "ttft_s": 0.489,
   "ttft_answer_s": 0.489,
   "tps": null,
   "prompt_tokens": 31,
   "answer_tokens": 14,
   "engine_durations": false,
   "gives": "только usage: prompt_tokens, completion_tokens, cached_tokens. Длительностей от движка нет — скорость считается лишь по стенным часам.",
   "reasoning_chars": 0
  }
 ],
 "speed_vs_content": {
  "series": "серия «скорость против предсказуемости текста» дня 29",
  "options": {
   "num_ctx": 8192,
   "temperature": 0,
   "seed": 42,
   "num_predict": 200
  },
  "cases": [
   {
    "label": "предельно предсказуемый текст",
    "tps": null
   },
   {
    "label": "проза по-английски",
    "tps": 6.02
   },
   {
    "label": "проза по-русски",
    "tps": 5.54
   },
   {
    "label": "код на JS",
    "tps": 11.07
   },
   {
    "label": "цифры",
    "tps": 11.42
   }
  ]
 },
 "speculative": {
  "draft_num_predict": 4,
  "accepted_fraction": {
   "min": 0.34337,
   "max": 1.0,
   "samples": 46,
   "by_text_kind": null
  },
  "log_lines": [
   "spec common_specu: adding speculative implementation 'draft-mtp'",
   "srv    load_model: speculative decoding context initialized"
  ],
  "documented_in_library": false
 }
}
