Код от нейронки плоский — как и её тексты. Только в тексте это видят все, а в коде никто
Три функции из легендарного опенсорса против наивных версий от GPT: побег из папки в secure_filename, утечка вместо LRU и timing-атака в constant_time_compare. Почему зелёные тесты печатают доверие без обеспечения.В прошлой статье я показывал, как биржу залило вайб-кодерами и как просели цены на базовые проекты. В комментах тогда был один вопрос, который мало кто задал прямо, но он висел в воздухе: ну ок, цены упали, а код-то у них рабочий? Вот про это сегодня.
Сразу дисклеймер: я каждый день работаю через Claude Code, я не хейтер нейронок, я на них построил весь свой процесс. И я внутри этого рынка, объективности не обещаю. Но я честно постарался вытащить не эмоции, а механику — и тут будут не «имхо», а реальные функции из легендарных проектов со ссылками, чтобы вы могли всё проверить сами.
Идея простая. Вайб-кодер в чистой форме — человек, который вообще не имеет отношения к разработке, — физически не способен оценить код. Для него работает = работает. А я утверждаю: код, сгенерированный нейронкой, всё равно будет более плоским, более ущербным и менее оптимальным, чем код живого разработчика. Проблема в том, как это доказать человеку, который код читать не умеет. Поэтому зайдём через аналогию, которую может проверить КАЖДЫЙ — через тексты.
Тексты от нейронки узнают уже все
Тут, я думаю, спорить никто не будет. Мы все научились чуять текст от нейросети. Эти бесконечные триколоны, «это не просто X — это Y», тяжёлые вводные конструкции, всё такое правильное, выверенное прямо по учебнику. Идеально. И мёртво.
Возьмём простой пример — продающее описание наушников.
Нейронка:
Откройте для себя мир кристально чистого звука с нашими беспроводными наушниками нового поколения. Это не просто наушники — это ваш персональный портал в безграничную вселенную музыки. Благодаря передовой технологии активного шумоподавления и эргономичному дизайну вы погрузитесь в любимые треки как никогда раньше. Идеальный выбор для тех, кто ценит качество, комфорт и стиль.
Человек:
Наушники — это уникальный продукт, который сочетает в себе стиль и качество звука. Эти беспроводные наушники с True Wireless технологией обеспечивают удобство использования и свободу движений. Наушники Marshall Minor IV имеют закрытую конструкцию, которая обеспечивает высокое качество звука и комфорт при использовании. Они также оснащены динамиками, которые позволяют наслаждаться музыкой в полной мере. Эти наушники являются отличным выбором для тех, кто любит качественную музыку и хочет наслаждаться ей в любом месте.
Чувствуете разницу? Текст от нейронки грамматически безупречен и при этом пустой — он подходит под ЛЮБЫЕ наушники, не утверждает ничего проверяемого, никого конкретного не представляет. А человек называет конкретную модель и конкретную технологию, то есть делает проверяемое заявление, и — внимание — допускает, что продукт кому-то не подойдёт. Человек отказывается перехваливать. А нейронка не отказывает никогда. Запомните это, дальше пригодится.
Ну так вот. С текстом все согласны: нейронка пишет плоско. А теперь самое интересное.
нейронка ──────────────────────── разработчик ──╱╲──╱╲──╱╲──╱╲──╱╲──
В коде происходит ровно то же. Просто это спрятано
Та же плоскость, те же повторяющиеся паттерны, одна и та же функция, переименованная пять раз. Но тут есть асимметрия, и в ней — вся статья.
В тексте посредственность видна демократически. Любой, кто много читал, носом чует нейронку. Плоскость текста легитимно замечают тысячи компетентных читателей.
В коде плоскость спрятана за зелёной галочкой тестов. Её видит ровно один человек — инженер, умеющий читать код. А вайб-кодер именно этого человека из процесса и убрал. То есть он купил не код. Он купил видимость работающей системы и отдал наружу единственное суждение, которое сам выполнить не способен.
Я, кстати, уже писал про обратную сторону той же монеты — как Claude на неполном контексте уверенно «находил уязвимости», которых не было, потому что не видел систему целиком. Каждое его замечание было локально корректным и глобально неверным. Тут то же самое, только с другого конца: нейронка генерит локально корректный код, который глобально гнилой, а проверить это некому.
Как я это докажу, чтоб вы не верили мне на слово
Методика такая. Сначала — настоящая функция из легендарного опенсорса, со ссылкой на файл: открывайте и проверяйте. Потом — то, что выдаёт НЕЙТРАЛЬНЫЙ чат с GPT (чтобы независимо) на наивный промпт.
И вот тут ключевой момент, без которого эксперимент был бы жульничеством. Промпт должен быть наивным — таким, какой реально способен сформулировать вайб-кодер, по конечной функции, без тайного знания о граничных случаях. Потому что — вот он, главный тезис — разрыв между кодом сеньора и кодом вайб-кодера, прогнанными через ОДИН И ТОТ ЖЕ GPT, это в основном разрыв в промпте. Несущие решения разработчика не попадают в промпт, потому что для него они очевидны, молчаливы. А вайб-кодер не может попросить то, о существовании чего не знает.
Три функции, специально расставленные по шкале видимости — от «это даже не-кодер увидит» до «это не видит почти никто».
1. secure_filename — видно глазами
Werkzeug, ядро Flask. Делает из имени файла безопасное имя для сохранения на диск.
Настоящая (pallets/werkzeug, файл src/werkzeug/utils.py, BSD-3, © Pallets):
def secure_filename(filename: str) -> str:
filename = unicodedata.normalize("NFKD", filename)
filename = filename.encode("ascii", "ignore").decode("ascii")
for sep in os.sep, os.path.altsep:
if sep:
filename = filename.replace(sep, " ")
filename = str(_filename_ascii_strip_re.sub("", "_".join(filename.split()))).strip("._")
# на nt в каждой папке есть спец-файлы устройств — нельзя, чтобы файл
# назывался так же, иначе подставляем подчёркивание
if os.name == "nt" and filename and filename.split(".")[0].upper() in _windows_device_files:
filename = f"_{filename}"
return filename
А вот что выдаёт нейтральный чат на «сделай безопасное имя файла»:
def secure_filename(filename):
filename = os.path.basename(filename)
filename = filename.replace(" ", "_")
filename = "".join(c for c in filename if c.isalnum() or c in "._-")
return filename
Работает? Работает. Демка отвечает, имя «чистится». А теперь смотрим, что наивная версия пропустила, причём это видно глазами:
secure_filename("..")— настоящая вернёт пустую строку, наивная вернёт.., то есть ссылка на родительскую папку выживает.secure_filename("CON.txt")на Windows — настоящая даст_CON.txt, наивная оставитCON.txt, зарезервированное имя устройства.secure_filename("naïve.txt")— настоящая приведёт к ASCII (naive.txt, портируется везде), наивная оставит не-ASCII, потому чтоisalnum()пропускает юникод-буквы.
Даже вайб-кодер тут способен увидеть: «о, через GPT-версию можно вылезти из папки». Это самый дружелюбный пример. Дальше хуже.
2. lru_cache — середина шкалы
CPython, стандартная библиотека. Кэширующий декоратор. Настоящая реализация (python/cpython, файл Lib/functools.py, PSF License) — это кольцевой двусвязный список с вытеснением по давности использования, RLock для потокобезопасности и аккуратное построение ключа, где f(1) и f(1.0) не путаются.
А наивный декоратор на «напиши кэширующий декоратор»:
def lru_cache(func):
cache = {}
def wrapper(*args, **kwargs):
key = str(args) + str(kwargs)
if key not in cache:
cache[key] = func(*args, **kwargs)
return cache[key]
return wrapper
Что не так:
- Это вообще не LRU. Нет ограничения размера, нет вытеснения — кэш растёт бесконечно. Назвали
lru_cache, а получили утечку памяти. - Хрупкий ключ.
str(args)+str(kwargs): два разных объекта с одинаковымreprдают один ключ, и вернётся ЧУЖОЙ закэшированный результат. Тихая ошибка корректности, которую ты будешь ловить неделю. - Не потокобезопасно. Под нагрузкой — гонки.
Это уже не дыра, это деградация. Видит её разработчик на ревью или твой сервер на проде, когда память кончится. Вайб-кодер — нет.
3. constant_time_compare — не видит почти никто
Django. Сравнить токен пользователя с правильным, вернуть True/False. Настоящая (django/django, файл django/utils/crypto.py, BSD-3, © DSF) — буквально одна строка:
def constant_time_compare(val1, val2):
return secrets.compare_digest(force_bytes(val1), force_bytes(val2))
А наивная, на тот же промпт:
def constant_time_compare(val1, val2):
return val1 == val2
Работает идеально. Проходит все тесты. И уязвима. Обычный == возвращает результат, как только нашёл первый несовпавший байт — значит, время сравнения зависит от того, ГДЕ первое расхождение. Атакующий, замеряя время ответа, подбирает секрет посимвольно. Django сравнивает за постоянное время, чтобы этого нельзя было сделать.
Вот он, главный пример. Код корректен по поведению и эксплуатируем по сути. И заметить это можно, только если ты знаешь про timing-атаки. То есть существует целый слой, который вайб-кодер не видит в принципе. Не «проглядел», а физически не способен увидеть.
Это не случайные косяки, а паттерны
Если разложить, почему так выходит, набирается несколько устойчивых механизмов:
- Регрессия к медиане. Нейронка тянет самый частый паттерн из обучения, а не идиому твоего проекта. Поэтому переписывает то, что уже есть в кодбазе, — она её целиком не видит.
- Локальная связность при глобальной бессвязности. Каждая функция нормальная, а швы не сходятся: деньги тут
float, там копейки вint— и где-то на стыке вылезает ошибка в 100 раз. Прямой аналог хороших предложений в плохом эссе. - Контекстная слепота. Не знает про твоё легаси-ограничение, модель безопасности, конвенции команды. Оптимизирует под промпт, а не под систему.
- Отсутствие несущих решений. Сеньор принимает ОДНО архитектурное решение, после которого следующие 50 фич делаются легко. Нейронка принимает локально разумные решения, которые складываются в техдолг.
- Никогда не отказывает. Помните наушники? Вот тут то же самое. Нейронка не скажет «это требование противоречиво» или «так строить нельзя». Сеньор пушбэчит. Вайб-кодер теряет самое ценное — суждение о том, стоит ли вообще это строить.
Шкала видимости (и при чём тут картинки)
Заметьте, как выстроились три примера. Шесть пальцев на руке у нейросетевой картинки видят все мгновенно. Плоский текст — внимательный читатель. Дыру в constant_time_compare — почти никто.
6 пальцев на картинке видно всем плоский текст внимательному читателю timing-атака почти никому
Чем «глубже» артефакт, тем невидимее в нём гниль и тем длиннее лаг до того момента, когда за неё прилетит счёт. И вот этот лаг вайб-кодера и обманывает: в секунду, когда «работает», он уверен, что поймал ценность.
Невидимая инфляция? Да нет, просто отложенная
Сначала я хотел назвать это невидимой инфляцией. Но это неправда, и кто-нибудь в комментах сразу скажет: да всё же измеримо. Вот именно. В этом и суть.
Инфляция не невидимая — она отложенная и смещённая. Я её уже померил в статье про биржу: цены на базовые проекты обвалились, и — кейсы на ремонт. Люди платят второй раз, чтобы починить код, написанный через LLM. Реальная цена всегда была выше; дешёвая часть на входе — это просто видимый кусок, как идеальная грамматика у текста от нейронки. Остаток приходит по счёту потом.
А механизм вот какой. Мы ведь никогда не оценивали код напрямую — это слишком дорого. Мы доверяли дешёвым прокси-сигналам. «Гладко читается, без ошибок» означало «компетентный человек вложил усилие». «Компилируется, тесты зелёные» означало «кто-то понимающий это проверил». Эти прокси работали как валюта — позволяли передавать доверие, не переделывая работу заново.
Нейронка печатает эти прокси без обеспечения. Идеальная грамматика, за которой ничего нет. Зелёные тесты, за которыми нет понимания. Это буквально печать денег без производства: сначала каждая купюра тратится нормально, потом рынок замечает, что обеспечения нет, — и прокси перестаёт покупать доверие. Текст этот порог уже прошёл: «вылизанный и структурный» теперь читается как «наверное, нейронка, наверное, дёшево», сигнал инвертировался. Код в середине инфляции: «оно работает» тихо теряет силу означать «оно надёжно».
«зелёные тесты» ─▶ доверие ─▶ обеспечения нет
И с продающими текстами ровно то же. Мы не можем написать через нейронку текст, который ГАРАНТИРОВАННО всем что-то продаст. А если бы могли — все бы так и делали, и преимущество мгновенно бы обнулилось, конверсия бы нормализовалась. Нельзя напечатать гарантированную продажу, как нельзя напечатать гарантированно рабочую систему.
Нейросети не обесценивают код — они обесценивают наши способы НЕ читать его.
Что из этого не инфлирует
Не инфлирует только само обеспечение — реальное понимание, вкус, способность отказать. Его нельзя напечатать, поэтому оно остаётся редким и дорожает ровно по мере того, как прокси вокруг него схлопываются.
Я к этому уже приходил в методичке: AI — это усилитель, а не уравнитель. Множитель, а не слагаемое. У эксперта он умножает экспертизу. У человека без знания он умножает незнание, а на неполном контексте уходит в минус. Вайб-кодер сейчас в лонге по инфлирующей валюте — объёму правдоподобного кода — и в шорте по единственному дорожающему активу: компетенции отличить, реален ли хоть кусок этого.
А способность отличить настоящую инженерию от уверенного бреда модели на обрывках контекста делегировать нельзя. В том числе самой модели.
Чем доступнее становятся нейросети, тем дороже стоит тот, кто понимает, что они делают. Усилитель бесполезен, если на входе нет сигнала.
И в коде это работает так же, как в тексте. Просто в тексте вы это уже видите. А в коде — пока нет.
Поток сознания и мысли по таким ситуациям складываю в канал «Плуг».