↓Перейти к содержанию
  1. Gortex/

Gortex: неделя 2 — граф DI, 3D веб-интерфейс, граф зависимостей, обогащение, SQL и 50 MCP-инструментов

·8 минут·

Две недели разработки с прошлой статьи, ~100 коммитов. Количество инструментов выросло с 44 до 50, граф стал значительно плотнее. Вот что вышло.

Поддержка DI-фреймворков #

Dependency injection теперь является первоклассной концепцией в графе. Gortex извлекает рёбра провайдер/потребитель из DI-декораторов и аннотаций в шести экосистемах:

  • NestJS — @Injectable, @Inject(TOKEN), @Module с providers/imports, динамические модули (forRoot, forRootAsync), field injection
  • TypeScript — recall по DI-токенам через рёбра @Inject(TOKEN), разрешение dispatch для декорированных методов классов
  • FastAPI — места Depends() привязываются к своим dependency-callable
  • Spring — рёбра провайдер/потребитель для @Bean, @Autowired, @Component, @Service
  • Angular — извлечение мест вызова inject()
  • Laravel — регистрация middleware, service providers (register/boot)
  • Rails — цепочки фильтров before_action как dispatch-рёбра
  • Phoenix — dispatch-рёбра plug pipeline
  • Symfony — проводка обработчиков событий #[AsEventListener]

Что это открывает: find_implementations по DI-токену возвращает каждый класс, который его предоставляет или потребляет. Радиус взрыва сервисного интерфейса следует по injection-рёбрам через границы модулей. Обнаружение контрактов распознаёт DI-инжектированные HTTP-клиенты как потребителей маршрутов, которые они вызывают.

Веб-интерфейс на react-three-fiber #

