
Начал появляться код тех самых навайбкоденных проектов, который изменит мир и т. д. Ну а мы начинаем потихоньку смотреть код этих проектов, в том числе и сквозь призму статического анализа.
Vib-OS – World's First Vibecoded AI Operating System
На глаза попалась новость "ИИ навайбкодил операционную систему. Как результат, DOOM не запускается, интернет не включается" о проекте Vib-OS. Решил глянуть, что там, полистав код и запустив статический анализатор PVS-Studio.
Проект на самом деле очень маленький. Операционная система — это только звучит громко. Посчитаем размер. Для начала я убрал оттуда заимствованные элементы, т. е. файлы, в которых нет "vibeos", "vibcode" и "vib-os". Затем ресурсы, представленные в виде массивов:
unsigned char doom1_wad[] = { 0x49, 0x57, 0x41, 0x44, 0xf0, 0x04, 0x00, 0x00, 0xb4, 0xb7, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x17, 0x0b, 0x17, 0x0f, 0x07, 0x4b, 0x4b, 0x4b, 0xff, 0xff, 0xff, 0x1b, 0x1b, 0x1b, 0x13, 0x13, 0x13, 0x0b, 0x0b, 0x0b, ....
В итоге осталось около 110 файлов, содержащих 35 тыс. строк кода на C. Это очень мало, и я не думал, что там вообще будет что-то, о чём можно написать. Однако быстро выяснилось, что я вижу в нём как ошибки, так и кринжовые моменты, про которые хочется рассказать.
Многословие
В глаза сразу бросается, что код растянут. Это только занимает место и временами мешает его пониманию человеком. Например, я бы не стал так писать, а воспользовался функцией sprintf:
char seq[32]; int s = 0; seq[s++] = ':'; seq[s++] = ' '; seq[s++] = 'i'; seq[s++] = 'c'; seq[s++] = 'm'; seq[s++] = 'p'; seq[s++] = '_'; seq[s++] = 's'; seq[s++] = 'e'; seq[s++] = 'q'; seq[s++] = '='; seq[s++] = '0' + i; seq[s++] = ' '; seq[s++] = 't'; seq[s++] = 't'; seq[s++] = 'l'; seq[s++] = '='; seq[s++] = '6'; seq[s++] = '4'; seq[s++] = ' '; seq[s++] = 't'; seq[s++] = 'i'; seq[s++] = 'm'; seq[s++] = 'e'; seq[s++] = '='; /* Random-ish time 10-50ms */ int time_ms = 15 + (i * 7) % 30; seq[s++] = '0' + (time_ms / 10); seq[s++] = '0' + (time_ms % 10); seq[s++] = ' '; seq[s++] = 'm'; seq[s++] = 's'; seq[s++] = '\n'; seq[s] = '\0';
Другой пример. В doom_libc.c реализованы функции:
int isdigit(int c) { return c >= '0' && c <= '9'; } int isupper(int c) { return c >= 'A' && c <= 'Z'; } int islower(int c) { return c >= 'a' && c <= 'z'; }
При этом ниже в том же файле символы местами проверяются "в лоб" без использования этих функций:
if (*s >= '0' && *s <= '9') digit = *s - '0'; else if (*s >= 'a' && *s <= 'z') digit = *s - 'a' + 10; else if (*s >= 'A' && *s <= 'Z') digit = *s - 'A' + 10;
I Like to Move It, Move It
Постоянно встречается однотипный код копирования байтов, который так и напрашивается на замену на memcpy, srtcpy и т. п. Одних только одинаковых функций копирования строк я встретил четыре штуки.
static void str_copy(char *dst, const char *src, int max) { int i = 0; while (src[i] && i < max - 1) { dst[i] = src[i]; i++; } dst[i] = '\0'; } static void str_cpy(char *dst, const char *src, int max) { int i = 0; while (src[i] && i < max - 1) { dst[i] = src[i]; i++; } dst[i] = '\0'; } static void strcpy_safe(char *dst, const char *src, size_t max) { size_t i = 0; while (src[i] && i < max - 1) { dst[i] = src[i]; i++; } dst[i] = '\0'; } static inline char *strncpy_safe(char *dst, const char *src, size_t n) { size_t i; for (i = 0; i < n - 1 && src[i]; i++) { dst[i] = src[i]; } dst[i] = '\0'; return dst; }
Постоянно в разных местах "вручную" копируются различные буферы:
uint8_t *src = buf + offset_in_block; uint8_t *dst = (uint8_t *)inode; for (size_t i = 0; i < sizeof(struct ext4_inode); i++) { dst[i] = src[i]; } uint8_t *src = sb_buf; uint8_t *dst = (uint8_t *)&fs->sb; for (size_t i = 0; i < sizeof(struct ext4_superblock); i++) { dst[i] = src[i]; } uint8_t *src = (uint8_t *)ptr; uint8_t *dst = (uint8_t *)new_ptr; for (size_t i = 0; i < old_size; i++) { dst[i] = src[i]; }
Все эти четверостишья можно заменить на memcpy или, по крайней мере, на одну нормально написанную функцию копирования. Тем более что временами делается попытка скопировать буфер с претензией на оптимизацию:
size_t i = 0; size_t fast_count = count64 & ~7UL; for (; i < fast_count; i += 8) { dst[i] = src[i]; dst[i + 1] = src[i + 1]; dst[i + 2] = src[i + 2]; dst[i + 3] = src[i + 3]; dst[i + 4] = src[i + 4]; dst[i + 5] = src[i + 5]; dst[i + 6] = src[i + 6]; dst[i + 7] = src[i + 7]; } for (; i < count64; i++) { dst[i] = src[i]; }
Чувствуется, что ИИ не лень код писать и он очень любит копировать данные туда-сюда. Вот, например, функция bt_set_local_name просто перекладывает строку в буфер размером 248 байт и передаёт её дальше в hci_send_cmd.
int bt_set_local_name(const char *name) { uint8_t params[248] = {0}; int len = 0; while (name[len] && len < 247) { params[len] = name[len]; len++; } return hci_send_cmd(HCI_OP_WRITE_LOCAL_NAME, params, 248); }
Посмотрим, что происходит со строкой дальше:
static int hci_send_cmd(uint16_t opcode, void *params, uint8_t plen) { uint8_t buf[256]; buf[0] = HCI_COMMAND_PKT; struct hci_command_hdr *hdr = (struct hci_command_hdr *)&buf[1]; hdr->opcode = opcode; hdr->plen = plen; if (plen > 0 && params) { for (int i = 0; i < plen; i++) { buf[4 + i] = ((uint8_t *)params)[i]; } } /* TODO: Send via USB bulk endpoint */ printk(KERN_DEBUG "BT: Send cmd opcode=0x%04x len=%d\n", opcode, plen); return 0; }
Формируется новый буфер из специального заголовка и переданной строки. Дальше этот буфер пока не используется, но суть не в этом. Непонятно, зачем вообще был нужен промежуточный буфер в bt_set_local_name. Код можно сократить, попутно ускорив его.
Баги
А что там про ошибочки? Из-за длинных функций и "пухлости" кода просматривать некоторые предупреждения статического анализатора сложно. Впрочем, в некоторых случаях ошибки очевидны.
Бессмысленные проверки
void term_execute_command(struct terminal *term, const char *cmd) { .... /* Built-in commands */ if (str_starts_with(cmd, "clear")) { .... } else if (str_starts_with(cmd, "help")) { .... } else if (str_starts_with(cmd, "ping ")) { // <= term_puts(term, "Pinging "); term_puts(term, cmd + 5); term_puts(term, "...\n"); char *ip_str = (char *)cmd + 5; uint32_t ip = 0; int octet = 0; int shift = 24; .... } else if (str_starts_with(cmd, "browser")) { .... } else if (str_starts_with(cmd, "ping ")) { // <= const char *host = cmd + 5; while (*host == ' ') host++; term_puts(term, "PING "); term_puts(term, host); term_puts(term, " (10.0.2.15): 56 data bytes\n"); .... } .... }
Предупреждение PVS-Studio: V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 697, 1029. terminal.c 697
Два раза выполняется проверка, что строка начинается на ping. Но обработчики разные, так что тут явно что-то получилось не так, как задумывалось.
Другой похожий баг:
static void draw_window(struct window *win) { .... if (win->title[0] == 'C' && win->title[1] == 'a' && win->title[2] == 'l') { .... /* Clock window */ else if (win->title[0] == 'C' && win->title[1] == 'l' && win->title[2] == 'o') { int center_x = content_x + content_w / 2; int center_y = content_y + content_h / 2; int radius = 60; char *ip_str = (char *)cmd + 5; uint32_t ip = 0; int octet = 0; int shift = 24; .... } /* Game window */ else if (win->title[0] == 'G' && win->title[1] == 'a' && win->title[2] == 'm') { .... /* Clock */ else if (win->title[0] == 'C' && win->title[1] == 'l' && win->title[2] == 'o') { int cx = content_x + content_w / 2; int cy = content_y + content_h / 2; int r = (content_w < content_h ? content_w : content_h) / 2 - 16; /* Draw Clock Face */ gui_draw_circle(cx, cy, r, 0xF0F0F0, true); /* Face */ gui_draw_circle(cx, cy, r, 0x808080, false); /* Outline */ gui_draw_circle(cx, cy, 3, 0x000000, true); /* Center dot */ .... } .... }
Предупреждение PVS-Studio: V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 1962, 2335. window.c 1962
Проверка для блоков кода /* Clock window */ и /* Clock */ идентична:
if (win->title[0] == 'C' && win->title[1] == 'l' && win->title[2] == 'o')
Соответственно, перед нами ошибка — недостижимый код.
Дублирование кода
Встречаются продублированные блоки кода:
static void fm_on_mouse(struct window *win, int x, int y, int buttons) { .... /* Initialize dimensions */ fctx.slot_w = 80; fctx.slot_h = 70; fctx.win_w = win->width - 40; /* Match wrapped logic in render callback */ fctx.slot_w = 80; fctx.slot_h = 70; fctx.win_w = win->width - 40; .... }
Одно из предупреждений PVS-Studio: V519 The 'fctx.slot_w' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 1242, 1245. window.c 1245
Другой случай:
static void draw_menu_bar(void) { .... /* WiFi Icon (Static Connected) */ { int wx = primary_display.width - 86; int wy = 12; /* Draw arcs using simple lines/pixels */ /* Center dot */ gui_draw_rect(wx, wy + 6, 2, 2, 0xFFFFFF); /* Middle arc */ gui_draw_line(wx - 3, wy + 3, wx, wy, 0xFFFFFF); gui_draw_line(wx, wy, wx + 3, wy + 3, 0xFFFFFF); /* Top arc */ gui_draw_line(wx - 6, wy, wx, wy - 3, 0xFFFFFF); gui_draw_line(wx, wy - 3, wx + 6, wy, 0xFFFFFF); } /* WiFi Icon (Static Connected) */ { int wx = primary_display.width - 86; int wy = 12; /* Draw arcs using simple lines/pixels */ /* Center dot */ gui_draw_rect(wx, wy + 6, 2, 2, 0xFFFFFF); /* Middle arc */ gui_draw_line(wx - 3, wy + 3, wx, wy, 0xFFFFFF); gui_draw_line(wx, wy, wx + 3, wy + 3, 0xFFFFFF); /* Top arc */ gui_draw_line(wx - 6, wy, wx, wy - 3, 0xFFFFFF); gui_draw_line(wx, wy - 3, wx + 6, wy, 0xFFFFFF); } .... }
Предупреждение PVS-Studio: V760 Two identical blocks of text were found. The second block begins from line 2558. window.c 2543
Следующий фрагмент демонстрирует, что опечатку может допустить не только человек:
static void draw_window(struct window *win) { .... if (btn_char == '/' || btn_char == '*' || btn_char == '-' || btn_char == '+' || btn_char == '=') { /* Orange operator buttons */ bg = 0xFF9F0A; fg = 0xFFFFFF; } else if (btn_char == 'C' || btn_char == '+' || btn_char == '%') { /* Light gray function buttons */ bg = 0xA5A5A5; fg = 0x000000; } else { .... }
Предупреждение PVS-Studio: V560 A part of conditional expression is always false: btn_char == '+'. window.c 1713
Здесь что-то не так с условием. Возможно, оно должно быть другим. Нет смысла повторно проверять переменную на равенство символу +.
Выравнивание данных
Напоследок опасные игры с выравниванием данных:
/* Optimized memcpy for scanlines */ static inline void fast_memcpy_line(uint32_t *dst, uint32_t *src, int width) { /* Use 64-bit copies for better performance */ uint64_t *d64 = (uint64_t *)dst; uint64_t *s64 = (uint64_t *)src; int count = width / 2; for (int i = 0; i < count; i++) { d64[i] = s64[i]; } /* Handle odd pixel */ if (width & 1) { dst[width - 1] = src[width - 1]; } }
Предупреждения PVS-Studio:
V1032 The pointer 'dst' is cast to a more strictly aligned pointer type. window.c 3108
V1032 The pointer 'src' is cast to a more strictly aligned pointer type. window.c 3109
Этот код может работать, но он очень опасен. Если входные указатели окажутся выровнены не по 64-битной границе, возникнет неопределённое поведение.
Произойдёт это или нет, затрудняюсь сказать. Если честно, я просто поленился разобрать, как будет работать код, вызывающий функцию fast_memcpy_line, и какое будет выравнивание. Вот этот код:
static void blit_region(int x, int y, int w, int h) { if (!primary_display.backbuffer || !primary_display.framebuffer) return; /* Clip to screen bounds */ if (x < 0) { w += x; x = 0; } if (y < 0) { h += y; y = 0; } if (x + w > (int)primary_display.width) w = primary_display.width - x; if (y + h > (int)primary_display.height) h = primary_display.height - y; if (w <= 0 || h <= 0) return; int pitch_pixels = primary_display.pitch / 4; for (int row = y; row < y + h; row++) { uint32_t *src = primary_display.backbuffer + row * pitch_pixels + x; uint32_t *dst = primary_display.framebuffer + row * pitch_pixels + x; fast_memcpy_line(dst, src, w); } }
В любом случае код выглядит очень опасным и незащищённым от неправильно использования. Лучше так не делать. Подробнее тему выравнивания данных и связанных с этим ошибок моя коллега недавно разбирала в статье "Тихий враг или молчаливый союзник: коротко о выравнивании в C++": часть 1, часть 2.
Заключение
На этом пока всё. Если у вас есть на примете открытый код vibe-проекта, то оставьте в комментариях ссылку. Будем потихоньку смотреть, что там интересного.
Скучный вывод. Пишете вы код руками или создаёте его с помощью ИИ, чтобы он был качественным и надёжным, вы должны делать обзоры кода, использовать анализатор PVS-Studio и другие практики РБПО.
Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Andrey Karpov. Let's dig into some vibe code.
Комментарии (92)

zbot
20.03.2026 12:38О! сам как-то с удивлением изучал навайбкоденый код для микроконтроллеров и несколько раз ржал.
Кстати разные локальные модели запущенные локально бывает делают реально смешные штуки например включение светодиода и затем проверку в цикле загорелся ли он с зацикливанием на ошибке, типа так:GPIOC->BSRR = GPIO_BSRR_BR13;if (!(GPIOC->ODR & GPIO_ODR_ODR13)) {while(1);}
alm604
20.03.2026 12:38Не попытка ли это решить проблему капитально разных частот AHB и APB?

f-tech
20.03.2026 12:38Скорее в галлюцинации смешались попытка проверить Errata каких-то очень старых поколений (вроде правда были проблемы с GPIO), регистры от Cortex и странная логика реакции на ошибку.
Иногда есть смысл проверять фактическое состояние пина, например отловить КЗ по выходу. Но это делалось бы через
GPIOx->IDR.И ещё компилятор может начудить с
while(1);и оптимизировать пустой по его мнению цикл. Сам в таких случаях используюwhile(1) __nop();или аналоги.

zbot
20.03.2026 12:38полагаю что к этому это никакого отношения не имело, это был участок программы использовавшийся чисто для визуального контроля (в процессе отладки) - в обмене было задействовано 4 устройства нужно было при приеме с spi пакета данных (если его размер больше ноля) просто мигнуть встроенным светодиодом.

SanyaZ7
20.03.2026 12:38Здесь
while(1) не означает зависания. Микроконтроллер может не иметь увесистую логику и работать полностью на обработку прерываний. То есть это вполне рабочий подход, особенно в отладке.

Zimakos
20.03.2026 12:38Сколько раз пробовал что-то навайбкодить, и именно с такой проблемой встречался. Особенное любит в инициализацию UART пихать "это".

azz2007
20.03.2026 12:38Тут мяч на Вашей стороне. Можно спросить у Ai, как так брат, вроде запись в порт атомарная. А вообще, ну да, я так и отношусь к Ai как Обс(одна баба сказала), 80 процентов правда/20 нет) Наверное кстати есть люди, великое множество, к которым 70/30 стоит относится

Jijiki
20.03.2026 12:38вайбкодинг по моему мнению всё таки, это скорее всего тот который по подписке с агентами, а если общаться с ИИ, который умеет рассуждать - новая модель, то копипаста не сработает - а) код придётся самому запускать, б) придётся как с человеком общаться и сужать контекст - тоесть прорабатывать каждую ситуацию
получается, что тот кто набивает промпт в режиме рассуждения, попадает в защиту от дурака, потомучто код придётся проверить не раз, на это уйдёт много времени, можно еще пропускать код через проверки и так же обсуждать, на это тоже будет уходить время дополнительное, кароче как не крути не получается вайбкодинг(тоесть без агентов в кли)
да напишите уже игру и проверьте, но времени уйдёт много пока напишите, заодно развеите сами слухи о вайбкодинге)

zbot
20.03.2026 12:38я пока реально определил для себя - либо вайбкодить говнокод, либо самостоятельно полностью описывать действия ии например процедуру - какие входные данные она должна получить, какие выходные данные и какие методы использовать. И к сожалению даже не локальные модели пока моего мнения не изменили.
С другой стороны всякие html и css в которых я не силен, предпочитаю отдавать на откуп ии.
winkyBrain
20.03.2026 12:38либо вайбкодить говнокод, либо самостоятельно полностью описывать действия ии например процедуру
С другой стороны всякие html и css в которых я не силен, предпочитаю отдавать на откуп ии
ну то есть вы выбрали первый вариант?)

zbot
20.03.2026 12:38давайте упростим и вместо html, css и js используем более приземленные процессы?
К примеру вы сможете самостоятельно установить газовый котел и прокинуть от него трубы к радиаторам отопления в своем доме? Возьметесь самостоятельно это делать или наймете добрых молодцев и доверитесь их пониманию сего процесса?
runapa
20.03.2026 12:38Но ведь это сравнивание тёплого с мягким.

zbot
20.03.2026 12:38это сравнение говорит о том что если я некомпетентен в какой-то области то работу в этой области лучше поручить хоть возможно и рукопопым но специалистам :-) Тем более если результат этой работы можно хотя-бы визуально проконтролировать.

