Шестьдесят постов, которые написал не я
Вчера снял пароль с сайта, сегодня отправляю карту в Google. Чем я отвечаю за текст, который написал не я, и что сломалось в первый час после открытия.

Автор: Georg Malahov
Вчера в 23:28 по местному я убрал пароль с сайта. До этого он полгода стоял за формой с одним полем: без пароля любой заход упирался в заглушку. Сегодня утром подтверждаю домен в Search Console и отправляю карту сайта — семьдесят семь адресов, четыре продукта, шестьдесят один пост на трёх языках.
Отправлена и прочитана в один день: 77 адресов, статус Success. Это ещё не индекс — это только заявка
Что открылось
Хаб я начал собирать в апреле, когда разобрал полтора года голосовых заметок и насчитал шестнадцать проектов. Сейчас на домене четыре продукта, блог и хроника на главной. Заметок в базе шестьсот двадцать четыре, первая от 11 декабря 2024 года.
Блог — это шестьдесят один пост, каждый в трёх языках, сто восемьдесят три файла. Все датированы честно: пост про январский коворкинг стоит январём, а не тем днём, когда я его собрал. Лента читается как хроника, потому что хроникой и является, только опубликована она задним числом, разом.
Три языка не для красоты. Русский — родной, на нём я думаю и наговариваю; немецкий — страна, в которой я живу и работаю; английский — язык, на котором ищут мои продукты. Первичен русский, остальные два делаются не машинным переводом, а переписыванием: у каждого свой набор оборотов, которых в оригинале не было, и свой список того, чего в нём быть не должно.
Перед снятием пароля сайт проверялся не только глазами. Восемнадцать страниц в трёх языках — все отдают двести. Карта сайта с языковыми альтернативами. Разметка для поисковика на главной и на каждом продукте. Лента в RSS. Письма уходят и доходят. Ежедневная задача по расписанию на сервере. Счётчик посещений на каждой странице. Список длинный и скучный, и именно поэтому его стоило пройти до того, как страницы стали видимыми.
Чего я не делаю
Тексты в этом блоге пишу не я.
Я наговариваю голосовую заметку — в машине, на прогулке, вечером на балконе. Заметка расшифровывается и разбирается в базу: проекты, люди, решения, вехи. Из базы собирается черновик. Я его читаю, правлю и утверждаю.
Это стоило проговорить вслух, потому что иначе получается тихий обман. Читатель видит первое лицо, дату и подробности — и справедливо считает, что за каждой фразой сидел человек. Человек сидел, но не за той работой, о которой обычно думают.
Чем я тогда отвечаю за текст, который написал не я.
Единственным способом, который у меня нашёлся: править всё, что вызывает сомнение. Любое место, где я спотыкаюсь глазом, где фраза звучит не так, как я бы сказал, где факт выглядит подозрительно, — исправляется. Не «в целом сойдёт», а буквально всё. Если довести это до абсолюта, получается текст, который я помню почти наизусть, — ровно то, что случилось бы, пиши я его сам. Разница заключается в способе создания этих текстов, а не в ответственности за них.
Как это выглядит в работе
Вычитка устроена так, что её можно делать с телефона.
Я открываю свой пост на сайте, выделяю кусок текста и нажимаю кнопку. Дальше наговариваю замечание голосом: что не так, чем заменить, почему. Замечания накапливаются, потом уходят одной пачкой в issue на GitHub. Оттуда их забирает агент: применяет правку во всех трёх языках сразу и — это важнее — записывает из неё правило.
Ощущение при этом почти разговорное. Я читаю как редактор и проговариваю замечания вслух, будто рядом сидит тот, кто это писал, и мы вместе идём по тексту. Потом правки применяются, я перечитываю — и с каждой итерацией спотыкаюсь реже.
Свод правил
Правила накапливаются в отдельном документе. Сейчас в нём семьдесят два раздела и три с лишним тысячи строк. Это не стилевое руководство, а протокол: что я сказал, почему, и во что это превратилось.
Например: имя сотрудника или клиента в тексте не появляется. Собственное слово из голосовой заметки разрешает мысль, но не разговорный оборот — говорю и пишу я по-разному. Заголовок не может быть драматичнее собственного содержания. О конкретных пользователях не пишется ничего: остаётся только то, что я понял, без следа, по которому человека можно узнать.
Механическая половина свода уехала в проверку, которая гоняется при каждом изменении: двадцать девять правил, отозванные слова, запрет на третье лицо о себе, требование назвать месяц в хронологическом посте. Что можно поймать регулярным выражением — ловится машиной, остальное остаётся на глаз.
Что ломалось
Четыре случая стоит назвать, потому что все они о том, как именно врёт сгенерированный текст.
Свод начал сам себе противоречить. Одно правило говорило: если слово есть в голосовой заметке — это авторский голос, оставляем. Другое: разговорные обороты убираем. Оба выполнить нельзя, а заметка полна разговорных оборотов. Разрешилось разделением: заметка разрешает содержание — что эту мысль и этот образ вообще можно писать, — но не регистр. Формулировку выбирает письменный язык.
Одно правило проверки молчало месяцами. Оно искало границу слова, а границу слова в JavaScript понимает только по латинице — на русском тексте не срабатывало ни разу. Нашлось, когда я удивился, почему запрещённое слово спокойно доехало до публикации. Таких копий бага оказалось три.
Три инструкции по продукту были фактически неверными. Их собрали по памяти, а не по коду, и в главном они расходились с продуктом. Три черновика удалены, инструкции переписываются заново по исходникам.
Заголовок разошёлся с собственным текстом. В девятимесячном итоге по Call Copilot в содержании стояло точно: платящих за девять месяцев около десятка, живых подписок к концу августа осталась одна. А в заголовке — «один платящий». Вчерашний пост подхватил заголовок, а не содержание, и построил на нём поворот, которого не было. Итог переименован, пост поправлен.
Первая ночь
Гейт я снял в 21:28 UTC. Дальше ночь пошла не по плану.
Три файла указывали на несуществующий хост. robots.txt, sitemap.xml и llms.txt отдавали адреса вида http://build.invalid — заглушку, с которой собирается образ. Эти три маршрута рендерились на сборке, а не на запрос, и запомнили её навсегда. Отправить такую карту в Google было нельзя: триста восемь адресов вели на хост, которого нет. Сами страницы при этом были в порядке — они собираются на запрос.
Главная не называла человека. В заголовке и описании стояли дефолты шаблона, с которого начинался проект, — одинаковые в трёх языках, про инструменты для разработчиков. Полгода я писал тексты от первого лица, а витрина представляла безымянный шаблон.
К утру обход всех страниц из карты сайта в трёх языках дал ноль битых ссылок на триста восемнадцать внутренних переходов. Замечания остались только по длине: описания части постов длиннее ста шестидесяти знаков, и поиск обрежет им хвост.
Что закрыто за утро
Хвосты, которые ночью я оставил до свежей головы, к утру закрыты: заголовки продуктовых страниц теперь говорят, что продукт делает, а не только как называется; юридические тексты под немецким и русским адресами перестали носить английский заголовок; адреса с префиксом /en уводят на беспрефиксные; у прода появилась проверка готовности, так что деплой больше не роняет страницы на несколько секунд.
Что я буду считать результатом
Внешнего трафика у меня нет — это я выяснил ещё в августе, и ради этого хаб и затевался. Значит, проверка простая: кто-то придёт на пост из поиска. Не по моей ссылке, не из моего письма, а сам.
Честная оговорка: первые переходы, скорее всего, придут не из поиска. На этой неделе я писал письма остывшим пользователям Call Copilot и собираюсь дальше отправлять им ссылки на посты. Это тоже переходы, но это я сам их привёл. Считать буду отдельно: свои и поисковые. Первый поисковый — та цифра, ради которой всё.
Счёт ещё не начался: вместо цифр Google предлагает зайти через день-другой
Пока измерять нечего: на месте цифр Google пишет, что данные обрабатываются и зайти стоит через день-другой. Индексация займёт недели, так что следующая заметка на эту тему появится нескоро.
Посмотрим.