Достоверность анализа
Два уровня анализа производят внешне одинаковый результат. Это ловушка, поэтому каждый адаптер объявляет, что он способен выдать, а руководство это раскрывает.
Проблема
Handbooks анализирует 18 языков двумя движками:
- Полный уровень (full) — написанный вручную адаптер для каждого языка, с разрешением вызовов по типам, унаследованными членами, отслеживанием состояния по атрибутам и диапазонами операторов.
- Универсальный уровень (generic) — один движок на основе конфигурации с декларативной спецификацией для каждого языка. Инвентаризация файлов и функций точна; отношения вызовов — по мере возможностей.
Оба производят одно и то же промежуточное представление. Ничто ниже по потоку не может различить их, глядя на узлы и рёбра.
В этом и ловушка. Читатель — и особенно агент — принял бы ребро вызова универсального уровня за факт питоновского качества и рассуждал бы на его основе соответственно.
Решение: объявить, записать, раскрыть
1. Каждый адаптер объявляет, что он способен выдать
interface AdapterCapabilities {
tier: 'full' | 'generic';
callTypes: readonly CallType[]; // which edge kinds it can actually produce
selfAttrs: boolean; // can it track self/this attribute reads and writes?
statementSpans: boolean; // can it report statement spans (resync precision)?
}Это поле обязательное, а не опциональное. Адаптеры может регистрировать кто угодно, и самодельный адаптер, не объявивший ничего, просто не попадает в метаданные графа — вместо того чтобы получить выдуманное за него заявление о достоверности.
2. Phase 1 записывает это для каждого языка
{
"metadata": {
"language": "multi",
"languages": {
"typescript": { "tier": "full", "selfAttrs": true, "statementSpans": true, "callTypes": ["..."] },
"kotlin": { "tier": "generic", "selfAttrs": false, "statementSpans": false, "callTypes": ["..."] }
}
}
}Для каждого языка, а не для графа в целом — многоязычный запуск смешивает уровни, и
единственная метка language: "multi" полностью скрыла бы это.
3. Руководство говорит об этом там, где формируется доверие
Когда присутствует хоть один язык универсального уровня, обзор получает одну строку сразу под системной прозой:
Достоверность анализа — отношения вызовов для Kotlin, Scala получены универсальным (управляемым конфигурацией) анализатором: они построены по мере возможностей и могут быть неполными. Инвентаризация файлов и структура этих языков точны.
И нигде вообще, когда все языки полного уровня, — так обычный случай остаётся
свободным от шума. То же раскрытие появляется в HTML-сайте, индексе-локаторе для агентов
и llms-full.txt.
Какой уровень у моего языка?
Полный уровень: Python, TypeScript (и JavaScript), Go, Rust, Java, C#, C/C++, Ruby, PHP, Swift, Dart, Solidity, Shell.
Универсальный уровень: Kotlin, Scala, Zig, Objective-C, OCaml.
Расширения и оговорки — в Поддержке языков.
Чего на самом деле стоит «по мере возможностей»
| Полный уровень | Универсальный уровень | |
|---|---|---|
| Инвентаризация файлов | точно | точно |
| Инвентаризация функций и методов | точно | точно |
| Диапазоны строк и сигнатуры | точно | точно |
| Прямые вызовы по имени | точно | в основном |
self.method() / this.method() | разрешается | часто |
self.attr.method() через известный тип | разрешается | нет |
param.method() через аннотацию типа | разрешается | нет |
| Унаследованные члены | разрешается | нет |
| Отслеживание состояния по атрибутам | да | нет |
| Диапазоны операторов (точность resync) | да | нет |
То, по чему вы маршрутизируетесь — где находится файл, какие функции он содержит, какие строки они занимают, — точно на обоих уровнях. Деградирует граф отношений, что влияет на качество группировки и подсказки о совместных изменениях, а не на адреса.
Две честные оговорки
Swift. Встроенная грамматика аварийно завершает процесс на V8 ≥ 13 — измерено:
фатально 5 раз из 5 на Node 24, нормально на Node 21, и уникально для этой одной
грамматики из девятнадцати. На таком рантайме адаптер отказывается на этапе discovery
и называет средство (node --liftoff-only), вместо того чтобы уронить весь ваш запуск.
Shell. Скрипт, содержащий оператор case, пропускается, потому что эта грамматика
бросает исключение — её внешний сканер импортирует символ, который зафиксированный
WASM-линкер не предоставляет. Поскольку case вездесущ, это большинство нетривиальных
скриптов (измерено на nvm: все 6 файлов, все 122 функции), так что считайте покрытие
shell частичным. Журнал сканирования называет причину, а каждый пропущенный скрипт отдельно попадает в
phase1/scan-coverage.json с reason: "unparsable" — этот пробел можно перечислить, а
не угадывать.
Оба случая сообщаются через логгер во время сканирования. Запустите с -v, чтобы их
увидеть.
Перевод языка на уровень выше
Язык универсального уровня — это декларативная спецификация, а не парсер — см.
Добавление языка. Повышение до полного уровня
означает реализацию LanguageAdapter напрямую и объявление честных возможностей.
Контракт адаптера намеренно мал.