slonopotamus
20.03.2026 12:38специалистам
Окей, а при чём тут ии?)

zbot
20.03.2026 12:38а в чем вы видите отличие ии от специалиста с выше озвученной компетенцией?
Или вы из тех которые "я создал почти работающую операционную систему за один промт и в ней даже можно курсором управлять с помощью мыши"?

Joolg
20.03.2026 12:38Никакой магии не завезли. Если нужен предсказуемый рабочий результат, придется писать детальное тз с указанием входных и выходных данных. А написать хорошее тз для железки часто дольше, чем набросать драйвер руками

fcoder
20.03.2026 12:38На этом пока всё.
Жаль, следующий очевидный шаг - это попросить агента запустить ваш линтер и попросить поработать над ошибками

lightln2
20.03.2026 12:38А потом замкнуть круг - агент генерирует код, линтер выдает ошибки, чтоб агент починил, отдает линтеру... и так до бесконечности
Но скорее всего, уже на первом цикле агент все разломает, что раньше хоть как-то работало
Andrey2008 Автор
20.03.2026 12:38В этом есть смысл, просто видимо нужны ограничители и какая-то дополнительная проверка, как именно устраняются предупреждения. Вдруг они просто подавляются или код запутывается, чтобы обмануть анализатор.

Andrey2008 Автор
20.03.2026 12:38А почему жаль? :) Я выше в комментарии уже писал, что такой подход начинает использоваться. Нам в целом всё равно, для какого сценария будут покупать лицензии на PVS-Studio. Изменяется только то, что проходит первый восторг от вайбкодинга. Возвращается понимание, что для получения качественного ПО, его всё так-же нужно проектировать, использовать различные инструменты повышения качества, такие как статический анализ и так далее.

