Словарь между двумя спеками разбирался целиком и не значил ничего
Функтор FTS — единственная из семи конструкций поверхности, которая утверждает соответствие понятий двух разных файлов требований:
функтор «Заказ в счёт» из «Продажи» в «Биллинг»
использует «Продажи» из «./prodazhi.fts»
использует «Биллинг» из «./billing.fts»
объект Покупка отображается в «Счёт»
поле сумма отображается в поле «сумма без НДС»
Такой конструкции нет ни в одном другом формате требований, и она ровно та, без которой не собирается замысел: спека закрывает легаси-систему, бизнес просит фичу, новая спека обязана не противоречить старой — а сравнивать две спеки можно только зная, что чему соответствует. В одной «Покупка», в другой «Счёт».
Разбор строил из этих строк всё нужное. parse на образце flang/test/fixtures/fts-naslediye/скидки-в-подписки.fts даёт legacy[0].value с imports (две пары «категория → путь»), objects (пара «Заказ → Подписка» и два поля внутри) и morphisms. Не терялось ничего.
Читать этот узел было некому, и это снималось грепом, а не чтением:
- слово
importsне встречается вflang/src/types.mjsни разу. Пути на спеки не открывал никто.link.mjsих тоже не трогает: строкаиспользуетвнутри функтора уезжает вvalue.imports, а не в импорты модуля, и связывание про неё не знает; - слово
fieldsне встречается вcheckFunctors(types.mjs, строки 2186–2400) ни разу. Так это и записано в контракте (flang/cat/SPEC.md): «Полей перевода компилятор не видит… согласованность перевода с ними не проверяется ничем».
Улика прогоном. flang check на образце отвечал {"valid":true,"module":"Скидка в подписку","functions":[],"types":[],"diagnostics":[]} и кодом 0 — при том, что оба пути использует в этом файле ведут в каталог specs/, которого в дереве нет, а объекты «Заказ» и «Подписка» не объявлены нигде. Словарь, который можно написать на несуществующие слова, — не словарь, а пометка для читателя.
Что сделано. checkFunctorDictionary в flang/src/compat.mjs: обе категории обязаны быть привезены строкой использует, оба пути — читаться и разбираться, файл — объявлять ту самую категорию, каждый названный объект и каждое названное поле — существовать с обеих сторон, а типы полей — сходиться. Четыре своих кода: FLANG_FUNCTOR_SPEC_MISSING, FLANG_FUNCTOR_SPEC_NAME, FLANG_FUNCTOR_DICTIONARY, FLANG_FUNCTOR_FIELD_TYPE.
Изъятием. Три испорченных словаря лежат в flang/test/fixtures/fts-slovar/ и отличаются от целого одной строкой:
поле скидка отображается в поле надбавка— дваFLANG_FUNCTOR_DICTIONARY, по одному на сторону, и в каждом список имён, которые в спеке есть;поле сумма отображается в поле лояльный—FLANG_FUNCTOR_FIELD_TYPE: «Покупка.сумма» —number, «Счёт.лояльный» —flag;объект Заказ отображается в «Подписка»— дваFLANG_FUNCTOR_DICTIONARY, иchecked.objectsостаётся нулём: объект не сошёлся, значит про его поля не известно ничего.
Целый словарь из того же прогона — valid: true и {functors:1, objects:1, fields:2, unmapped:0}.
Чем ограничено, и это важнее списка сделанного.
- Полнота словаря по полям не объявляется бедой. Объект-источник вправе иметь поля, о которых словарь молчит; политики на этот счёт в контракте нет, и заводить её здесь значило бы решить за автора. Молчание при этом считается:
checked.unmapped. Ноль сравнений и «проверено» — разные вещи. ДеньгииЧислоне различаются. Обе поверхности FTS дают один и тот же тип языка, иsameTypeвtypes.mjsсмотрит на вид, а не на исходную строку. Развести их здесь значило бы завести второе равенство типов, расходящееся с языковым.- Проверка ещё не встроена в
flang check. Она вызывается своим тестом (flang/test/compat-slovar.test.mjs, 9 из 9) и требует чтения файла и разбора извне:compat.mjsне тянет ни одного узла платформы, и втащитьnode:fsради одного вызова значило бы сделать мост непригодным там, где файловой системы нет. Прогон это и предъявляет:flang checkна всех трёх испорченных словарях по-прежнему отвечаетvalid: trueи кодом 0. Встроить обязан тот, кто владеетflang/bin/flang.mjsиlink.mjs. - Противоречия между требованиями здесь не ищутся. Это следующий слой и другая работа. Доказано ровно то, что словарь, которым тот слой будет пользоваться, состоит из существующих слов.
Правило, которое из этого вынимается. Конструкция, которая разбирается в полный узел и не имеет ни одного читателя этого узла, выглядит работающей ровно до первого замера. Грепом по имени поля — imports, fields — это видно за минуту, и такой греп стоит делать раньше, чем читать код проверки.