<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="https://androman.pro/wp-content/themes/androman/assets/feed.xsl?ver=0.9.4" type="text/xsl"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>AI &#8212; ANDROMAN.PRO</title>
	<atom:link href="https://androman.pro/tag/ai/feed/" rel="self" type="application/rss+xml" />
	<link>https://androman.pro</link>
	<description>Независимый 1С-архитектор и AI-автоматизация корпоративных процессов: аудит, PoC на реальных данных, проверка качества и внедрение. · build 0.9.4</description>
	<lastBuildDate>Wed, 13 May 2026 21:00:00 +0000</lastBuildDate>
	<language>ru-RU</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>Я хотел CI для тестов 1С. Получил шесть граблей и одну DeepSeek-галлюцинацию</title>
		<link>https://androman.pro/2026/05/14/ci-1c-za-den/</link>
					<comments>https://androman.pro/2026/05/14/ci-1c-za-den/#respond</comments>
		
		<dc:creator><![CDATA[Androman.pro]]></dc:creator>
		<pubDate>Wed, 13 May 2026 21:00:00 +0000</pubDate>
				<category><![CDATA[1С]]></category>
		<category><![CDATA[дев-лог]]></category>
		<category><![CDATA[ИИ-разработка]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Allure]]></category>
		<category><![CDATA[Claude]]></category>
		<category><![CDATA[Gitea]]></category>
		<category><![CDATA[YAxUnit]]></category>
		<guid isPermaLink="false">https://androman.pro/2026/05/14/ci-1c-za-den/</guid>

					<description><![CDATA[За вечер собрал автоматический прогон для 72 тестов 1С — Gitea Actions, Allure, Telegram. Расскажу про шесть граблей и одну галлюцинацию DeepSeek.]]></description>
										<content:encoded><![CDATA[<p>Заметил, что общаясь с Клодом и другими моделями, перенимая их лексикон, всё труднее общаться с живыми людьми. То есть говорить нормальными человеческими фразами, а не промптами, напичканными профессиональным жаргоном. ИИ сильно ускоряет мою производительность, но цена этому — нарастающая асоциальность.</p>
<p>С другой стороны это похоже на ещё одну игру в жанре «ИТ-стратегия», которую я так хочу пройти. Не знаю, какие уровни будут дальше, но вчера я, похоже, взял ещё один уровень. Наконец-то разобрался с одним из элементов CI/CD — автотестами и графическими отчётами к ним.</p>
<p>Ниже в основном творчество Клода, я попросил его писать попроще, потому что для меня тоже многие слова не то чтобы каждый день на языке. У меня теперь разработка так устроена — в основном это приключения на вечер в стиле Рика и Морти, на 20 минут вошли и вышли, которые перетекают в очередную эпопею. Я не проходил курсов, не считаю каждый токен, предварительно выстраивая всю архитектуру на бумажке — я просто чётко (а иногда не очень) формулирую свою задачу и контролирую, чтобы в процессе реализации Клод не ушёл в очень уж густые дебри.</p>
<p>А ещё он меня похвалил, когда кружил вокруг одной проблемы около часа, перепробовал всё и пытался меня отговорить от фичи. Я ему сказал, что не привык сдаваться, и дал небольшую подсказку — через минуту готовое решение было у меня на экране. Никогда бы не подумал, что буду хвалиться тем, что меня похвалила машина.</p>
<hr>
<p>У меня в <a href="https://github.com/andromanpro/1c-ai-connector">ИИконе</a> — это открытое расширение к 1С для интеграции с LLM, над которым плотно сижу с весны — 72 теста YAxUnit. Прогон на полминуты руками, считаю прошедшие и упавшие глазами по длинному JSON. К утру следующего дня вместо этого работал зелёный автопрогон по каждому коммиту в Gitea, дашборд Allure на NAS с историей и Telegram-бот, который ругается, когда тесты падают.</p>
<p>Финальная картинка: <strong>72/72 PASSED, около 29 секунд</strong> от коммита до отчёта в Allure.</p>
<p>По дороге наступил на шесть граблей и одну галлюцинацию DeepSeek.</p>
<h2>Что было до</h2>
<p>Тесты разнесены по 14 общим модулям. YAxUnit умеет писать отчёт в формате JUnit XML — а это как английский для систем прогона: понимают почти все.</p>
<p>До этого прогон выглядел так. Я открывал Claude Code, говорил «прогони тесты». Запускался MCP-инструмент <code>run_module_tests</code>, который под капотом дёргает <code>1cv8.exe ENTERPRISE /C "RunUnitTests=config.json"</code>. На выходе — JSON, в нём список модулей, для каждого — список тестов с результатами.</p>
<p>Я смотрел на JSON и решал, доволен ли я.</p>
<p>Иногда — открывал HTML-отчёт, который YAxUnit любезно генерирует рядом. Иногда — нет. Часто — забывал, что прогонял утром, и не помнил, был ли тогда красный или зелёный.</p>
<p>Не то чтобы это было больно. Просто очевидно бестолково, если задумываться. <strong>Нет истории прогонов. Нет графика по неделям. Нет процента успешных тестов в динамике.</strong> Каждый прогон — снимок, который я тут же забываю.</p>
<p>И ещё — задним числом я не помнил, <strong>что я последний раз сломал</strong>. Если сегодня 70 из 72, а вчера было 72 из 72 — где регрессия? Какой тест начал падать? Когда? Чтобы это понимать, надо вести историю. А чтобы вести историю — надо чтобы прогон жил не в моей голове.</p>
<p>Вот, собственно, и решил.</p>
<h2>Из чего собирал</h2>
<p>Я собрал такой зоопарк:</p>
<ul>
<li><strong>Gitea</strong> на NAS. Простой git-сервер, лёгкая система автопрогонов Gitea Actions внутри.</li>
<li><strong>act_runner</strong> под Windows. Это исполнитель шагов, который умеет крутиться где угодно. У меня — на ноуте, потому что 1С живёт там же.</li>
<li><strong>vanessa-runner</strong> (vrunner). Обвязка для запуска <code>1cv8.exe</code> с человеческим лицом. Умеет YAxUnit, BDD, и кучу другого.</li>
<li><strong>YAxUnit kernel</strong> — собственно тестовый раннер для 1С. Пишет JUnit XML.</li>
<li><strong>Allure server</strong> на NAS. Тот самый Docker-контейнер от <code>frankescobar/allure-docker-service</code>. История прогонов, тренды, графики.</li>
<li><strong>Прометей + Графана + Алертменеджер + Telegram-бот</strong>. Понятно зачем — чтобы когда что-то упало, я узнал об этом из телефона, а не из размышлений «а как там у меня тесты».</li>
</ul>
<p>Вот как это бегает по прямой:</p>
<p><img decoding="async" alt="Стек прогона: коммит в Gitea → Gitea Actions → act_runner на Windows → vrunner → 1cv8.exe + YAxUnit → JUnit XML → upload-to-allure.py → Allure на NAS → Prometheus/Grafana/Alertmanager → Telegram bot" src="https://androman.pro/wp-content/uploads/2026/05/ci-1c-stack-diagram.png"></p>
<p>Всё локальное. Никаких облаков, никаких счётчиков минут на чужих исполнителях. У меня дома NAS, у меня ноут, у NAS — Docker, у ноута — 1С. Этого достаточно.</p>
<h2>Что в итоге за вечер</h2>
<p>За вечер прошёл семь этапов: включил Gitea Actions, поднял Windows-исполнитель, подключил прогон через <code>vrunner</code>, перенёс исполнитель в службу, поднял Allure на NAS, написал переводчик JUnit XML в формат Allure, сверху прикрутил Prometheus с Telegram-ботом. Подробности — в граблях ниже, пошаговый туториал — в <a href="https://github.com/andromanpro/onec-yaxunit-ci-template">README шаблона</a>.</p>
<p>Получилось — коммит в репо → через минуту в Allure лежит свежий отчёт, в Grafana прирастают метрики, в Telegram — тишина, пока зелёное.</p>
<p>А теперь грабли. По штукам.</p>
<h2>Грабля 1 — кириллица в пользователе</h2>
<p>В 1С база лежит файловая, пользователь — «Администратор», пароль — пустой. Так настроено лет десять и до сегодня не мешало.</p>
<p>Запускаю прогон через <code>vrunner</code>. В консоли:</p>
<pre class="highlight"><code>Пользователь ИБ не идентифицирован
</code></pre>
<p>Код выхода 1, прогон умирает за полторы секунды.</p>
<p>Грешу на vrunner. Грешу на YAxUnit. Грешу на конфиг. Перепробовал три варианта параметров, четыре — не помогает.</p>
<p>Запускаю ту же команду напрямую, без vrunner:</p>
<pre class="highlight"><code class="language-bash">&quot;C:/Program Files/1cv8/8.3.27.1989/bin/1cv8.exe&quot; ENTERPRISE \
  /IBConnectionString &quot;File='F:/...'&quot; \
  /N &quot;Администратор&quot; /P &quot;&quot; /C &quot;RunUnitTests=...&quot;
</code></pre>
<p>Тот же ответ. Та же полторы секунды.</p>
<p>Меняю пользователя в базе на латинского <code>mcp-client</code>, пароль <code>12345</code>. Запускаю.</p>
<p>Зелёный прогон.</p>
<p>Что произошло. Похоже, где-то в цепочке запуска <code>1cv8.exe</code> через PowerShell / vrunner / Python всплывает однобайтная кодировка — и кириллический <code>Администратор</code> теряется при преобразовании. Для 1С такого пользователя в базе просто нет, дальше падение.</p>
<p>Хочется сказать «1С виновата». Но реально — это болезнь почти любого <code>.exe</code> старше десяти лет, который не научили читать аргументы как Unicode. PowerShell тут просто прокладка.</p>
<p>Лечение скучное и работает на 100%: <strong>в пользователе для автопрогонов не должно быть кириллицы</strong>. Создаёшь в базе пользователя <code>mcp-client</code> или <code>ci-user</code>, выдаёшь ему права (для тестов — полные, не жалко), и в шагах прогона ходишь под ним.</p>
<p>Лечение для себя: я держу кириллического «Администратора» как основного для работы руками и латинского <code>mcp-client</code> для автопрогонов. Они не мешают друг другу.</p>
<p><strong>Самое смешное:</strong> за этот вечер я потерял на этой грабле минут сорок. Через две недели после этого, копаясь в старых заметках по статьям, нашёл собственную запись от 6 мая: «Codex решил эту проблему. Описал в инструкциях и в CLAUDE.md. Через латинского пользователя.» Прошлый я знал. Текущий я забыл и пошёл по тем же граблям. И понял, почему есть отдельный шаг во всех моих инструкциях — «<strong>первым делом загляни в свою папку наработок</strong>».</p>
<h2>Грабля 2 — права запуска скриптов под LocalSystem</h2>
<p>Окей, прогон работает. Тесты зелёные. Открыт терминал, в нём крутится <code>act_runner.exe</code>. Если я закрою терминал — исполнитель умрёт, и коммит в Gitea не подхватится.</p>
<p>Надо поднять исполнитель как Windows-службу, чтобы он жил вечно.</p>
<p>Беру WinSW (это маленькая обёртка для запуска чего угодно как службы), регистрирую исполнитель под аккаунтом LocalSystem, стартую. Коммит в репо. Шаг 1 — пять секунд. Падает.</p>
<p>В логах:</p>
<pre class="highlight"><code>PSSecurityException: UnauthorizedAccess
File ...\0.ps1 cannot be loaded because running scripts is disabled
on this system. ExecutionPolicy: Restricted
</code></pre>
<p>Ставлю права запуска на <code>RemoteSigned</code> через групповую политику. Перезапускаю. То же самое.</p>
<p>Ставлю <code>Set-ExecutionPolicy -Scope Process Bypass</code> первой командой в скрипте. То же самое.</p>
<p>Что-то тут странное.</p>
<p>Открываю как Gitea на самом деле запускает шаг PowerShell:</p>
<pre class="highlight"><code>powershell -command . '0.ps1'
</code></pre>
<p>Видите эту <strong>точку</strong> перед <code>'0.ps1'</code>? PowerShell это называет «загрузить в текущую сессию». Это означает: проверка политики запуска происходит <strong>до</strong> того, как тело скрипта начнёт выполняться. То есть мой <code>Set-ExecutionPolicy</code> внутри <code>0.ps1</code> физически не успевает сработать. Скрипт даже не запускается.</p>
<p>Нашёл лечение — <code>shell: cmd</code> плюс явный вызов <code>powershell -ExecutionPolicy Bypass -File</code>:</p>
<pre class="highlight"><code class="language-yaml">- name: Run smoke
  shell: cmd
  run: powershell -ExecutionPolicy Bypass -File run-yaxunit-smoke.ps1
</code></pre>
<p>Это уже не загрузка в текущую сессию — это запуск отдельного PowerShell-процесса с уже выставленной политикой. Работает. Без UAC, без правки реестра, без правки локальной групповой политики на всех компах.</p>
<p>Запускаю. Падаем на следующем шаге:</p>
<pre class="highlight"><code>'oscript' is not recognized as an internal or external command
</code></pre>
<h2>Грабля 3 — PATH потерял пользовательскую часть</h2>
<p>Это уже сцепка к предыдущему. LocalSystem видит <strong>машинную</strong> часть PATH. А <code>oscript.exe</code> я ставил через ovm (это менеджер версий для OneScript). ovm кладёт всё в <code>C:/Users/&lt;user&gt;/AppData/Local/ovm/current/bin</code> — то есть в <strong>пользовательскую</strong> часть PATH.</p>
<p>Запускаю под собой — работает. Запускаю под LocalSystem — <code>oscript</code> не найден.</p>
<p>Решений два. Первое — добавить путь от ovm в машинную часть PATH. Так нельзя, потому что я там ставил конкретно локально, под себя, и не хочу делать это глобальным.</p>
<p>Второе — расширить <code>$env:Path</code> в скрипте-обёртке, явно ткнув в нужную папку:</p>
<pre class="highlight"><code class="language-powershell">$VrunnerExe = &quot;C:/Users/&lt;user&gt;/AppData/Local/ovm/current/bin/oscript.exe&quot;
$env:Path = &quot;$(Split-Path -Parent $VrunnerExe);$env:Path&quot;
</code></pre>
<p>Сразу после этого <code>vrunner</code> находит <code>oscript</code>, <code>oscript</code> находит свой пакет, прогон стартует.</p>
<p>В сумме — три грабли подряд. Кириллица в пользователе, политика запуска под службой и пропавший PATH — на отдельный вечер каждая, если не знать. Все три отлично гуглятся задним числом. Но в моменте, когда видишь «выход 1 за полторы секунды без объяснения», не очевидно, что это, цитирую, <strong>проблема границы Unicode и однобайтной кодировки в системном вызове Windows</strong>.</p>
<p>Зелёный прогон через службу — после этого. Пять часов в сумме на сегодняшний вечер.</p>
<h2>Грабля 4 — DeepSeek убедил меня чинить не ту Synology ACL</h2>
<p>Это моя любимая.</p>
<p>Allure поднялся за две минуты — <code>docker run</code> на NAS, <code>frankescobar/allure-docker-service</code>, проброс папки <code>/volume1/docker/allure/projects</code> внутрь как <code>/app/projects</code>. Стартует, на порту 5050 живая морда.</p>
<p>Делаю первый POST — отправить результаты прогона. Получаю:</p>
<pre class="highlight"><code>HTTP 400
Permission denied: '/app/allure-docker-api/static/projects/yaxunit-iikona'
</code></pre>
<p>Делаю <strong>перезапуск</strong> контейнера. Тот же POST. <strong>Зелёный</strong>. Загрузка прошла.</p>
<p>Хм. Подозрительно — после перезапуска работает, а до — нет.</p>
<p>Запоминаю это в голове и думаю: «Видимо первый раз после старта он что-то досоздаёт».</p>
<p>На следующий день поднимаю <strong>второй проект</strong> на том же Allure. Та же ошибка. Тот же перезапуск. Лечит.</p>
<p>Это уже не «видимо». Это <strong>закономерно</strong>. Каждый новый проект — перезапуск.</p>
<p>В Claude Code прикасаюсь к скиллу про связку нескольких агентов: «поручу DeepSeek через <code>opencode run</code>, пусть посмотрит свежим взглядом и найдёт настоящую причину». DeepSeek (v4-pro через OpenRouter) у меня в скилле для именно таких ситуаций — независимое мнение по конкретной проблеме.</p>
<p>Отправляю описание ошибки и контекст. Через двадцать секунд ответ. <strong>Уверенный</strong>, со ссылками на скрипт запуска этого образа Docker:</p>
<blockquote>
<p>«Скрипт запуска выполняет <code>chown -R 1000:1000 /app/projects</code> асинхронно. Flask-приложение стартует раньше, чем заканчивается смена владельца. Поэтому первый POST приходит до того, как владелец поменялся, и процесс с правами 1000 не может писать. После перезапуска скрипт инициализации уже отработал, права выставлены — POST проходит.</p>
<p>Решение: в <code>docker-compose.yml</code> добавить <code>command: ["sh", "-c", "chown -R 1000:1000 /app/projects &amp;&amp; exec entrypoint.sh"]</code> — синхронная смена владельца перед стартом сервиса.»</p>
</blockquote>
<p>Логично. Стройно. Объясняет всё, что я видел.</p>
<p>Я уже почти было пошёл это применять. Но <strong>что-то</strong> меня остановило. Не знаю что. Какой-то рефлекс «проверь руками сначала».</p>
<p>И я зашёл в контейнер по SSH:</p>
<pre class="highlight"><code class="language-bash">docker exec -it allure ls -ld /app/projects/yaxunit-iikona
</code></pre>
<p>Ответ:</p>
<pre class="highlight"><code>drwxrwxrwx 2 1029 users 4096 May 14 22:30 /app/projects/yaxunit-iikona
</code></pre>
<p>Стоп.</p>
<p><strong>Владелец — 1029. Не 1000.</strong></p>
<p>То есть никакой смены владельца в скрипте запуска <strong>не происходило</strong>. Ни до старта, ни после. Владелец — <code>1029:users</code>, как я его создал через <code>mkdir</code> изначально. Права в стиле Unix — <code>0777</code>, что для процесса с правами 1000 (под которым Flask) <strong>разрешает запись</strong>.</p>
<p>Я был в полу-шаге от того, чтобы записать в инструкцию <code>1c-yaxunit-runner</code> «добавьте смену владельца в скрипт запуска, иначе будет 400 на первом POST» — и оставить этот ложный вывод там навечно.</p>
<p>После пары часов проб — стартовал контейнер, ждал пять секунд, делал POST, замерял. Стартовал, ждал десять секунд, POST, замерял. Менял <code>command:</code>, не менял <code>command:</code>. Через двадцать минут реальная картина была вот такая:</p>
<p><strong>Flask-приложение начинает слушать порт 5050 раньше, чем заканчивается скрипт инициализации внутри образа.</strong> Скрипт инициализации делает кучу всего — миграции базы SQLite, проверки, прогрев. POST, приходящий на сервер, который уже слушает но ещё не готов, получает 400 с криво сложенным сообщением «permission denied на /app/&hellip;», хотя реально с правами ни при чём.</p>
<p>Лечение — банальный <strong>опрос готовности</strong> перед первым POST:</p>
<pre class="highlight"><code class="language-python">for _ in range(30):
    if requests.get(f&quot;{ALLURE_URL}/version&quot;).ok:
        break
    time.sleep(1)
</code></pre>
<p>Тридцать секунд ожидания готовности на старте. После этого POST-запросы летят.</p>
<p>DeepSeek был умен, стройн и неправ. Я его очень люблю как независимого ревьюера, особенно в обычной связке нескольких агентов: каждое ревью кода через DeepSeek поверх Claude находит баги уровня «уборка дубликатов событий цепляется не за идентификатор, а за совпадение сумм за тридцать дней». Но в этот раз он сочинил красивую внутреннюю модель ошибки, которая не имела отношения к реальности.</p>
<blockquote>
<p><strong>Я:</strong> «Так ты выдумал про смену владельца в скрипте запуска?»</p>
<p><strong>DeepSeek:</strong> Молчит. Он не помнит этот разговор. Третий агент в моём рабочем потоке — без памяти между запросами.</p>
</blockquote>
<p>Урок: <strong>на инфраструктурных вопросах сначала проверка руками, потом совет от ИИ</strong>. Пять минут <code>docker exec</code> и <code>ls -l</code> стоят дешевле, чем час неверной правки и потеря веры в собственные диагнозы. Без проверки руками я бы записал в скилл <code>1c-yaxunit-runner</code> навсегда инструкцию «в скрипте запуска синхронная смена владельца» — и каждый, кто бы шёл моими граблями по моему же скиллу, запомнил бы её как факт.</p>
<h2>Грабля 5 — Allure не принимает JUnit XML</h2>
<p>Я думал, JUnit XML — это универсальный билет в Allure. Раз Allure про красивые отчёты тестов, и почти все системы понимают JUnit XML — значит и он понимает.</p>
<p>Оказалось, в этом контейнере билет не тот. <code>frankescobar/allure-docker-service</code> принимает только <strong>свой формат Allure raw JSON</strong> — это один JSON-файл на тест. У него своя структура: <code>name</code>, <code>fullName</code>, <code>status</code>, <code>start</code>, <code>stop</code>, <code>historyId</code>, <code>labels</code>, <code>parameters</code>.</p>
<p>Открыл документацию Allure. Половина — про плагин для Java, половина — про SBT и Gradle. Описание собственного формата — где-то на третьем уровне навигации, под спойлером, на английском, с примером в YAML, который не валиден как JSON.</p>
<p>Окей, написал переводчик сам. На стандартной библиотеке Python, пятьдесят строк:</p>
<pre class="highlight"><code class="language-python">import xml.etree.ElementTree as ET
import json, hashlib, time, uuid

def junit_to_allure(xml_path, out_dir):
    tree = ET.parse(xml_path)
    for tc in tree.iter(&quot;testcase&quot;):
        name = tc.get(&quot;name&quot;)
        suite = tc.get(&quot;classname&quot;)
        failure = tc.find(&quot;failure&quot;)
        status = &quot;failed&quot; if failure is not None else &quot;passed&quot;
        # historyId через md5 — чтобы Allure связал прогоны в график
        history_id = hashlib.md5(f&quot;{suite}.{name}&quot;.encode()).hexdigest()
        result = {
            &quot;uuid&quot;: str(uuid.uuid4()),
            &quot;name&quot;: name,
            &quot;fullName&quot;: f&quot;{suite}.{name}&quot;,
            &quot;status&quot;: status,
            &quot;stage&quot;: &quot;finished&quot;,
            &quot;historyId&quot;: history_id,
            &quot;labels&quot;: [{&quot;name&quot;: &quot;suite&quot;, &quot;value&quot;: suite}],
        }
        if failure is not None:
            result[&quot;statusDetails&quot;] = {&quot;message&quot;: failure.get(&quot;message&quot;), &quot;trace&quot;: failure.text}
        with open(f&quot;{out_dir}/{result['uuid']}-result.json&quot;, &quot;w&quot;) as f:
            json.dump(result, f)
</code></pre>
<p><code>historyId = md5(fullName)</code> — критическая мелочь. Без неё Allure не свяжет прогоны между собой, и не будет графиков трендов. Это написано в их документации, но не очевидно — раздел про историю как раз про этот md5, и легко пропустить, потому что параметр выглядит как «необязательный».</p>
<p>Переводчик работает. Заливка работает. Тренды строятся. Дальше в цепочке от меня нужно только смотреть на красивые графики и иногда отвечать в Telegram-бот «yes, видел, сегодня починю».</p>
<p><img decoding="async" alt="Allure dashboard: 72 теста, 100%, разбивка по 14 suites" src="https://androman.pro/wp-content/uploads/2026/05/screenshot-allure-dashboard.png"></p>
<h2>Грабля 6 — BDD-тесты в автопрогон не лезут</h2>
<p>В ИИконе кроме YAxUnit (модульные тесты) есть сценарии BDD через Vanessa Automation. Это поведенческие тесты, написанные на Gherkin. Они умеют ходить по формам, нажимать кнопки, читать значения — то есть нужен <strong>живой экран с интерфейсом</strong>.</p>
<p>Под YAxUnit мы только что собрали красивую штуку — исполнитель крутится как служба под LocalSystem, прогон без видимого окна, прекрасно. Хочется BDD туда же.</p>
<p>Не работает.</p>
<p>LocalSystem в Windows стартует в <strong>Session 0</strong> — это специальная сессия для системных служб, без интерактивного рабочего стола, без окон, без сообщений интерфейса. Сценарии Vanessa отправляют оконные сообщения формам — в Session 0 этих окон нет.</p>
<p>Vanessa запускает 1С тонкий клиент, тонкий клиент пытается открыть форму, движок интерфейса отправляет оконные сообщения — некому слушать. Тест зависает или падает с непонятной ошибкой через таймаут.</p>
<p>Можно? Технически — <code>psexec -s -i 1 vrunner.exe</code>, переключение в Session 1, тонкий клиент в видимом рабочем столе. Можно службу запускать <strong>не от LocalSystem, а от обычного пользователя</strong> с разрешением «вход как служба». Тогда сессия получает интерфейс.</p>
<p>Должен ли я это делать? Для моего случая — <strong>нет</strong>. Сценарии BDD у меня прогоняются раз в неделю руками через Vanessa MCP в Claude Code. Я в этот момент сижу за компом, смотрю как кликается. Это и нужно, потому что BDD у меня про вёрстку форм — я в этот момент <strong>смотрю</strong> скриншоты.</p>
<p>Решил так:</p>
<table>
<thead>
<tr>
<th></th>
<th>YAxUnit</th>
<th>BDD (Vanessa)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Нужен живой рабочий стол</td>
<td>Нет</td>
<td>Да</td>
</tr>
<tr>
<td>Под Windows-службой</td>
<td>работает</td>
<td>не работает</td>
</tr>
<tr>
<td>Где прогон</td>
<td>Автоматически на коммит</td>
<td>Вручную через MCP</td>
</tr>
<tr>
<td>История прогонов</td>
<td>Allure (проект <code>yaxunit-iikona</code>)</td>
<td>Allure (проект <code>bdd-iikona</code>)</td>
</tr>
</tbody>
</table>
<p>То есть Allure-история покрывает <strong>обе</strong> ветки одним и тем же дашбордом. Просто прогон BDD стартует с моей кнопки, не с коммита. И переводчик JUnit → Allure raw используется одинаково.</p>
<p>Получилась несимметричная, но честная цепочка. Без окон там, где это работает. Руками там, где требуется живой экран. Один Allure, два проекта, общая история.</p>
<h2>Где помог Claude Code, а где помешал</h2>
<p>Здесь не про «ИИ круто помогает разработчику», а про конкретные мелочи.</p>
<p><strong>Где помог.</strong> Связка из трёх агентов — Claude как архитектор плюс Codex CLI как разработчик плюс DeepSeek как независимый ревьюер. Я отдаю Codex детально-сформулированную задачу («написать опрос готовности, добавить повторы, обновить модульные тесты»), он реализует, Claude (то есть я в этой сессии) ревьюит, DeepSeek проверяет третьим взглядом. На длинной дистанции эта тройка ловит баги, которые я бы не нашёл. Дороже подписки на Claude Max — копейки на DeepSeek через OpenRouter, около половины цента за прогон ревью.</p>
<p>Скиллы — память между сессиями. После сегодняшних граблей записи про них уже в памяти. Следующая сессия с фразой «настроить автопрогон тестов 1С» сама подтянет нужный скилл, и я не повторю эти же грабли. Это работает не идеально, но лучше, чем без него — Грабля 1 (кириллица в пользователе) тому подтверждение: скилл был, я его не открыл, прошёл по тем же костям. Скилл стал жёстче.</p>
<p><strong>Где помешал.</strong> Как показала Грабля 4 — советы ИИ на инфраструктурных вопросах требуют проверки руками. Особенно когда модель не видит <strong>твоего</strong> конкретного контейнера и твоих конкретных прав.</p>
<p>И ещё — я регулярно ловил себя на том, что <strong>изобретаю</strong> там, где у меня уже есть готовое. Например я пошёл писать с нуля PowerShell-скрипт для прогона YAxUnit, при том что у меня уже лежат готовые скилл-обёртки <code>db-create</code>, <code>db-load-cf</code>, <code>epf-build</code> для всего этого. Лень открыть <code>ls</code>. Прошлогодний я в инструкциях уже <strong>умнее</strong>, чем текущий я по памяти. Это смешно и грустно одновременно.</p>
<h2>Сколько ушло</h2>
<p>Время: <strong>5 часов</strong> с клавиатуры в сессиях Claude Code. С вечера четверга до утра пятницы, с перерывом на сон. Реально это две полу-сессии — одна на цепочку YAxUnit до Allure (три часа), одна на Allure плюс стек мониторинга плюс Telegram (два часа).</p>
<p>Деньги:</p>
<ul>
<li>Claude Pro Max — подписка, не за задачу. Считать как «фиксированная».</li>
<li>DeepSeek через OpenRouter — около двух центов за всю сессию. Это пять-шесть прогонов ревью по половине цента, цифра реальная (есть в моём трекере, <a href="/ai-tracker-60k/">про который писал отдельный пост</a>).</li>
<li>Прометей, Графана, Allure — контейнеры Docker на NAS, который и так крутится 24/7.</li>
<li>1С — лицензия учебная, файловая база.</li>
</ul>
<p>Железо: домашний NAS, который и так работает 24/7. Под весь стек — около гигабайта оперативки (Allure плюс Prometheus с Grafana и Alertmanager). На нём же живёт Gitea и пара других сервисов. Запас есть.</p>
<h2>Когда стоит это делать</h2>
<p>Это <strong>не для каждого 1С-проекта</strong>. Это для конкретного класса проектов:</p>
<ul>
<li>Тестов больше тридцати, и прогон занимает заметное время (десятки секунд → минуты).</li>
<li>Прогон делается <strong>чаще раза в день</strong>. Если раз в неделю — перебор.</li>
<li>Хочется график «процент успешных по неделям», регрессии замечать «вчера было 72/72, сегодня 70/72 — что я сломал?».</li>
<li>Команда больше одного человека, и тесты надо видеть не только в моей голове.</li>
<li>Или: команда из одного, но есть стратегическая цель — например, сертификация «1С:Совместимо», для которой автоматизация тестов это плюс.</li>
</ul>
<p>Если тестов десять и они прогоняются раз в неделю руками — забудь про это, тебе не надо.</p>
<h2>Когда не стоит</h2>
<ul>
<li>Файловая база, единственный разработчик, два десятка тестов раз в неделю. Достаточно ручного прогона.</li>
<li>Нет NAS / нет виртуалки / нет ноута, который можно отдать под свой исполнитель. На облачных исполнителях 1С запускать нельзя — лицензия привязана к железу.</li>
<li>Команда не понимает «зачем нам автопрогон» и сопротивляется. Сначала разговор, потом инфраструктура.</li>
</ul>
<h2>Шаблон для тех, кто хочет повторить</h2>
<p>Я выложил репозиторий-шаблон. Все шесть грабель задокументированы в README, плюс готовый конфиг прогона, готовый скрипт-обёртка, готовый переводчик JUnit → Allure raw, готовый сборщик метрик Allure для Prometheus.</p>
<p><a href="https://github.com/andromanpro/onec-yaxunit-ci-template"><code>github.com/andromanpro/onec-yaxunit-ci-template</code></a> — MIT, бери и адаптируй. Поднимается у нового проекта минут за тридцать.</p>
<p>Поднимается у нового пользователя минут за тридцать. Главные параметры — путь до <code>1cv8.exe</code>, имя файловой базы, латинский пользователь с правами. Остальное — копипаста.</p>
<h2>Посмотреть</h2>
<ul>
<li><a href="https://github.com/andromanpro/onec-yaxunit-ci-template">Шаблон <code>onec-yaxunit-ci-template</code></a> — MIT, README со списком грабель на 200 строк</li>
<li><a href="https://github.com/andromanpro/1c-ai-connector">ИИкона — AI-коннектор для 1С</a> — открытый проект, из CI-инфраструктуры которого вырос этот шаблон</li>
<li><a href="/ai-tracker-60k/">Пост про трекер расходов на ИИ</a> — там тот же DeepSeek, который ловит реальные баги, упоминается в контексте связки нескольких агентов</li>
<li><a href="https://github.com/andromanpro">github.com/andromanpro</a> — публичная часть моих проектов</li>
</ul>
<h2>Что осталось</h2>
<p>План, до которого я <strong>не дошёл</strong> в этот вечер и который висит на следующий заход:</p>
<ul>
<li>Перенос всего стека на Linux-исполнитель на NAS плюс 1С в Docker плюс Postgres. Это убирает зависимость от моего ноута. Три-пять дней работы, ждёт повода вроде «команда выросла» или «ноут перестал быть надёжным».</li>
<li>Сборщик метрик 1С для Prometheus для кластерной базы (если когда-нибудь появится кластер). Для файловой ИБ — бессмысленно.</li>
<li>Расширение сборщика метрик Allure — помодульные числа, чтобы в Grafana видеть процент успешных <strong>по конкретному модулю</strong> в динамике.</li>
<li>Архив HTML-отчётов Allure в <code>/volume1/backups/</code> (сейчас Allure держит последние 20 отчётов, потом удаляет).</li>
</ul>
<p>Ни один из этих пунктов не блокирует ничего. Если упадёт что-то критичное, я узнаю через Telegram в течение минуты — это самое важное, что я успел собрать.</p>
<h2>Самое смешное</h2>
<p>Самое смешное про этот вечер — это не количество граблей. Их шесть, и каждая ловится через 30 секунд <code>docker exec</code> или <code>Get-ChildItem $env:Path</code>.</p>
<p>Самое смешное в том, что <strong>из шести граблей пять я уже встречал раньше</strong>. Грабля 1 — кириллица в пользователе — была решена 6 мая, в скилле и в CLAUDE.md. Грабля 2 — права запуска под службой — общеизвестная штука среди Windows-сисадминов. Грабля 5 — Allure ждёт свой формат — задокументирована в их официальной документации.</p>
<p>Только <strong>Грабля 4</strong> — DeepSeek и не та Synology ACL — была мне новой. И именно на ней DeepSeek дал красивый, уверенный, неверный диагноз. Единственная по-настоящему свежая грабля среди шести — единственная, на которой совет от ИИ дал сбой.</p>
<p>Это не значит, что ИИ бесполезен. Это значит, что ИИ <strong>очень хорошо имитирует</strong> уверенный ответ, и если ты сам не знаешь правильного ответа, ты не различишь.</p>
<p>Скиллы — внешняя память от прошлого меня к текущему — работают лучше, чем модельная память внутри ИИ. Скилл написан после того, как я <strong>проверил руками</strong>. Модель пишет ответ из обучающего корпуса, не глядя в мой контейнер.</p>
<p>DeepSeek через два дня после этого вечера поймал в ревью два серьёзных бага в коде, которые я бы не нашёл (обход путей в одной из точек входа, гонка проверок в уборке дубликатов). Я ему очень благодарен. Просто <strong>для инфраструктурных диагнозов</strong> — <code>docker exec</code> стоит дешевле и точнее.</p>
<p><img decoding="async" alt="Grafana «Allure CI — тесты и тренды»: pass rate, тренды, длительность по проектам" src="https://androman.pro/wp-content/uploads/2026/05/screenshot-grafana-allure.png"></p>
<p><img decoding="async" alt="Telegram-алерт от бота через Alertmanager" src="https://androman.pro/wp-content/uploads/2026/05/screenshot-telegram-alert.png"></p>
<p>Автопрогон зелёный. Дашборд Allure жив. Telegram-бот молчит, что означает «всё ок».</p>
<p>А я теперь сижу и думаю, сколько ещё вещей вокруг меня я могу автоматизировать за один длинный вечер.</p>


<p style="margin-top:1em;font-family:monospace;font-size:0.9em;">→ <a href="https://androman.pro/2026/05/14/ci-1c-za-den/">открыть на androman.pro</a></p>]]></content:encoded>
					
					<wfw:commentRss>https://androman.pro/2026/05/14/ci-1c-za-den/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Я построил трекер для ИИ. Через час он показал почти пять миллионов рублей</title>
		<link>https://androman.pro/2026/05/09/ai-tracker-60k/</link>
					<comments>https://androman.pro/2026/05/09/ai-tracker-60k/#respond</comments>
		
		<dc:creator><![CDATA[Androman.pro]]></dc:creator>
		<pubDate>Wed, 13 May 2026 06:31:43 +0000</pubDate>
				<category><![CDATA[дев-лог]]></category>
		<category><![CDATA[ИИ-разработка]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Claude]]></category>
		<category><![CDATA[neon-legion]]></category>
		<category><![CDATA[vibe-coding]]></category>
		<category><![CDATA[метрики]]></category>
		<guid isPermaLink="false">https://androman.pro/?p=287</guid>

					<description><![CDATA[Субботний трекер посчитал, что мои два месяца работы с Claude по API-тарифам стоили бы почти пять миллионов рублей. А подписка стоила тридцать две тысячи.]]></description>
										<content:encoded><![CDATA[<p>Суббота. 9 мая 2026 года. Час дня или около того.</p>
<p>Я решил сделать маленький трекер для собственного использования ИИ: сколько токенов, сколько денег, сколько времени я реально экономлю, и не обманываю ли я себя красивым ощущением разгона.</p>
<p>Через час он показал <strong>почти пять миллионов рублей</strong> — точнее, <strong>4 824 000</strong> в эквиваленте API при курсе 80 рублей за доллар.</p>
<p>Я посмотрел на цифру и сказал примерно так:</p>
<blockquote>
<p>«Я столько за год не зарабатываю».</p>
</blockquote>
<p>Потом выдохнул и поправил себя. Нет, я не <strong>потратил</strong> пять миллионов. Это важная разница. Столько стоили бы мои Claude Code сессии за два месяца, если бы я платил за них по API-тарифам. Реально я заплатил за Max-подписку: <strong>16 тысяч в месяц</strong>, то есть <strong>32 тысячи за два месяца</strong>.</p>
<p>Получилось не «я потратил пять миллионов».</p>
<p>Получилось хуже и смешнее.</p>
<p>Получилось: я <strong>не потратил</strong> примерно <strong>4,79 миллиона рублей</strong>, потому что подписка окупилась почти в <strong>150 раз</strong>.</p>
<p>И самое странное — это посчитал трекер, который в этот момент сам ещё строился.</p>
<h2>Сначала надо было признаться, что я не считаю</h2>
<p>У меня давно было ощущение, что ИИ экономит мне время. В апреле я уже считал часы: <strong>147 часов</strong> активного общения с моделью за месяц, десятки сессий, куча артефактов, блог, pet-проекты, клиентские задачи, инфраструктура, вся эта прекрасная каша.</p>
<p>Но часы — штука скользкая. Сегодня кажется, что без модели я бы делал задачу неделю. Завтра кажется, что преувеличил. Послезавтра уже не помнишь, что именно было трудно: код, вход в предметную область, проверка результата или просто нежелание начинать.</p>
<p>Деньги в этом смысле грубее.</p>
<p>Есть подписка. <strong>16 тысяч в месяц</strong>. Есть фактическое потребление моделей. Есть тарифы API. Можно посчитать, сколько стоил бы тот же объём, если бы всё шло не через Max, а через прямую оплату токенов.</p>
<p>Не как бухгалтерскую истину. Как личный датчик масштаба.</p>
<p>Мне нужен был не корпоративный BI, не «панель эффективности цифровой трансформации», прости господи, а простой локальный счётчик: вот сессия, вот модель, вот токены, вот примерная стоимость, вот день, вот сумма.</p>
<p>Ну и, конечно, я не стал делать это один.</p>
<h2>Два агента, один NAS и нормальный взрослый процесс</h2>
<p>Схема у меня уже сложилась: <strong>Claude Code</strong> работает архитектором, <strong>Codex CLI</strong> работает разработчиком, а Gitea на NAS держит всё в виде задач, PR и слияний. Человек посередине иногда делает вид, что руководит процессом.</p>
<p>Роли простые:</p>
<ol>
<li><strong>Claude</strong> формулирует фазу, режет задачу, ревьюит результат.</li>
<li><strong>Codex</strong> лезет в репозиторий, пишет код, чинит тесты, приносит PR.</li>
<li><strong>Gitea</strong> не даёт этой каше превратиться в «я тут что-то правил в папке».</li>
<li><strong>Я</strong> смотрю на цифры и периодически говорю: «алло, это точно не взорвётся?»</li>
</ol>
<p>За один длинный сеанс пролетели несколько фаз.</p>
<p><strong>Phase 1.0</strong> — хук окончания сессии для Claude Code. Когда сессия заканчивается, хук читает данные, находит последнее событие ассистента с расходом токенов, считает примерную стоимость и пишет событие в локальный JSONL.</p>
<p><strong>Phase 1.3</strong> — хук на старте сессии и оценка сложности через <code>claude -p --bare</code>. Идея: на старте новой сессии найти предыдущие сессии без оценки и в фоне попросить Claude прикинуть, сколько часов такая задача заняла бы без ИИ.</p>
<p><strong>Phase 1.0.1</strong> — обратная загрузка истории из <code>~/.claude/projects/*/*.jsonl</code>. Это и стало большим взрывом цифр: не только новые события, а весь хвост за два месяца.</p>
<p><strong>Phase 1.0.2</strong> — срочная правка, потому что внезапно выяснилось, что у нас есть не только данные, но и способы ими случайно замучить собственную подписку: ограничитель частоты, пропуск синтетических сессий, уточнение цен, правильный разворот формулы экономии.</p>
<p>Каждая фаза шла через задачу → реализацию Codex&rsquo;ом → ревью Claude → PR → слияние. К вечеру в локальной Gitea уже лежали PR #3, #5, #7, плюс добивки вокруг 1.0.2.</p>
<p>Звучит почти прилично.</p>
<p>На практике приличие началось не сразу.</p>
<p>Сначала я создал Gitea-репозиторий с <code>auto_init: True</code>, получил unrelated histories и потом восстанавливал нормальную историю через cherry-pick из reflog&rsquo;а. Да, взрослый процесс. Да, с ударом лбом о дверной косяк на входе.</p>
<p>Потом первая попытка Codex&rsquo;а упала на строгой схеме OpenAI: у каждого объекта в схеме должен быть <code>additionalProperties: false</code>. Не «желательно». Не «потом добавим». HTTP 400 и иди думай.</p>
<p>А ещё в <code>working_dir</code> всплыли кракозябры из-за cp1251→utf8. Не смертельно, но привет из мира Windows, где кириллица всегда ждёт в тёмном углу и улыбается.</p>
<h2>Трекер смотрит на того, кто его строит</h2>
<p>Самый красивый момент случился почти незаметно.</p>
<p>Я тестировал хук окончания сессии. Claude завершал сессию. Хук писал событие в <code>tracker/claude-events.jsonl</code>. Потом мы правили хук. Потом снова завершали сессию. Потом снова писалось событие.</p>
<p>И в какой-то момент я понял: <strong>трекер уже трекает собственную постройку</strong>.</p>
<p>То есть я смотрю на файл, в котором лежит история создания файла, который записывает историю создания файла.</p>
<p>Нормальная такая рекурсия выходного дня.</p>
<blockquote>
<p><strong>Я:</strong> «Подожди, он сейчас считает эту же сессию?»</p>
<p><strong>Claude:</strong> «Да. Хук окончания сессии глобальный».</p>
<p><strong>Я:</strong> «То есть он видит не только этот проект?»</p>
<p><strong>Claude:</strong> «Он видит все Claude Code сессии».</p>
</blockquote>
<p>И вот тут маленький локальный счётчик превратился в <strong>observatorium</strong>.</p>
<p>Хук был зарегистрирован глобально в <code>~/.claude/settings.json</code>. Значит он ловил не только multi-agent, но и параллельные сессии в WMSTnext, и субагентов, и всё, что проходило через Claude Code на этой машине. Не потому что мы так хитро задумали. Просто хук глобальный.</p>
<p>С одной стороны — прекрасно. Полная картина использования.</p>
<p>С другой — приватность и нагрузка сразу перестают быть «потом подумаем». Если Phase 4 когда-нибудь покажет публичные метрики на сайте, сырые транскрипты туда не поедут никогда. Только агрегаты, короткие хэши, обезличенные пути, без содержимого запросов. Иначе это не дашборд, а добровольная публикация собственного чердака.</p>
<p>Второй сюрприз был злее.</p>
<p>Хук на старте сессии для оценки сложности должен запускать <code>claude -p --bare</code>. Флаг <code>--bare</code> тут не декоративный. Он нужен, чтобы оценочная сессия не тащила за собой обычное окружение и не запускала собственные хуки в петлю.</p>
<p>Потому что если каждая оценка запускает новую сессию, а каждая новая сессия запускает оценку, то это уже не автоматизация. Это маленький финансовый чёрный квадрат.</p>
<p>После обратной загрузки у нас оказалось <strong>247 файлов транскриптов</strong>. Если на следующем старте сессии хук бодро запустит 247 дочерних процессов оценки сложности — будет не продуктивность, а ад из лимитов запросов. И это поймали до того, как я открыл следующую нормальную сессию.</p>
<p>Вот зачем нужен второй агент на ревью.</p>
<p>Codex хорошо прошёлся по ширине: нашёл места, где может бахнуть, проверил схемы, краевые случаи, обратную загрузку, дедупликацию. Claude лучше собрал смысл: что это значит для архитектуры, где граница приватности, почему <code>--bare</code> не мелочь, почему формула экономии сначала была перевёрнута не туда.</p>
<p>Эмпирическое правило дня: <strong>Codex лучше ищет по ширине, Claude лучше собирает смысл</strong>.</p>
<p>Не абсолютный закон природы. Просто в этот день так работало.</p>
<h2>Что я нашёл в шестидесяти тысячах</h2>
<p>После обратной загрузки история выглядела так:</p>
<ul>
<li><strong>79,716 событий</strong> за период с <strong>2026-03-09</strong> по <strong>2026-05-09</strong>.</li>
<li><strong>247 файлов транскриптов</strong>.</li>
<li>JSONL после обратной загрузки — около <strong>30 MB</strong>.</li>
<li>Пиковый день — <strong>31 марта</strong>, <strong>1,113 calls</strong>.</li>
<li>По моделям: <strong>Opus 4.7 — 53,854 calls</strong>, <strong>Opus 4.6 — 9,418</strong>, <strong>Sonnet 4.6 — 16,275</strong>.</li>
</ul>
<p>Итоговая сумма по API-тарифам: <strong>4 824 000 рублей</strong>.</p>
<p>Сразу оговорка, жирная и скучная: это пока <strong>завышение на 10-15%</strong>. Старые записи с Opus 4.6 считаются по ценам 4.7, потому что история моделей не идеальна. После пересчёта цен будет точнее. Реалистичнее ожидать <strong>4-4,4 миллиона</strong>, а не ровно 4,82.</p>
<p>Но даже если это не пять миллионов, а четыре — порядок не меняется.</p>
<p>Я заплатил <strong>32 тысячи</strong> за два месяца Max-подписки.</p>
<p>Если бы платил по API-тарифам — было бы около <strong>4,8 миллиона</strong> в текущей грубой оценке.</p>
<p>Экономия относительно API-варианта — <strong>4,79 миллиона</strong> по первому расчёту. Даже после уточнения цен останутся миллионы.</p>
<p>И вот тут мозг делает смешную вещь. Он одновременно понимает, что это не настоящие «заработанные деньги», потому что я бы просто не стал так использовать API за прямые деньги, и одновременно не может игнорировать факт: объём вычислений, который я реально прогнал за два месяца, стоит на открытом тарифе как хорошая машина.</p>
<p>Это не бизнес-кейс для презентации.</p>
<p>Это личная фотография масштаба.</p>
<blockquote>
<p><strong>Я:</strong> «То есть Max за 16 тысяч в месяц — это не дорого?»</p>
<p><strong>Трекер:</strong> «Смотря с чем сравнивать».</p>
<p><strong>Я:</strong> «С API».</p>
<p><strong>Трекер:</strong> «Тогда это почти неприлично дёшево».</p>
</blockquote>
<p>Я раньше писал про разгон как про ощущение: больше задач, больше артефактов, больше связей между проектами. Теперь к этому ощущению прирос счётчик.</p>
<p>Не идеальный. Не финальный. Но уже достаточно честный, чтобы стало слегка не по себе.</p>
<h2>Что я унёс с собой</h2>
<p>Глобальный хук — это власть. Он видит всё, и значит дизайн надо начинать не с красивого дашборда, а с границы приватности. Что пишем, куда пишем, что никогда не публикуем, как обезличиваем путь — это первое решение, не последнее.</p>
<p>Автоматизация должна иметь тормоза. Обратная загрузка на 247 сессий плюс дочерний процесс на старте сессии — почти готовый способ самому себе устроить ад из лимитов запросов. Ограничитель частоты — не украшение, а предохранитель.</p>
<p>И самое неудобное: про деньги надо говорить аккуратно. Я не потратил $60k. Я использовал подписку так, что эквивалентный счёт по API был бы около $60k. Разница принципиальная. Иначе это превращается в инфоцыганскую картинку, от которой самому стыдно.</p>
<h2>А теперь хочется ещё хуже</h2>
<p>Текущий трекер считает деньги. Следующий слой — время.</p>
<p>Phase 1.3 должен научиться оценивать сложность задачи: сколько часов это заняло бы без ИИ, сколько заняло по реальным часам, какой получился множитель. Не «истина в последней инстанции», а личная шкала. Если задача без ИИ была бы на 8 часов, а с агентами заняла 50 минут — это уже не просто красивое ощущение.</p>
<p>Потом хочется отслеживать настроение.</p>
<p>Не только «сколько токенов», но и <strong>сколько раз я матерился</strong>. Счётчик раздражения. Благодарности. Моменты, где я пишу «ёбать» не потому что всё сломалось, а потому что трекер показал $60k.</p>
<p>Потом дашборд. Конечно, киберпанк. Графики, крупные числа, локальный HUD, виджет «сколько осталось до лимита», карточки для блога, которые можно публиковать без сырых данных. Тот самый случай, когда эстетика не мешает инженерии, потому что счётчик должен быть видимым. Если он спрятан в JSONL, мозг его быстро перестаёт чувствовать.</p>
<p>Дальше публичная статистика на androman.pro. Только агрегаты. Никаких транскриптов. Никаких приватных путей. Никаких клиентских имён. Просто «за месяц модель сэкономила N часов / N долларов эквивалента / N дней жизни, которые я всё равно потратил на новые задачи».</p>
<p>А где-то в дальнем углу планов лежит AR-оверлей через Xreal: маленький HUD в углу зрения, агент в сети, PR готов, расходы за сегодня, голосовая команда «merge PR».</p>
<p>Звучит как фантастика.</p>
<p>Но сегодня утром у меня не было трекера. К вечеру он уже нашёл пятьдесят с лишним тысяч долларов не-потраченных денег.</p>
<p>Так что я теперь осторожнее со словом «фантастика».</p>
<h2>Самое смешное</h2>
<p>Самое смешное не в сумме.</p>
<p>Сумма — это просто неоновая вывеска, на которую удобно смотреть с открытым ртом.</p>
<p>Самое смешное в том, что я строил инструмент для измерения собственного ИИ-разгона, а он сразу стал частью этого разгона. Он писал JSONL о сессиях, в которых его писали. Он ловил параллельные ветки. Он обнаружил угрозу собственных оценочных дочерних процессов. Он заставил переписать формулу экономии, потому что первая версия думала не туда.</p>
<p>Счётчик оказался не прибором снаружи системы.</p>
<p>Он оказался ещё одним участником системы.</p>
<p>Подписка окупилась примерно в <strong>150 раз</strong>. Трекер это посчитал сам. А я теперь сижу и думаю, сколько ещё вещей вокруг меня уже пора начать считать.</p>
<p>Потому что ощущение — врёт красиво.</p>
<p>JSONL врёт скучнее.</p>
<hr>
<h2>Через три дня</h2>
<p>Я открыл черновик утром, хотел внести «пару правок перед публикацией».</p>
<p>Через четыре часа переписываю заново.</p>
<h3>Откуда вообще трекер</h3>
<p>Если совсем честно — трекер был <strong>побочным продуктом</strong>.</p>
<p>Изначальная задача звучала по-другому: настроить совместную работу трёх ИИ-агентов. <strong>Claude</strong> разбивает задачу на куски и проверяет результат — архитектор. <strong>Codex</strong> реализует — разработчик. <strong>OpenClaw</strong> — мост через Telegram, чтобы давать команды с телефона из бара. Три модели, три API, три разных протокола. Хотелось чтобы они передавали друг другу задачи и не ругались по поводу того кто из них что испортил.</p>
<p>Чтобы этот конвейер не превратился в чёрный ящик, нужно было видеть кто из агентов что сделал, за сколько токенов и времени. То есть нужен был учёт. А значит — трекер.</p>
<p>Учёт оказался первой готовой частью и пожрал внимание. Заголовок про пять миллионов — оттуда. А мульти-агент тем временем тихо собирался в фоне.</p>
<p>К 12 мая он работает. Я пишу боту в Telegram «обнови README в репо», OpenClaw принимает, Claude составляет план, Codex реализует, DeepSeek (третий ревьюер, появился за эти три дня) проверяет. Я только апрувлю. Это уже не «один человек с одним трекером». Это маленький конвейер из трёх ИИ и одного меня.</p>
<p><img decoding="async" alt="Конвейер neon-legion: Telegram → OpenClaw → Claude → Codex → DeepSeek → approve, события каждого шага оседают в трекер" src="https://androman.pro/wp-content/uploads/2026/05/neon-legion-flow.png"></p>
<p>В репозитории за три дня прирос не только трекер. Прирос мульти-агент, ради которого его и затевали. И заодно — имя <a href="https://github.com/andromanpro/neon-legion"><code>neon-legion</code></a> (вместо служебного <code>multi-agent</code>) и слоган, в котором счётчик ругательств вынесен прямо в название: <em>«Твоя личная армия. Почти без ебать-колотить. Да, мы считаем маты»</em>. Маты считаются не для красоты. У каждой Claude-сессии в дашборде есть поле <code>profanity_count</code>, заполненное по факту. Шутка — это фича.</p>
<h3>Где деньги, Лебовски</h3>
<p>Тут хочется разобраться с одной неудобной вещью.</p>
<p>На 9 мая трекер показывал 4,8 миллиона. Сейчас, пока пишу эту главу, уже <strong>5,77 миллиона</strong> — за три дня плотной работы с моделями цифра прибавила ещё <strong>почти миллион</strong>. Трекер тикает прямо сейчас. На статье тоже.</p>
<p>Подписка нарастающим итогом — <strong>48 тысяч</strong> за два с половиной месяца. Экономия относительно API-варианта — <strong>5,72 миллиона</strong>.</p>
<p>Хочется носить эту цифру на бейдже.</p>
<p>Только в кошельке у меня не прибавилось пяти миллионов. Где же деньги, Лебовски?</p>
<p>Их нет, потому что я бы не потратил эти пять миллионов. Если бы подписки не было, я бы не оплатил все эти запросы по API. Я бы просто <strong>сделал в десять раз меньше</strong>. Экономия — это сравнение с ситуацией, в которой я бы вообще так не работал. Бенчмарк, а не выручка. Цифра на бейдже была бы враньём.</p>
<p>Но интересно другое.</p>
<p>ИИ даёт мне условные <strong>10x</strong> к производительности. Не маркетинговая цифра — субъективная оценка, подтверждённая таблицей часов: без ИИ я делал бы в десять раз меньше за те же часы. Допустим, мой месячный оборот по задачам — <strong>2,5 миллиона</strong>. Тогда один «ИИ-работник» делает работы примерно на <strong>250 тысяч в месяц</strong>.</p>
<p>250 тысяч — это зарплата нормального мидла в РФ. Не сеньора, не лида. Но мидла-с-опытом точно.</p>
<p>Подписка стоит <strong>16 тысяч в месяц</strong> на двоих, Claude Max + ChatGPT Pro. На неё работает <strong>четыре</strong> таких ИИ-мидла одновременно: Claude думает, Codex пишет, DeepSeek ревьюит, OpenClaw таскает между ними сообщения.</p>
<p>Вот где деньги: на каждой ИИ-подписке я не получаю +250 в карман. Я <strong>не плачу</strong> 250 тысяч зарплаты человеку, которого иначе пришлось бы взять. Дельта — невидимая экономия. Её нельзя положить на стол. Но именно она позволяет мне делать в десять раз больше за те же часы.</p>
<p>В кошельке прибавилось не пяти миллионов. Прибавилось <strong>возможности</strong>.</p>
<p>Возможность — паршивая единица отчётности. На неё хорошо ложится подписка и плохо ложится ипотека.</p>
<h3>Что в итоге</h3>
<blockquote>
<p><strong>Я:</strong> «Так ты считаешь свою собственную статью прямо сейчас?»</p>
<p><strong>Трекер:</strong> «Конечно. Я глобальный».</p>
</blockquote>
<p>Реальный сегодняшний счёт после догона: <strong>67 тысяч рублей</strong> в эквиваленте API за один день.</p>
<p>За три дня в репозиторий приехало много мелочи: тесты, сканер приватности перед публикацией, демо за минуту, починка кракозябр, конфиг в одном файле, плюс одна красивая штука — Hindsight Replay, когда вторая модель пишет критику работы первой. Подробности — в коммитах между 9 и 12 мая.</p>
<p>Главная функция трекера — не показать сколько ты сэкономил.</p>
<p>Главная функция трекера — показать насколько ты эффективен и сколько примерно стоит твой труд, <strong>если его будут делать ИИ</strong>.</p>
<p>Пока они дороже тебя — будь спокоен.</p>
<p>Если они начнут выполнять ту же работу что и ты, без ошибок и дешевле — ты станешь не нужен.</p>
<p>Трекер посчитает и это.</p>
<hr>
<p><strong>Посмотреть:</strong></p>
<ul>
<li><a href="/neon-legion/">Живой дашборд</a> — что трекер показывает прямо сейчас: множитель, сэкономлено, активные часы, разбивка по моделям</li>
<li><a href="https://github.com/andromanpro/neon-legion">github.com/andromanpro/neon-legion</a> — open-source, MIT, stdlib-only Python, локальный pipeline без внешних обращений</li>
</ul>


<p style="margin-top:1em;font-family:monospace;font-size:0.9em;">→ <a href="https://androman.pro/2026/05/09/ai-tracker-60k/">открыть на androman.pro</a></p>]]></content:encoded>
					
					<wfw:commentRss>https://androman.pro/2026/05/09/ai-tracker-60k/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Я это сделал!</title>
		<link>https://androman.pro/2026/04/27/ya-eto-sdelal/</link>
					<comments>https://androman.pro/2026/04/27/ya-eto-sdelal/#respond</comments>
		
		<dc:creator><![CDATA[]]></dc:creator>
		<pubDate>Mon, 27 Apr 2026 06:17:15 +0000</pubDate>
				<category><![CDATA[дев-лог]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[creative-code]]></category>
		<category><![CDATA[vibe-coding]]></category>
		<category><![CDATA[WordPress]]></category>
		<guid isPermaLink="false">https://androman.pro/?p=249</guid>

					<description><![CDATA[Дев-лог о перезапуске сайта на собственной WordPress-теме. 15 итераций дизайна, парадокс растущего бэклога, открытия про безопасность CMS.]]></description>
										<content:encoded><![CDATA[<p>Кайфую от веб-разработки — точнее, от вайб-кодинга в ней. Это прямо наслаждение, когда от задумки до результата проходит минимальное количество времени.</p>
<h2>1С vs веб через ИИ — два разных мира</h2>
<p>В 1С не так. Там огромный контекст, галлюцинации модели и загрязнённый контекст: контекст одного проекта просачивается в выводы по другому, имена путаются, факты выдумываются. Платформа сопротивляется.</p>
<p>В вебе — свобода. Сформулировал хотелку, пусть даже криво, и через минуту уже есть что потрогать. Не нужно неделю входить во фреймворк, читать документацию к новому инструменту и вспоминать, почему CSS опять делает вид что всё нормально. ИИ быстро накидывает варианты, а я уже выбираю, что похоже на меня.</p>
<h2>Цифры одного дизайна</h2>
<p>На эту тему ушло 5 итераций по 3 варианта в каждой. Итого <strong>15 разных тем</strong>, каждая собиралась на основе того, что понравилось в предыдущих. В итоге получилась не «идеальная тема», а тема, которую я наконец не хочу немедленно снести.</p>
<p>Главное что вышло:</p>
<ul>
<li><strong>Декодер-заголовок</strong> — <code>androman.pro</code> на главной печатается через шумовые символы <code>█▓▒░</code>, потом «защёлкивается» в текст и морфит между <code>androman.pro → .1С → .ai → .dev</code>. Glitch — короткий RGB-бурст 2.5 секунды.</li>
<li><strong>HUD-углы</strong> — <code>agent ONLINE</code>, <code>build v0.6.x</code>, <code>mode roaming</code>, <code>focus hyperfocus</code>. Левый верхний кликается — открывается changelog проекта (RU/EN, версии с alpha до текущей).</li>
<li><strong>Страница <code>/сейчас</code></strong> — кроме обычного описания фокуса, terminal-блок со 150 случайными dev-фразами в киберпанк-стиле. Клик — мгновенный реролл.</li>
<li><strong>Команд-палитра</strong> — нажми <code>/</code> (на любой раскладке клавиатуры — работает на ЙЦУКЕН тоже), всплывает терминал команд.</li>
<li><strong>Визуальная лаборатория</strong> — 7 моих open-source WebGL/Canvas-проектов собраны в одной странице. У одной из карточек — hover-preview живой 3D-сцены через lazy-load.</li>
</ul>
<p>Шрифты — все 74 woff2 self-hosted. Никаких Google Fonts CDN, сайт работает без внешних соединений.</p>
<h2>Парадокс роста</h2>
<p>Заметил парадокс: <strong>чем больше разрабатываешь с ИИ, тем сильнее растёт бэклог задач</strong>. Раньше идея «было бы круто» оставалась идеей. Сейчас — становится таском в течение часа. Скорость реализации опережает способность приоритизировать.</p>
<p>И ещё — перфекционизм. Если уходишь в него, тратишь неимоверно больше времени, чем если довольствуешься средним вариантом. Но это везде так, <strong>принцип Парето</strong> — 80% результата за 20% времени, остальные 20% — за всю оставшуюся жизнь.</p>
<h2>Workflow получился взрослый</h2>
<p>Заодно собрался нормальный workflow разработки сайта: <strong>тестовый и прод-контуры</strong>, возможность обкатать фичи до выхода в прод. Всё через git, версионирование, автодеплой по rsync через SSH. Бэкап БД и файлов — до любого изменения.</p>
<p>В общем — я доволен. Так и должен выглядеть собственный сайт. Хотя в наше время это уже похоже на ретроградство — социальные сети поглотили личные блоги. Но мне так нравится.</p>
<h2>Открытие про безопасность</h2>
<p>ИИ заодно проаудировал сайт и подсветил то, чего я не знал: <strong>пароли от БД у CMS традиционно хранятся в открытом виде</strong> в конфиге. Это касается всех — WordPress, Joomla, Drupal, Magento, любого PHP-стека. Защита идёт не криптографией, а правами файла + правильной настройкой веб-сервера.</p>
<p>Закрыли всё что обычно светится: XMLRPC отключён, REST <code>/users</code> скрыт от анонимов (admin slug больше не виден), <code>?author=N</code> редиректит на главную, <code>readme.html</code> и <code>license.txt</code> удалены, security-headers через PHP + <code>.htaccess</code>.</p>
<h2>Что дальше</h2>
<p>Сайт работает. Версия <code>0.6.x</code> — pre-release, до публикации <code>1.0</code> хочу наполнить блог постами и быть уверенным в каждой странице.</p>
<p>Ближайшие планы — <strong>перенесу статьи с инфостарта</strong>, плюс буду публиковать <strong>эксклюзивы</strong> здесь. Радар на сайте уже ждёт blip’ов.</p>


<p style="margin-top:1em;font-family:monospace;font-size:0.9em;">→ <a href="https://androman.pro/2026/04/27/ya-eto-sdelal/">открыть на androman.pro</a></p>]]></content:encoded>
					
					<wfw:commentRss>https://androman.pro/2026/04/27/ya-eto-sdelal/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