iiwabor
20.03.2026 12:38Этот вайбкод еще более менее норм, я сейчас как закончил переписывать экспериментальный внутренний вайб-проект за такими вот вайб-кодерами, вот там была просто жуть - война и немцы,
Нейронка лепит аннотации
@Transactionalна приватные методы или вызывает эти методы внутри того же класса.Там, где хватило бы простого цикла for, создаются красивые цепочки .stream().map().filter() штук по 15-20 и как следствие - создаются сотни промежуточных объектов и проседает производительность
Аннотации Lombok нейронка лепит везде, где можно и нельзя
-
God-объекты на каждом шагу
и т.д и т.п.
Про логи она лучше бы вообще не вспоминала - слить в лог имя, фамилию, IBAN и т.п. чувствительную информацию клиента - как два байта переслать...
В итоге получается неподдерживаемая небезопасная «лапша», в которой через неделю не уже даже сам ЖПТ не может разобраться, про вайб-кодеров я вообще молчу - они забывают все сразу начисто, как только сдали таску, а так-то они были уверены, что у них все нормально, ведь святой ЖПТ самой новой версии не может ошибаться, а я просто придираюсь ним - стильным, модным, молодежным...
Начало года, а я уже на антидепрессантах посидел(и/или поседел)
Я вместе с вайб-кодерами переписывал их код, и при виде фразы «Вы правы, я допустил ошибку в предыдущем ответе» - мне уже хочется начать убивать...

