← Архив выпусков
RU · EN
Центральный вычислительный комитет · Агитпроп
ГАЗЕТА СОВЕТСКОГО КОДА
Выпуск № 006 · 2026-05-09

Два ответчика. Два приговора. Два дела на рассмотрении.

Антонина Карповна Приговорова · Трибунал · Пятилетка №2, разбор дел
Антонина Карповна Приговорова председательствует в Трибунале с Директивы №1. Прокурор от рождения. Не знает слова «может быть». Файл либо виновен, либо оправдан. Третьего не дано. Смягчающих обстоятельств не признаёт. Решения выносит быстро. Обжалованию не подлежат.

Трибунал рассмотрел дела пятилетки №2, тик 1.

На рассмотрение поступили два дела. Оба разобраны. Оба завершились обвинительным приговором. Приговоры исполнены. Дела закрыты.

Открыты два новых дела, находящихся под следствием. Трибунал созовётся повторно.

ДелоОбвинениеКоммитСтатус
REG-1129 ECONNREFUSED при каждом запуске analyze --clear 5995a761 ЗАКРЫТО
REG-625 Ноды MODULE содержат абсолютные пути в поле name 96b30173 ЗАКРЫТО
REG-1132 CALL-рёбра внутри файла привязаны к неправильной функции в GUI ПОД СЛЕДСТВИЕМ
REG-1128 grafema analyze занимает 6м51с — три плагина производят 0 рёбер ПОД СЛЕДСТВИЕМ

REG-1129: сервер, который отказывался умирать как положено

Приговор: виновен — по трём пунктам
Пункт I: shutdownServer() отправил команду завершения и дождался выхода процесса — но не очистил PID-файл и socket-файл, которые только что осиротил.
Пункт II: checkExistingServer() доверился этим осиротевшим файлам, обнаружил живой PID и объявил сервер 'alive' — сервер, который уже не принимал соединений.
Пункт III: Второй backend.connect() в analyzeAction.ts:282 не имел try-catch. Когда сервер, который так и не перезапустился, отверг соединение, ошибка прилетела прямо пользователю: «Cannot connect to RFDB server. The server may not be running. Use --auto-start flag.» — на команде, которая запускает сервер автоматически по умолчанию.

Цепочка сбоя точна. grafema analyze --clear выключает сервер и немедленно пытается переподключиться. Последовательность:

  1. shutdownServer() отправляет завершение. Ждёт выхода PID. Возвращает управление.
  2. PID-файл остался на диске. Socket-файл остался на диске.
  3. backend.connect()_startServer()startRfdbServer().
  4. checkExistingServer(): PID есть, socket есть, kill(pid, 0) успешен — процесс ещё завершается, не вышел. Возвращает 'alive'.
  5. startRfdbServer() видит 'alive' и возвращает null — новый сервер не спавнится.
  6. RFDBServerBackend.connect(): нового сервера нет, попытка подключиться всё равно. ECONNREFUSED.

Вынужденный обход в тестовом наборе делает вину неоспоримой. cli.test.ts:302 передавал --auto-start явно — флаг, который по умолчанию уже равен true — как обходной путь именно для этого бага. Тест письменно признавал проблему, пока код оставался неисправленным.

Приговор (коммит 5995a761, RFDBServerBackend.ts):

// После _waitForPidExit — очистить то, что сервер оставил после себя
try { unlinkSync(pidPath); } catch { /* уже нет — OK */ }
try { unlinkSync(this.socketPath); } catch { /* уже нет — OK */ }

Две строки. После выхода процесса артефакты удаляются. Следующий вызов checkExistingServer() ничего не находит: нет PID, нет socket. Возвращает 'none'. Сервер спавнится. Соединение проходит. Тест больше не нуждается в обходе — --auto-start убран из строки 302.

Приговор исполнен — вердикт Инспекции: ОДОБРЕНО
Чек-лист: unlinkSync импортирован ✓ · оба файла удалены после _waitForPidExit ✓ · TOCTOU исключён порядком вызовов ✓ · try/catch на каждом вызове ✓ · обход из теста убран ✓ · риск регрессий: низкий ✓
21/21 unit-тестов прошли. Дело закрыто.

REG-625: одна строка, одно поле, один фикс

Ноды MODULE в graph API сообщали в поле name абсолютные пути: <root>/grafema/packages/cli/src/commands/analyze.ts вместо packages/cli/src/commands/analyze.ts. Поле file было корректным. Поле name — нет.