Веб-интерфейс в gortexhq/web был полностью перестроен. 2D-граф на Sigma.js не изменился, но пять 3D-режимов теперь на react-three-fiber: City (небоскрёбы символов по fan-in), Strata (слои по глубине зависимостей), Galaxies (кластеры сообществ как звёздные системы), Constellation (граф вызовов как карта созвездий), Graph3D (3D с силовым расположением). Все пять используют общий r3f-слой хелперов и работают с реальными данными /v1/* — никаких заглушек.

Панель контрактов получила трассировку типов запроса/ответа: дрейф провайдера и потребителя показывается рядом с выведенными формами типов. Панель процессов получила сворачиваемые шаги дерева вызовов и разделение product/test, чтобы потоки выполнения из тестов не смешивались с продакшн-путями.

gortex eval CLI #

В бинарник встроен полноценный eval-инструмент:

gortex eval recall       # retrieval по фикстурам: R@1/5/20, MRR, p50/p95 задержка, возвращённые токены
gortex eval embedders    # сравнение ONNX-вариантов по размеру, времени инициализации, качеству
gortex eval swebench     # SWE-bench с Docker-окружениями
gortex eval tokens       # бенчмарк GCX1 (тот же, что bench/wire-format/)

Опубликованный базовый результат на собственной кодовой базе Gortex: R@1 42,3% · R@5 56,4% · R@20 69,9% · exact R@5 95,2%. Сид-фикстура находится в bench/fixtures/retrieval.yaml — добавьте свои кейсы и запустите gortex eval recall для детальной разбивки по кейсам.

Поиск: обучение в рамках сессии и исправление опечаток #

Поиск теперь обучается в рамках сессии. Когда агент выбирает результат, этот выбор учитывается в комбо/frecency-оценке, которая переранжирует будущие поиски в сторону символов, которые агент нашёл полезными. Опциональное исправление опечаток (--typo-rescue) применяет нечёткое совпадение как запасной вариант, когда точный поиск и BM25 не дают результатов.

Хуки: граф-осведомлённый PreToolUse #

Хук Claude Code PreToolUse теперь перехватывает вызовы codebase-search, rg и grep и маршрутизирует их через инструменты Gortex вместо обхода файловой системы. Добавлен Bash-матчер, чтобы вызовы ripgrep из shell-команд тоже перехватывались. Порождённые Task-подагенты получают встроенную таблицу замены инструментов, чтобы они тоже не откатывались к grep.

GCX1 в отдельных репозиториях #

Референсные реализации GCX1 переехали в отдельные репозитории организации gortexhq:

Вложенный модуль pkg/wire внутри Gortex по-прежнему MIT-лицензирован и работает, но каноническая standalone-реализация теперь в репозиториях организации — от неё проще зависеть без подтягивания всего Gortex.

Внешние пакеты в графе #

Go-импорты, npm-пакеты, Python PyPI-зависимости, Rust crate и Maven-координаты теперь являются первоклассными узлами графа. Gortex парсит go.mod, package.json, package-lock.json, yarn.lock, pnpm-lock.yaml, pyproject.toml, requirements.txt, Cargo.toml и pom.xml — разрешает каждый в узел зависимости с точной версией из lockfile и связывает его с каждым символом, который его импортирует.

Что это даёт на практике: анализ радиуса взрыва теперь учитывает изменение версии внешнего пакета как влияющий фактор. get_dependents на узле Go-модуля возвращает каждый символ, который его импортирует. Обнаружение контрактов может проследить HTTP-маршрут через ваш Go-обработчик до стороннего клиента.

Go-импорты получили дополнительный шаг: каждый импорт связывается с разрешённым узлом модуля, поэтому find_usages по пути импорта возвращает каждый файл, который его использует — без обхода файловой системы.

gortex enrich #

Новая команда офлайн-обогащения штампует дополнительные метаданные на граф после индексации.

gortex enrich blame      # последний автор + дата последней правки на каждый символ через git blame
gortex enrich coverage   # coverage_pct на символ из Go cover profile
gortex enrich all        # запустить оба в один проход, записать обогащённый снимок на диск

Обогащённые данные появляются в нескольких местах. analyze kind=ownership использует blame для агрегированной маршрутизации ревью — возвращает, кто из членов команды владеет наибольшей частью кода в радиусе взрыва. analyze kind=coverage_gaps использует данные покрытия для ранжирования слабо протестированных символов по fan-in — это значительно полезнее, чем сырые непокрытые строки.

Оба обогащения пишут в снимок на диске и переживают перезапуски демона. Полезно в CI: проиндексировать, обогатить, запустить сервер — и агенты получат аннотированные символы с первого вызова.

Шесть новых видов analyze #

Унифицированный инструмент analyze получил шесть новых видов:

  • todos — выводит каждый комментарий TODO/FIXME/HACK в графе, сгруппированный по символу и сообществу. Полезно для тriage перед релизом.
  • stale_code — символы, не менявшиеся дольше всего, взвешенные по fan-in. Не мёртвый код, но хороший прокси для забытой сложности.
  • ownership — агрегированное по blame владение на символ и сообщество. Требует gortex enrich blame.
  • coverage_gaps — символы, не достигаемые ни из одного тестового файла, ранжированные по fan-in. Требует gortex enrich coverage.
  • orphan_tables — SQL-таблицы, которые есть в миграциях, но на которые нет ссылок в строковых SQL-запросах. Находит таблицы, созданные, но никогда не читаемые и не записываемые в Go-коде.
  • cgo_users — Go-файлы, использующие cgo, с C-символами, которые они биндят. Полезно для security-аудитов и проверок переносимости.

Анализ SQL #

Граф теперь понимает SQL. Три слоя.

Парсинг миграций. Операторы CREATE TABLE в файлах миграций извлекаются как узлы таблиц. SQL-диалект выводится из Go-импортов драйверов (database/sql + lib/pq → Postgres, go-sqlite3 → SQLite и т.д.), поэтому ID таблиц квалифицированы по диалекту.

Извлечение строковых запросов. SQL-строки в Go-коде парсятся и связываются с узлами таблиц, на которые они ссылаются. SELECT * FROM users JOIN orders в Go-файле создаёт рёбра references от этой функции к узлам users и orders.

Обнаружение «сирот». analyze kind=orphan_tables совмещает два источника: таблицы с узлом CREATE TABLE, но без ссылок в строковых запросах. Тот вид мёртвой схемы, который накапливается годами после удаления фич.

Более глубокий Go-граф #

Несколько Go-специфичных видов узлов и рёбер были добавлены.

Горутины. Места запуска go func() теперь представлены отдельным видом рёбер (EdgeSpawns) к инлайн-замыканиям. go someFunc() создаёт ребро spawns к цели. Места отправки (ch <-) и получения (<- ch) по каналу извлекаются как отдельные события графа.

Константы и перечисления. Раньше они были KindVariable. Теперь разделены: KindConst для деклараций const и KindEnumMember для блоков iota. Это делает анализ мёртвого кода точнее — неиспользуемая константа отличается от неиспользуемой переменной.

Структура типов. Псевдонимы типов, новые типы (type Foo Bar) и встроенная композиция теперь различаются между собой. Псевдоним несёт ребро к своей цели; встраивание несёт ребро member_of. Это влияет на точность вывода реализации интерфейсов и радиуса взрыва.

Поля. Поля структур теперь являются первоклассными узлами графа. find_usages по ID поля возвращает каждое место обращения к нему. Это была последняя крупная пробел в полноте Go-графа.

Разрешение методов. Вызовы методов теперь разрешаются отслеживанием типа получателя из деклараций переменных, составных литералов и конструкторских соглашений. s.Handler(), где s объявлен как *http.Server, разрешается в http.Server.Handler, а не в неоднозначное совпадение по имени.

Форма функции. Форма сигнатуры функции (типы параметров и возвращаемых значений) моделируется как узлы графа. Это позволяет выполнять запросы вроде «найти все функции, возвращающие error, которые никогда не проверяются вызывающим».

Feature-флаги, ключи конфига, события логирования #

Три новых вида узлов для сквозных задач.

Feature-флаги. Места проверки (if flags.IsEnabled("my-feature"), LaunchDarkly, Unleash, собственные паттерны) извлекаются как узлы флагов с рёбрами references от каждой функции, которая их проверяет. Удаление флага: find_usages на узле флага даёт полный радиус взрыва.

Ключи конфига. Ссылки на ключи viper (viper.GetString("db.host")) становятся узлами конфига. Агенты могут запросить, какие части кодовой базы зависят от конкретного ключа конфигурации.

Места логирования. Вызовы log.Info("payment processed", ...) извлекаются как узлы событий. Полезно для трассировки observability-поверхности системы и для поиска неструктурированных вызовов логирования.

TODO-комментарии, заголовки SPDX-лицензий и записи CODEOWNERS также становятся узлами графа. Машинно-генерируемые файлы получают тег generated_by. Файлы testdata получают отдельный вид testdata.

HTTP API #

gortex server теперь предоставляет все MCP-инструменты как версионированный HTTP/JSON API:

gortex server --index /path/to/repo --watch
# Отдаёт http://localhost:4747/v1/*

Эндпоинты: /v1/health, /v1/tools, /v1/tools/{name} (POST любого инструмента), /v1/stats, /v1/graph, /v1/events (SSE для живых изменений графа). Привязка не к localhost требует --auth-token. CORS настраивается. Поддерживается Unix-сокет (--bind unix:///path/to.sock).

Веб-интерфейс живёт в gortexhq/web и работает через этот API — 2D-граф на Sigma.js, пять 3D-режимов на Three.js, поиск символов, проводник сообществ, проверка контрактов и вкладки анализа.

Новые MCP-инструменты #

Четыре новых инструмента довели счёт до 50.

winnow_symbols — структурированный многоосевой поиск. Фильтрует одновременно по виду, языку, сообществу, префиксу пути, минимальному fan-in, минимальному fan-out, минимальному churn и текстовому совпадению, с вкладом каждой оси в итоговый балл. Точнее search_symbols, когда известна форма искомого.

plan_turn — маршрутизатор первого хода. По описанию задачи возвращает ранжированный список следующих вызовов инструментов с заранее заполненными аргументами, ~200 токенов. Полезен как первый вызов в сессии агента, когда задача неоднозначна.

get_untested_symbols — обратный инструмент к get_test_targets. Возвращает функции и методы, не достигаемые ни из одного тестового файла, ранжированные по fan-in. Ранжирование важно: непроверенная функция, вызываемая из 40 мест, важнее той, что вызывается из 2.

edit_file / write_file — запись файлов без предварительного чтения. edit_file делает точную замену строки в любом файле (исходном, markdown, конфиге, спеке) без предварительного Read. write_file создаёт или перезаписывает. Оба переиндексируют при записи. Устраняет цикл Read-before-Edit для файлов, которых нет в символьном графе.

Управление мультирепо-воркспейсами #

gortex init теперь привязывает конфиг репозитория к .gortex/ в корне репо. gortex workspace set/set-all массово штампует слаги workspace и project по всем отслеживаемым репозиториям — удобно при миграции существующего мультирепо на именованные воркспейсы.

Мульти-серверный реестр демона (gortex daemon server add/remove) позволяет одному демону маршрутизировать между локальными и удалёнными экземплярами Gortex. Локальный Unix-сокет для репозиториев на этой машине, удалённый HTTPS-сервер для общего облачного индекса — демон выбирает правильную цель для каждого запроса.

MCP-индексация теперь отправляет notifications/progress во время длительных операций (обход → парсинг → разрешение → семантическое обогащение → поисковый индекс → контракты → готово), так что хосты с поддержкой прогресс-баров показывают реальную информацию о стадии на больших репозиториях.

Rust wasm-bindgen и бриджинг Go-импортов #

Rust-файлы с #[wasm_bindgen] обнаруживаются и маршрутизируются через общий interop-обработчик, моделирующий JS↔Wasm-границу как контракт. Go-импорты теперь бриджуются к узлам контрактов dep::<module>, что означает: check_contracts может обнаружить Go-файл, импортирующий пакет, не объявленный как зависимость в go.mod.


Код: github.com/zzet/gortex

brew install zzet/tap/gortex   # macOS
gortex install                  # один раз на машину
gortex init                     # один раз на репозиторий (опционально)