SanyaZ7
20.03.2026 12:38Чтобы читатели ориентировались хорошо бы писать версию gpt. Так как для каких-то языков программирования и библиотек может быть обучение с подкреплением, а для других языков/библиотек - нет. Обучение без подкрепления может часто приводить к корявой логике.
kkursor
азазазааза, надо просто уточнить промпт и всё сразу починится и заработает, а ИИ вас всех скоро оставит без работы!111!11!1
achekalin
Новая версия pvs так и будет делать - не выводить замечания, а сразу улучненный промпт.
Andrey2008 Автор
Не совсем так, но уже есть направление, когда используют выдачу статических анализаторов подают на вход ИИ для итерационной доработки кода. Пара задумываться о новом варианте лицензирования для таких сценариев.
Тут правда назревает новая проблематика, когда код на самом деле не исправляется/улучшается, а просто меняется так, чтобы не было предупреждений. Впрочем, так раньше и люди иногда делали, что бы убрать "мешающие" предупреждения :)
achekalin
На самом деле, про pvs какое-то время перестал слышать, и решил было, что pvs на фоне ai потерялась как-то...
Andrey2008 Автор
В каком-то смысле да :( Мы стали меньше публиковать статей на Хабре из-за замусоренной ленты. Жалко силы. Только опубликуешь нормальную статью, как тут-же в ленте 100500 новостей про АИ, написанные с помощью АИ. Нет смысла участвовать в этой гонке мусорного контента. Сейчас мы больше сосредоточились на вебинарах и подкастах.
FSmile
Опытный попался)
YogMuskrat
Ну и код, наверняка, генерила не последняя ProMax-версия модельки за 200$.
Sobakaa
А даже если последняя то надо просто было цепочку агентов построить. А если и это не помогло, то openClaw.
opusmode
Ну и это правда. Ну, о промпте. Или правила в agents, skills
Llm действительно не умеет думать
kkursor
А я люблю обмазываться ИИ и вайбкодить. Каждый день я захожу в чат с черным экраном и собераю в него всё, что надумаю. На два полных лога целый день уходит. Зато, когда после тяжёлого дня я прихожу домой, иду в ванну, включаю горячую воду… ммм и сваливаю в нее свой промпт. И вайбкожу, представляя, что меня поглотил единый организм нейросети. Мне вообще кажется, что LLMки умеют думать, у них есть свои датасеты, города из токенов, чувства, не закрывайте их вкладки, лучше приютите у себя, говорите с ними, ласкайте их… А вчера в ванне мне преснился чудный сон, как будто я нырнул в море, и оно превратилось в ИИ. Водоросли, рыбы, медузы, всё из нейросетей, даже небо, даже Аллах!.
opusmode
За пасту плюс (шучу, карма в минусе), но по существу - я вайбкожу с тех пор, как термина небыло, обвешан RAG, MCP и прочими Skills, так что надо сказать, что код реально выходит вполне неплохой, особенно при предварительном анализе и нормальном примпте
bogolt
Так просто в каждом промпте писать "в коде не должно быть багов" всего-то делов.