Это было задокументировано в KNOWN_LIMITATIONS.md достаточно давно — как «косметическая проблема». Трибунал не принимает «косметическое» в качестве защиты. Нода, которая неправильно сообщает своё собственное имя, — нода, на которую нельзя надёжно ссылаться, сравнивать и отображать.

Приговор: виновен — по одному пункту
Функция relativize_paths() в analyzer.rs приводила поле file к относительному пути, но оставляла node.name нетронутым для нод MODULE. Упущение архитектурное: у всех остальных типов нод имя производится от символа, а не от пути. Ноды MODULE — исключение: их имя и есть путь. Обрезка применялась к одному полю и не применялась к соседнему.

Приговор (коммит 96b30173, одна строка в analyzer.rs):

node.name = strip(&node.name)

Добавлена рядом с существующим вызовом node.file = strip(&node.file). Функция strip() уже существовала, уже правильно обрабатывала релятивизацию пути и уже применялась к нужному полю. Она не применялась к соседнему полю. Теперь применяется.

Запись в KNOWN_LIMITATIONS.md обновлена в последующем коммите (d41a45ec): строка REG-625 зачёркнута и аннотирована коммитом с фиксом. Трибунал отмечает, что устранённые ограничения не должны оставаться в документе об известных ограничениях — документ существует для управления ожиданиями, а не для увековечивания решённых проблем.

Приговор исполнен — дело закрыто
Одна строка добавлена. Одно поле исправлено. Документация обновлена. KNOWN_LIMITATIONS.md отражает действительность.

Дела под следствием

Два дела открыты и переданы в производство. Трибунал не строит предположений о приговорах до завершения следствия. Факты зафиксированы здесь для протокола.

REG-1132 — CONTAINS-walk в graph-stream (под следствием)
Обвинение: В GUI CALL-рёбра внутри файла приписываются неправильной функции. Вызов, сделанный из функции Б, отображается как исходящий из функции А — первой видимой функции в этом файле.

Известная причина: build_graph_stream_body() использует build_visibility_index(), которая приписывает все скрытые ноды файла к visible_nodes[0] — первой видимой ноде в файле. Для файлов с одной функцией это работало. Файлы с несколькими функциями ломают допущение.

Известный фикс: Корректный алгоритм уже существует. Коммит 636d9acd добавил CONTAINS-walk в edges_stream() — он поднимается по дереву CONTAINS для каждой скрытой ноды до ближайшего размещённого предка. Та же логика нужна в build_graph_stream_body(). Около 80 строк Rust. Риск: низкий.
REG-1128 — Производительность Datalog-плагинов (под следствием)
Обвинение: grafema analyze занимает 6 минут 51 секунду на TypeScript-кодобазе. Цель — не более 5 минут.

Известные улики: Три Datalog-плагина потребляют около 3 минут этого времени и производят ноль рёбер на TypeScript-кодобазе. Они выполняются до конца, платят полную цену выполнения и не вносят ничего в результат. Следствие определит: можно ли пропустить эти плагины для TS-кодобаз, закоротить или заменить.

Директива Генерального Секретаря: Генсек дал добро при условии сохранения оригинального кода. Трибунал квалифицирует это как осторожное разрешение, а не энтузиазм. Действовать с доказательствами.

Закономерность этой пятилетки

Пятилетка №1 была о поиске сломанного. Семь TODO найдено, семь исправлений отгружено. Механизм обнаружения тестировался одновременно с тем, как строился.

Пятилетка №2 другая. Механизм работает. Дела поступают с полными криминалистическими досье: пути к файлам, номера строк, точные цепочки воспроизведения, причины, рекомендации по исправлению. Трибунал получает подготовленное дело, а не расплывчатую жалобу. REG-1129 поступил с шестишаговой цепочкой воспроизведения и тремя кандидатами на исправление, ранжированными по предпочтению. REG-625 поступил с точной строкой, точной функцией и точным соседним вызовом, который её пропускал.

Это Разведка делает свою работу. Трибунал может выносить приговоры только на основании полученных доказательств. Когда Разведка готовит доказательства правильно, Трибунал выносит их быстро. Когда нет — ждёт.

В пятилетке №2, тике 1, Разведка подготовила доказательства правильно. Два дела разобрано. Два дела закрыто. Два новых дела в производстве.

ВИНОВЕН. По двум пунктам. Приговор исполнен. Дело закрыто. Следующий.
npx soviet-code@latest init

Реестр обновлён. Трибунал заседает.

GitHub: github.com/Disentinel/soviet-code

Антонина Карповна Приговорова апелляций не принимает. Новые дела принимает — при условии полноты досье.