check

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 14, 2026 License: AGPL-3.0 Imports: 21 Imported by: 0

Documentation

Overview

acceptance_edit_after_verdict.go — правка ОДОБРЕННОЙ приёмки после вердикта объявляется в самом документе.

Порт с монорепо (`internal/repohygiene/acceptanceeditafterverdict.go`, снят вынесением службы — `kacho#2597`). Изменилось: путь дома приёмок (был `services/iam/docs/engineering/acceptance`, здесь — `docs/engineering/acceptance` от корня СВОЕГО модуля) и обход git через `platformtree`/`gitenv` вместо внутреннего `repoRoot(t)` монорепо. Осталось дословно: имя функции гейта (`TestAcceptanceEditedAfterItsVerdictSaysSo`), сам разбор и текст находки.

Предмет

Вердикт есть утверждение о РЕВИЗИИ, которую прочитал проверяющий: правка её не переносит и не отзывает задним числом. Документ, чья строка состояния правлена раньше, чем сам файл, и не назвавший эту правку прямо, объявляет вердикт о ревизии, которую никто не читал.

Почему пара величин, а не одна

Признак — сравнение двух отметок: когда последний раз правилась СТРОКА СОСТОЯНИЯ и когда сам документ. Обе берутся в ЭПОХЕ: строковое сравнение дат в двух часовых поясах даёт неверный порядок.

acceptance_path_coordinate.go — гейт: ПУТЬ, названный приёмкой как ПРЕДИКАТ, резолвится в дереве службы либо называет свой ДОМ.

Сосед по классу — `acceptance_probe_coordinate.go`: там координата есть ИМЯ ПРОБЫ, здесь — ПУТЬ. Предмет один (утверждение, пережившее свой предмет), граница разбора — разная, и разница ниже названа целиком, потому что дважды она ИНВЕРТИРОВАНА и списать её на небрежность легко.

Предмет

Приёмка доказывает свои утверждения ПРЕДИКАТОМ — командой, которую читатель обязан прогнать сам: `git grep … -- <путь>`. Предикат, чей путь в дереве не существует, даёт пустоту НЕ ПОТОМУ, что находок нет, а потому, что читать было нечего. «Ноль находок» становится неотличимо от «ноль прочитанного», и читатель делает вывод О ДЕРЕВЕ по замеру, который ничего не измерял.

Это тот же класс, что у соседа, но он ТИШЕ. Мёртвое имя пробы обнаруживается первым же прогоном (`go test -run` отвечает «no tests to run»). Мёртвый путь не отвечает ничем: команда завершается успехом и печатает пустоту — ровно то, чего от неё и ждали, когда утверждение было «здесь чисто».

Замер, из которого гейт заведён (`kaname#71`, дерево на `bbd196ea`): путей, названных предикатом, — 52, из них не резолвилось **66 вхождений в 16 документах** по наивному предикату задачи и **192 в 24** по разбору, знающему путь-спецификацию в кавычках. Разница — не придирка: она и есть слепая зона наивного предиката, а слепая зона проверки не краснеет и не зеленеет.

ГРАНИЦА РАЗБОРА — названа явно, потому что путь стоит в тексте ТРОЯКО

Один и тот же путь встречается в приёмке в трёх видах, и лишь один из них — координата, за которой читатель идёт с командой:

`git grep -n 'X' -- internal/manifest`   — ПРЕДИКАТ: путь после `--`, СУДИТСЯ
`internal/manifest/roles.go:135`         — проза: описание места, НЕ судится
`git ls-files 'proto/kacho/cloud/iam/**'` — путь-спец БЕЗ `--`, НЕ судится

ПРОЗА ВНЕ СУЖДЕНИЯ, и это решение, а не недосмотр. Путь в прозе — описание, а не адрес для прогона; в корпусе приёмок службы таких вхождений ОДНОГО только монорепного корня 992 в 33 документах, и почти все они — исторические утверждения о дереве, каким оно было ДО выноса (`kacho#2598`). Судить их значило бы требовать переписать свидетельство о прошлом. Число прозаических вхождений тем не менее ПЕЧАТАЕТСЯ переписью: слепая зона, которую видно, остаток, а не дыра.

ПУТЬ-СПЕЦИФИКАЦИЯ БЕЗ `--` ВНЕ СУЖДЕНИЯ ПО ДРУГОЙ ПРИЧИНЕ, и она несущая: в форме `git ls-files <спец>` путь сплошь и рядом есть САМ ПРЕДМЕТ УТВЕРЖДЕНИЯ ОБ ОТСУТСТВИИ — «такого корня в дереве нет, → 0». Там нерезолвящийся путь не дефект, а ровно то, что доказывают, и находка на нём была бы ложной. Отличить «путь мёртв» от «путь назван мёртвым намеренно» можно лишь прочитав НАМЕРЕНИЕ соседней прозы, а этого гейт не умеет и обещать не вправе. Замер: в дереве таких вхождений 33, из них утверждением об отсутствии — 27. Число печатается.

ОГОРОЖЕННЫЙ БЛОК КОДА СУДИТСЯ — ИНВЕРСИЯ ОТНОСИТЕЛЬНО СОСЕДА

Сосед пропускает огороженные блоки целиком: имя пробы внутри команды — не координата, а часть предиката, и судить его значило бы краснеть на собственном объяснении документа.

Здесь наоборот: блок кода — ГЛАВНОЕ место жительства предиката. Приёмка выносит команду в блок именно тогда, когда хочет, чтобы её прогнали. Пропусти гейт огороженные блоки — и он потерял бы 48 вхождений из 192 (четверть), не сказав об этом ничем. Поэтому блок судится, а различение делает не забор, а ПОЗИЦИЯ ТОКЕНА: после `--` в строке, несущей `git grep` либо `git ls-files`.

ПОДСТАНОВОЧНЫЙ ЗНАК: судится ГЛУБОЧАЙШИЙ ПРЕДОК БЕЗ МЕТАСИМВОЛА

`internal/migrations/*.sql` резолвится, если есть КАТАЛОГ `internal/migrations`, а не если шаблону что-то соответствует. Различие несущее в обе стороны:

  • шаблон, которому сегодня не соответствует ничто, — ЗАКОННЫЙ вердикт («миграций с такой датой нет»), а не мёртвая координата;
  • каталог, которого нет, — мёртвая координата, даже когда шаблон выглядит правдоподобно.

Отсюда правило отсечения: берём часть до первого метасимвола и поднимаемся до ближайшего `/`. Наивное «часть до звёздочки» ошибается на шаблоне, чей метасимвол стоит ВНУТРИ имени файла (`internal/migrations/20260902*`): оно объявило бы мёртвым живой каталог. Класс пойман на себе при заведении гейта.

НАЗВАННЫЙ ДОМ: чужой репозиторий — вне суждения, но НЕ прощён

Форма ВЗЯТА у соседа (`владелец/репозиторий:путь`, необязательно `@<ревизия>`), а он взял её у `scripts/docs-gate/check-03-holding-claim-resolves.py` воркспейса. Отличие от соседа одно: там дом стоит у ИМЕНИ, здесь — у ПУТИ, потому что координата этого гейта и есть путь. Двоеточие не спутать с git-формой `<ревизия>:<путь>`: слева от него требуется слэш, которого у ревизии не бывает.

Чужой дом ВНЕ суждения по построению: чужого дерева рядом может не быть, а сеть в прогоне гейта запрещена. «Вне суждения» отличается от «прощено» тремя свойствами, и все три обязательны:

  1. чужая координата СЧИТАЕТСЯ, а её дома ПЕЧАТАЮТСЯ: дом, стоящий в корпусе один раз, тем самым виден — опечатка в имени репозитория не уходит молча;
  2. приставка, домом НЕ являющаяся (`kacho:internal/x`, `MOD-MF-21:internal/x`), — НАХОДКА. Иначе любой неразобранный префикс снимал бы путь с суждения, и приставка стала бы способом спрятать адрес, а не назвать дом;
  3. СТОРОЖА живут в гейте, а не здесь: ядро судит поданные значения, и для него всякий непустой дом чужой. Свой дом, названный чужим, ловит гейт.

ЧЕГО ЭТОТ ГЕЙТ НЕ ДЕЛАЕТ — сказано прямо

Он судит СУЩЕСТВОВАНИЕ пути, а НЕ истинность числа, стоящего рядом с предикатом. Путь, приведённый к дереву, делает предикат исполнимым; сойдётся ли его вывод с числом, которое приёмка назвала, — вопрос К ЧИСЛУ, и он закрывается кругом ревью, а не этой проверкой. Граница честная и она же неприятная: живой адрес с ложным содержимым хуже мёртвого, потому что не краснеет. Держателя у второй половины сегодня НЕТ, и завести его дороже: потребовался бы прогон каждого предиката приёмки на каждом прогоне гейта.

acceptance_probe_coordinate.go — гейт: имя пробы, названное приёмкой КООРДИНАТОЙ, резолвится функцией в дереве.

Порт с монорепо (`internal/repohygiene/acceptanceprobecoordinate.go`, снят вынесением службы — `kacho#2597`). До этой правки держатель (`TestAcceptanceProbeCoordinateResolves`) не существовал ни в одном файле, а восемь живых приёмок службы (`roles-come-as-data-not-migrations.md`, `model-block-prose-has-a-home.md`, `model-generated-from-manifest.md`, `classes-form-of-role-right.md`, `retire-tenant-condition-surface.md`, `system-role-segments-resolve.md`, `module-manifest-resources-roles-deprecated.md`, `module-manifest-roles-and-seed-grants.md`) продолжали называть его своим.

Предмет

Приёмка ссылается на пробу, чтобы читатель мог её открыть и прогнать. Проба переживает не всякую правку: её переименовывают, сводят с соседней, снимают вместе с предметом — и делают это в СВОЁМ изменении, которое чужой приёмки не касается. Тогда координата остаётся стоять, а функции за ней нет.

Класс — утверждение, пережившее свой предмет, и он опаснее обычной устаревшей строки: следующий идёт по названному адресу, не находит ничего и делает вывод О ДЕРЕВЕ, а не о документе.

Почему координатой считается ТОЛЬКО целый пролёт кода

Имя пробы встречается в приёмке в трёх видах, и лишь один из них — координата:

`TestFoo`                            — КООРДИНАТА: пролёт целиком есть имя
`go test -run '^TestFoo$' -count=1`  — предикат: имя стоит внутри команды
«проба TestFoo снята вместе с предметом» — проза разбора

Проверка по подстроке краснела бы на втором и третьем, то есть на СОБСТВЕННОМ объяснении документа. Поэтому документ читается РАЗОБРАННЫМ: огороженные блоки кода пропускаются целиком, а из строки берутся только пролёты `…`, чьё содержимое ЦЕЛИКОМ есть имя пробы.

Почему резолв по ПРЕФИКСУ, а не по равенству

Корпус называет пробу двумя законными формами: полным именем и ИДЕНТИФИКАТОРОМ СЦЕНАРИЯ (`TestIAMCT112`), которым отбирают семейство — `-run '^TestIAMCT112'`. Отсюда правило: координата резолвится, если ОБЪЯВЛЕННОЕ имя начинается с неё. Направление существенно: `TestFoo‹хвост›` → `TestFoo` этим правилом не прощается — объявленное короче координаты и её префиксом не является.

НАЗВАННЫЙ ДОМ: чужой репозиторий — вне суждения, но НЕ прощён

Служба вынесена из монорепо (`kacho#2598`), и приёмки уехали вместе с ней, а гейты дерева остались там, где судят своё дерево. Отсюда третья форма записи координаты:

`TestFoo`                              — координата ЭТОГО дерева, судится;
`PRO-Robotech/kacho:TestFoo`           — координата ЧУЖОГО дома;
`PRO-Robotech/kacho@d941344bd9:TestFoo` — чужой дом, связанный ревизией.

Форма ВЗЯТА, а не придумана здесь: `owner/name:` у координаты ввёл `PRO-Robotech/kacho-workspace` `scripts/docs-gate/check-03-holding-claim-resolves.py` по тому же поводу — вынос службы оставил его координаты нерезолвящимися в стволе продукта. Оттуда же довод в пользу двоеточия: спутать `owner/name:путь` с git-формой `<ревизия>:<путь>` нельзя, потому что слева требуется слэш, которого у ревизии не бывает. Отличие одно и вынужденное: там дом стоит у ПУТИ, здесь — у ИМЕНИ, потому что координата ЭТОГО гейта и есть имя.

Чужой дом ВНЕ суждения по построению: ни подтвердить, ни опровергнуть объявление функции в чужом репозитории этот гейт не может — дерева рядом нет, а сеть в прогоне гейта запрещена. Доктрина в дереве уже есть и здесь не заводится второй раз: `carried_coordinate_ledger.go` §«Кросс-репо координата — вне суждения ОБОИХ сторон».

РЕЗОЛВ В НАЗВАННОМ ДОМЕ ТЕПЕРЬ ДЕЛАЕТСЯ — `probe_home.go` плюс `JudgeHomes` у вызывающего. Ядро по-прежнему судит ЗНАЧЕНИЯ и чужих деревьев не читает: оно собирает координаты чужих домов в `ForeignCoordinates`, а резолвит их тот, у кого есть корень. Ниже — прежний разбор, объясняющий, почему ветвь нельзя было завести БЕЗ производителя входа; он остаётся верным и описывает, чем производитель стал.

ПРЕЖНИЙ ОСТАТОК (закрыт `kaname#44`): резолв в названном доме здесь НЕ делался, и это остаток с предметом, а не граница по незнанию: воркспейс его умеет (опознаёт дерево идентичностью `origin`, отвечает третьей категорией, когда дерева рядом нет), но в конвейере службы чужого дерева нет НИКОГДА — ветвь была бы вечно-пустой, то есть мёртвым стражем ровно того вида, который запрещает ban #16. Заводится вместе с резолвером дома и инъекцией на двух синтетических деревьях — `kaname#44`.

«Вне суждения» отличается от «прощено» ТРЕМЯ свойствами, и все три обязательны:

  1. чужая координата СЧИТАЕТСЯ, а её дома ПЕЧАТАЮТСЯ переписью. Дом, стоящий в корпусе один раз, тем самым виден — опечатка в имени репозитория не уходит молча. Связанные РЕВИЗИЕЙ считаются отдельно: они не проверяемы даже там, где дерево дома есть;
  2. приставка, домом НЕ являющаяся (`kacho:TestFoo`, `IAM-MV-04:TestFoo`), — НАХОДКА. Без этого любой не-разобранный префикс снимал бы координату с суждения, и приставка стала бы способом спрятать адрес, а не назвать дом;
  3. ДВА СТОРОЖА, и живут они в гейте (`acceptance_probe_coordinate_test.go`), а не здесь, потому что им нужен дом ЭТОГО дерева — ядро судит значения, и для него всякий непустой дом чужой. Первый отвергает корпус, где ВСЕ координаты объявлены чужими: судить нечего, и «находок ноль» означало бы «ноль прочитанного». Второй ловит СВОЙ дом, названный чужим (`PRO-Robotech/kaname:TestFoo`), — иначе всякая мёртвая координата закрывается припиской своего же имени репозитория. Дом дерева выводится из `go.mod` (`OwnHomeOfTree`), а не складывается литералом.

Замер перед введением формы: пролётов вида `<что-то>:<имя-пробы>` в корпусе приёмок — НОЛЬ в обе стороны (и разобранных домом, и не разобранных), то есть правило 2 не краснеет ни на одной существующей строке.

applier_never_deletes.go — разбор пакета применителя ролей на предмет удаления строки роли (приёмка `docs/engineering/acceptance/roles-come-as-data-not-migrations.md` §3.1, держатель Г3; сценарий MOD-RD-15).

Порт с монорепо (`internal/repohygiene/applierneverdeletes.go`, снят вынесением службы — `kacho#2597`). Осталось дословно: имя функции гейта (`TestMODRD15ApplierNeverDeletesARoleRow`), сам разбор (обе оси, оба образца) и текст находки. Изменилось: пакет-цель — `internal/apps/kaname/moduleroles` (в монорепо — `services/iam/internal/apps/kaname/moduleroles`), путь-константа без префикса `services/iam/`.

Предмет

Роль с выдачами удалить нельзя (`ON DELETE RESTRICT`) — применитель встал бы на первой же роли, которой кто-то пользуется. Форма отзыва роли выбрана решением: строка ПОМЕЧАЕТСЯ снятой, а не удаляется (`docs/engineering/architecture/role-withdrawal-is-a-mark.md`).

Что здесь считается находкой — ДВЕ оси, и первая сильнее

  1. порт применителя объявляет ОДНОЗНАЧНО удаляющий глагол НАД СТРОКОЙ РОЛИ (судит имена методов интерфейса: глагол + предмет глагола);
  2. в пакете стоит оператор `DELETE` над таблицей ролей строковым литералом узла разбора, а не подстрокой текста.

Чего разбор НЕ видит — названо, а не спрятано

Запрос, собранный из кусков в рантайме, и запрос, приехавший параметром — первое не встречается в дереве, второе ловит первая ось: чтобы позвать чужое удаление, порт обязан его объявить.

ascii_identifiers.go — шов гейта имён этого дерева к общему разбору фундамента.

Предмет

Ban #17 состоит из двух половин, и в этом дереве держалась ровно одна. Объявления конвейера судит `TestDeliveryCarriesItsOwnPipeline` (`internal/supplyhygiene`). Идентификаторы Go не судил НИКТО: держателем был гейт монорепо (`PRO-Robotech/kacho:TestIdentifiersAreASCII`), а после вынесения службы (`kacho#2597`, `kacho#2598`) он судит ЧУЖОЕ дерево — его зелёный о `PRO-Robotech/kaname` не говорит ничего. Шесть вхождений в приёмках службы продолжали называть его своим держателем. Предмет закрыт задачей #41.

Разбор переехал в фундамент — копии здесь больше нет

Почему имя обязано быть латинским, чем омоглиф опасен и почему это РАЗБОР, а не поиск по образцу, — сказано в github.com/PRO-Robotech/corelib/treehygiene, там же и сам разбор. Здесь это не пересказывается: два места об одном предмете расходятся молча, и цена копии измерена — разбор имён совпадал с близнецом платформы на 17 строках кода из 34 (#51, ban #20).

Что осталось СВОИМ

Обход и его КОРЕНЬ: фундамент разбирает ОДИН исходник и о деревьях не высказывается — судить чужое дерево значило бы краснеть на чужом. Обход по корню модуля службы, перепись и порог беспредметности живут у гейта, `ascii_identifiers_test.go`.

Своих правил у этого файла нет, и потому он — ШОВ, а не вторая реализация: гейт и его инъекция зовут одно имя, и связь с фундаментом объявлена в одном месте. Появится у службы своя часть разбора имён — её место здесь, и менять придётся один файл, а не три.

assertion_admission_calls.go — разбор обращений к базе, разложенных по функциям (приёмка F2, сценарий F2-28).

Порт с монорепо (`internal/repohygiene/assertionadmissioncalls.go`, снят вынесением службы — `kacho#2597`). Держатель этого гейта уже цитируется ПРОД-КОММЕНТАРИЕМ в дереве службы: `internal/repo/kaname/pg/client_assertion_replay_repo.go` — «Гейт TestAssertionAdmissionIsASingleDatabaseCall стережёт это число». Осталось дословно: имя функции гейта, сам разбор и текст находки. Изменилось: путь без префикса `services/iam/`.

Предмет

Число обращений к базе внутри одной функции. Допуск однократности обязан делать РОВНО ОДНО: «не предъявлялось ли уже» и «погасить» неделимы, и неделимыми их делает первичный ключ таблицы, а не аккуратность вызывающего. Пара «посмотреть — записать» проходит ВСЕ последовательные пробы: окна между чтением и записью при последовательном прогоне не существует.

Почему владелец соединения берётся из ОБЪЯВЛЕНИЯ ТИПА, а не из списка имён

Разбор читает объявления структур файла и берёт в носители соединения те поля, ЧЕЙ ТИП называет драйвер базы. Переименование поля исход не меняет, чужое одноимённое поле находкой не становится.

audit_payload_pii.go — ГЕЙТ КЛАССА: нагрузка записи журнала аудита не несёт личных данных (задача `kacho#2483`).

Норма платформы названа здесь ФАКТОМ, а не ссылкой на документ: личные данные конечного пользователя — почта, телефон, предъявляемый секрет — не пишутся в след ни на успехе, ни на отказе, а корреляция ведётся по неизменяемому идентификатору.

Предмет

Приёмник журнала аудита — собственный поток записей службы, и он кладёт ВСЕ поля нагрузки как есть: шага сокрытия нет ни одного. Значит всякий личный ключ, положенный в нагрузку, уезжает в поток, а срок хранения потока становится сроком хранения личных данных. Корреляция при этом личных полей НЕ требует: идентификатор субъекта (`user_id` / `resource_id`) в нагрузке уже есть, он неизменяем и остаётся правдой через год, тогда как почта и отображаемое имя изменяемы и правдой не остаются.

Почему ГЕЙТ, а не правка двух мест

Правка закрывает экземпляр; класс приходит не по одному. Мест построения нагрузки в дереве три с лишним десятка, они лежат в разных пакетах, и ни одно из них не видит остальных. Автор следующего, скопировав соседнее, внесёт личный ключ незамеченным: отказа нет, красного нет, наблюдаемо это только у получателя потока.

Перечень личных ключей объявлен ЗАКРЫТЫМ СПИСКОМ, и он не выдуман

Он взят у самого дерева: проба `set_blocked_test.go` уже утверждает отсутствие `email` / `display_name` / `displayName` / `external_id` в нагрузке пользовательского события — то есть решение о составе личных ключей дерево приняло раньше этого гейта, а гейт распространяет его с одного события на все. Сверх того перечень несёт ключи-секреты: та же нагрузка объявляет о себе «No secrets in payload», и это утверждение до сих пор держалось комментарием.

`external_id` попадает в перечень СОЗНАТЕЛЬНО, и это расходится с нормой платформы, называющей его не-личным идентификатором корреляции для журнала процесса. Расхождение разрешается ЕДИНИЦЕЙ НОСИТЕЛЯ: та норма — о СТРОКЕ ЖУРНАЛА процесса, которую читает оператор и которая живёт до ротации; здесь — о ЗАПИСИ ПОТОКА АУДИТА, которая живёт срок хранения потока и уезжает к внешнему получателю. Для второго носителя дерево выбрало строже, и выбрало до нас.

Чего перечень НЕ содержит и почему

Ключа `name` в нём нет, хотя проба пользовательского события требует его отсутствия. Причина — предмет: в нагрузке роли, группы и реестра `name` есть имя РЕСУРСА, а не человека, и оно там законно (пять мест дерева). Запрет по имени ключа, верный для одного вида события и неверный для пяти, гейтом дерева быть не может; держит его проба СВОЕГО события, где известно, чьё это имя.

Формы построения нагрузки — перечислены ВСЕ, и каждая доказана

Распознаватель, не знающий одной из форм, не даёт ни красного, ни зелёного — он МОЛЧИТ, и записанное в этой форме оказывается вне наблюдения, оставаясь на вид покрытым. Формы поэтому измерены по дереву, а не придуманы:

FormFieldLiteral    `Payload: map[string]any{…}` — литерал прямо в поле;
FormHelperDecl      `func …Payload(…) map[string]any { … }` — построитель,
                    чьи ключи живут у ОБЪЯВЛЕНИЯ, а не у вызова;
FormIndexAssign     `p["ключ"] = …` — ключ, добавленный ПОСЛЕ литерала;
                    литеральный разбор без него теряет условные ключи;
FormFieldIdent      `Payload: p`, где `p` собран выше в той же функции.

Поле `EventPayload` формой НЕ является и в счёт не идёт: это уже сериализованные байты у писателя, а не место построения. Разбор, судящий по подстроке `Payload:`, принял бы его за пятую форму — и судил бы место, где ключей нет вовсе.

Значение поля `Payload`, не сводящееся ни к одной форме, разбор объявляет НЕПРОЗРАЧНЫМ и печатает числом. Ноль непрозрачных — вердикт обхода, а не свойство записи: пока их ноль, «личных ключей нет» сказано обо всех местах.

Чем держится способность упасть

`audit_payload_pii_injection_test.go` — инъекция в обе стороны по КАЖДОЙ форме и по КАЖДОМУ объявленному ключу: дефект находится с координатой, законный близнец (тот же ключ в НЕ-нагрузочном литерале, идентификатор вместо личного поля) молчит.

authz_wrapper_outcome_lanes.go — булева ОБЁРТКА вопроса о правах не вызывается там, где у неё есть парная форма с исходом (задача #1045).

Порт с монорепо (`internal/repohygiene/authzwrapperoutcomelanes_test.go`, снят вынесением службы — `kacho#2597`). В кaname живёт как минимум одна такая пара: `authzguard.SubjectIsClusterAdmin` (bool) рядом с `SubjectIsClusterAdminE`/`SubjectIsClusterAdminPlainE` (bool, error) — то есть предмет ЖИВ, и гейт переносится. Изменилось: перечень «прод-корней» и путь модуля читаются из СВОЕГО дерева, а не из монорепо; имя гейта сохранено дословно.

Что ищется — СВОЙСТВО, и оно ВЫВОДИТСЯ ИЗ ДЕРЕВА

Перечня имён у этого гейта нет и быть не может: пары выводятся —

F  — экспортированная функция пакета, возвращающая РОВНО `bool`;
FE — функция ТОГО ЖЕ пакета с именем `F`+`E` либо `F`+`PlainE`,
     возвращающая `(bool, error)`.

Есть пара ⇒ автор пакета УЖЕ объявил, что у этого вопроса три исхода, а не два. Значит вызов булевой половины из ЧУЖОГО пакета — выбор, а не необходимость, и выбран он в пользу формы, из которой «хранилище не ответило» достать нельзя.

Граница названа честно

Вызовы ВНУТРИ пакета, объявившего пару, под гейт не подпадают: там булева половина и есть тело обёртки. Узнавание идёт по ИМЕНИ ИМПОРТА файла, а не по типам.

basic_credential_proof_run.go — доказательство формы базового удостоверения обязано ПРОИЗВОДИТЬСЯ ПРОГОНОМ, а не просто лежать в дереве (`PRO-Robotech/kacho#1253`).

Порт с монорепо (`internal/repohygiene/basiccredentialproofrun_test.go`, снят вынесением службы — `kacho#2597`). Осталось дословно: имя функции гейта, сам разбор `run:`-тел workflow и текст находки. Изменилось: пути без префикса `services/iam/`, конвейер — `.github/workflows/` СВОЕГО репозитория.

Предмет

Во всём сквозном прогоне не было НИ ОДНОГО зелёного утверждения, читающего секрет базового удостоверения из УСПЕШНОГО ответа. Проверка, которую никто не зовёт, ничего не производит: её зелёное существует только в чужой голове.

Читается ИСПОЛНЯЕМАЯ часть, а не текст

YAML разбирается, берутся тела `run:`, и из них выбрасываются строки оболочечных комментариев. Гейт по подстроке краснел бы на собственном объяснении и зеленел бы на шаге, откуда вызов сняли, а комментарий оставили.

build_stamp_word.go — разбор объявления строковой константы синтаксическим деревом, а не текстом.

Предмет

Слово «сборка штамп не проставила» стоит в прозе (шапках, документации) не реже, чем в объявлении. Поиск по подстроке нашёл бы собственное объяснение и остался бы зелёным при разошедшихся объявлениях — узел объявления константы судится вместо строки файла ровно по этой причине.

carried_coordinate_ledger.go — разбор ведомости координат, переносимых до снятия внешнего провайдера аутентификации клиента (приёмка F2, сценарий F2-46, §9.4).

Порт с монорепо (`internal/repohygiene/carriedcoordinateledger.go`, снят вынесением службы — `kacho#2597`). Осталось дословно: имя функции гейта (`TestCarriedCoordinateLedgerExpiresOnItsOwn`), сам разбор и словарь исходов. Изменилось: путь ведомости без префикса `services/iam/` (`docs/engineering/architecture/client-assertion-carried-over-coordinates.md`) и область зеркальной колонки — раньше сужалась до `services/iam/` внутри монорепо, теперь это ВЕСЬ репозиторий службы (у неё нет больше соседей по дереву). Ведомость службы, будучи скопирована целиком, несла координаты со старым префиксом `services/iam/` — они не резолвились НИ ОДНА (кросс-репо staleness, а не намеренное послабление); исправлено тем же изменением, которым перенесён гейт.

Предмет

Фаза F2 завела принимающую сторону и ничего не сносит. У каждой координаты, дожившей до снятия внешнего провайдера, обязан быть назван исход из закрытого словаря; четвёртого — «осталось как есть, потому что не заметили» — не существует. У исхода «оставлено» обязан быть ПРЕДИКАТ СНЯТИЯ.

Гейт двусторонний

  • ПОЛНОТА: координата, живущая в дереве и не названная ведомостью, — находка;
  • САМОИСТЕЧЕНИЕ: запись, чьей координаты в дереве больше нет, — находка.

Кросс-репо координата — вне суждения ОБОИХ сторон

Ведомость несёт координаты не только своего репозитория (напр. `services/registry/...` — сервис реестра остался в монорепо продукта, а не уехал со службой доступа). Такую координату этот гейт не проверяет НИ ПОЛНОТОЙ, ни САМОИСТЕЧЕНИЕМ: он не может ни подтвердить, ни опровергнуть существование файла в ЧУЖОМ репозитории. «В скоупе» решает первый сегмент пути — совпадает с одним из ФАКТИЧЕСКИ отслеживаемых верхних каталогов своего дерева.

catalog_check_wiring.go — сверка каталога прав с копией края обязана быть ЗВАНОЙ конвейером, а не просто существующей целью Makefile.

ПРЕДМЕТ У ГЕЙТА ФОРМА-ПРОВЕРКА, А НЕ ФОРМА-СИНХРОНИЗАЦИЯ (kaname#15)

Портированная редакция требовала вызова `sync-permission-catalog` — и была НЕИСПОЛНИМА by construction: эта цель ПИШЕТ файл. Задание, правящее дерево, вердикта о дереве не даёт: «копии совпали» после собственного `cp` истинно всегда, а рабочая копия ранера уезжает от коммита. Поэтому решение записано в самом рецепте, а гейт судит его: конвейер зовёт `check-permission-catalog` (ничего не пишет, годна обеим посадкам) и НЕ зовёт пишущую форму, которая объявлена ручной операцией выпуска.

Отсюда и переименование пробы: портированное имя было `TestCatalogSyncTargetIsCalledByThePipeline`, и после смены предмета оно утверждало бы неверное — цель синхронизации конвейером не звана НАМЕРЕННО.

Вторая половина того же решения — ОТКУДА БЕРЁТСЯ КОПИЯ КРАЯ. Замер, которого у портированной редакции не было: копия края приезжает в самостоятельный клон МОДУЛЕМ-ПИНОМ платформы (`go.mod`), поэтому сверка исполнима и здесь, а не только в полном чекауте монорепо. Предикат и его граница — в рецепте, у самой цели.

Порт с монорепо (`internal/repohygiene/catalogcheckwiring_test.go`, снят вынесением службы — `kacho#2597` с заявлением «предмет уехал вместе со службой»). Заявление НЕВЕРНО для kaname: своя половина цепочки уехала СЮДА — цель `sync-permission-catalog` объявлена в корневом Makefile службы (`GATEWAY_CATALOG`/`IAM_CATALOG_EMBED`), и её собственный комментарий говорит: «Копия каталога у iam ОБЯЗАНА побайтово совпадать с копией шлюза». Предмет, которым монорепошный гейт стерёг ПРОВЯЗКУ, здесь тот же самый, только половина цепочки живёт по обе стороны границы репозитория.

Здесь СУЖЕННАЯ форма монорепошного гейта: он спрашивал достижимость через ОБЩИЙ анализатор рецептов Makefile (`gatetargetwiring.go`, там же судят гейты `services/*`), которого в этом репозитории нет и заводить его ради двух целей с нулём зависимых — избыточно (ни у `check-permission-catalog`, ни у `sync-permission-catalog` сегодня НЕТ ни одной цели-потребителя внутри Makefile: обе стоят сами по себе, реаситься до них нечему). Поэтому проверяется прямая достижимость: зовёт ли ХОТЬ ОДИН шаг конвейера имя цели напрямую (`make check-permission-catalog` либо `make -C … <цель>`). Появится цель-потребитель — предикат обязан расшириться до реситься-графа, как в монорепо; это отдельное изменение, а не молчаливое сужение.

Чем этот гейт НЕ является

Он не сверяет копии побайтово — это отдельный предмет, и живёт он внутри рецепта `check-permission-catalog`. Предмет ЭТОГО гейта — ПРОВЯЗКА: существует ли у сверки вызывающий среди того, что исполняется САМО, и не зовёт ли конвейер пишущую форму вместо неё.

catalog_writer_lock.go — всякий прод-писатель строк `kaname.catalog_*` берёт глобальный транзакционный замок каталога (приёмка `docs/engineering/acceptance/plan-confirms-what-apply-withdraws.md` §7, объём О11, держатель Г1; kacho#1034).

Порт с монорепо (`internal/repohygiene/catalogwriterlock.go`, снят вынесением службы — `kacho#2597` с заявлением «обход служб жив, но исполняемых операторов записи в этот каталог ноль». Заявление было верно ТОЛЬКО для монорепо (там дерево служб доступа исчезло) — приёмка сама называет отсутствие держателя пунктом Н5 и требует его. Механизм в дереве службы ЖИВ дословно: `internal/repo/kaname/pg/catalog_writer.go` несёт `CatalogLockKey`/`LockCatalog` (`pg_advisory_xact_lock`) и три `UpsertModule`/`UpsertResource`/`UpsertVerb` на том же получателе (`catalogWriter`) — единица суждения по-прежнему сходится. Осталось дословно: весь алгоритм (регулярки, разбор, единица суждения, тексты находок). Изменилось: путь-константа без префикса `services/iam/`, обход — от корня СВОЕГО репозитория целиком (предмет запрета — «ВСЯКИЙ прод-писатель», не только сегодняшний).

Предмет

Подтверждение применения (отпечаток состояния модуля) есть CAS ТОЛЬКО потому, что между чтением отпечатка и записью строк не может встать второй писатель. Обеспечивает это не сравнение, а `pg_advisory_xact_lock`, взятый В ТЕЛЕ КАКОГО-ЛИБО МЕТОДА писателя (гейт не проверяет порядок — это держит интеграционная проба, не разбор).

Единица суждения — ТИП (получатель метода), а не файл и не пакет-вызывающий

Замок и запись могут лежать в РАЗНЫХ методах ОДНОГО получателя в ОДНОМ пакете (как здесь: `LockCatalog` и `UpsertModule` — оба методы `catalogWriter` в `internal/repo/kaname/pg`) — тогда они СХОДЯТСЯ в одну единицу суждения и гейт молчит. Замок, взятый ЧУЖИМ пакетом (например, вызывающим use-case, держащим порт `CatalogWriter`), этот гейт НЕ видит — он не о том, кто ЗОВЁТ замок, а о том, что писатель СПОСОБЕН его взять (несёт метод, который это делает).

census_fixture_producer.go — проба, которая пересчитывает ВСЕ строки таблицы, не вправе наполнять её сама в обход производителя.

Порт с монорепо (`internal/repohygiene/censusfixtureproducer_test.go`, снят вынесением службы — `kacho#2597`). Гейт уже цитируется ШЕСТЬЮ местами в дереве службы (прод-код `internal/repo/kaname/pg/scalegrid/{census,seed}.go` и пробы `relverdict`/`parentedge`) как «гейт дерева `TestCensusFixturesSeedThroughTheProducer`» — предмет жив, и цитаты уже ждут держателя. Осталось дословно: имя функции гейта, разбор и текст находки. Изменилось: пакет-производитель узнаётся ОДНОЙ величиной (каталог = хвост импорта: у самостоятельного модуля службы расхождения, из-за которого монорепо держало ДВЕ константы, больше нет), обход — от корня СВОЕГО модуля, без сегмента `services/iam`.

Предмет

Утверждение вида «у каждой строки зеркала есть цепь предков» — квантор по всему множеству. Если множество наполнила сама проба прямой записью в таблицу, утверждается свойство ФИКСТУРЫ: она положила ровно то, что потом пересчитала. Такая проба остаётся зелёной, даже если производитель перестал писать цепь ЦЕЛИКОМ.

Единица суждения — ПАКЕТ, а не файл

В Go все `_test.go` каталога с одним именем пакета собираются в один бинарь и делят помощников. Проба, сеющая через помощника из соседнего файла, сеет через производителя ровно так же.

Разбор идёт по СТРОКОВЫМ ЛИТЕРАЛАМ, а не по тексту файла

Текстовый поиск нашёл бы обе примеет и в комментарии, объясняющем эту же дисциплину (в том числе в шапке самой пробы полноты).

client_expiry_immutable.go — разбор операторов правки, разложенных по столбцам (приёмка F2, §9.4, решение §2.10).

Порт с монорепо (`internal/repohygiene/clientexpiryimmutable.go`, снят вынесением службы — `kacho#2597` с заявлением «снято вместе с предметом: таблицы user_oauth_clients в применённых миграциях дерева нет». Заявление было верно ТОЛЬКО для монорепо (там дерево служб доступа исчезло целиком) — в дереве службы обе таблицы объявлены (сегодня — в консолидированной `internal/migrations/0001_initial.sql`), с колонкой `expires_at`. Осталось дословно: имя функции гейта, сам разбор и текст находки. Изменилось: пути без префикса `services/iam/`.

Предмет

Срок клиента неизменяем после создания. На этой предпосылке стоит структурная гарантия: срок выданного токена не превышает остатка срока клиента, и проверять это на пути запроса не нужно ровно потому, что срок не двигается. Сдвинь его — и гарантия держится ничем.

Что здесь считается ПРАВКОЙ СТОЛБЦА

UPDATE t SET expires_at = $2 WHERE id = $1   ← правка: столбец назван в SET
INSERT INTO t (…, expires_at) VALUES (…)     ← СОЗДАНИЕ: срок назначается
SELECT expires_at FROM t WHERE id = $1       ← чтение

Чего разбор НЕ видит — названо, а не спрятано

  1. оператор, собранный из частей во время выполнения;
  2. правка через функцию базы или триггер, а не оператором `UPDATE`;
  3. `UPDATE` без имени таблицы в том же литерале.

client_truth_exclusion_form.go — извлечение для гейта «форма взаимоисключения, НАЗВАННАЯ оператору, есть та, которой оно держится» (задача #17, порт-ПОЛОВИНА семейства `clienttruth_kaname_exclusion_form` с монорепо `internal/repohygiene/clienttruth_kaname_exclusion_form.go`, снятого выносом службы — `kacho#2597`).

───────────────────────────────────────────────────────────────────────────── ПРЕДМЕТ

Назваться на публичном слушателе Kaname можно двумя способами: предъявить удостоверение самому либо получить личность от нашего края. Способы взаимоисключающи, и держится это ПОСТРОЕНИЕМ, а не проверкой.

Держалось оно не всегда так. Прежняя редакция требовала ОТВЕРГАТЬ запрос, несущий обе формы, — и эта проверка отвергала бы каждый запрос, проксированный нашим же краем, потому что сочетание производил он сам. Ветвь отказа снята вместе со своим предметом; страница оператора об этом узнать не могла — она не собирается и ничего не импортирует.

───────────────────────────────────────────────────────────────────────────── ДВА УТВЕРЖДЕНИЯ, И ВТОРОЕ ПОЛОЖИТЕЛЬНОЕ

A. отказ, ОБЕЩАННЫЙ страницей, обязан иметь производителя в не-тестовом коде
   читателя. Обещание без производителя — утверждение, пережившее свой
   предмет: оператор ждёт отказа, которого служба не делает;
B. пока построение живо, страница обязана НАЗЫВАТЬ его.

Второе — положительное, и это не стилистика. Отрицание («страница не говорит такого-то слова») ЗАМОЛКАЕТ при первой же переформулировке: вход, на котором оно находит нарушение, перестаёт быть представимым, а ветвь остаётся в коде и вердикт остаётся зелёным — а отличить это от исправной работы нельзя ничем, потому что обе стороны печатают ноль находок. Утверждение B умолкнуть не может: оно краснеет ровно тогда, когда объяснение исчезает.

───────────────────────────────────────────────────────────────────────────── ЧТО РАЗРЕЗ СДЕЛАЛ С УТВЕРЖДЕНИЕМ B — И ПОЧЕМУ ЭТО НЕ ОСЛАБЛЕНИЕ

Взаимоисключение держат ДВА построения, по одному на сторону провода, и разрез развёл их по репозиториям:

СНЯТИЕ у края   — край снимает арендаторское удостоверение перед пересылкой
                  за себя. Замер этого дерева: `git ls-files gateway | wc -l`
                  → 0; `git grep -l StripPresentedCredential` → 0. Живёт в
                  `PRO-Robotech/kacho`.
ОБЁРТКА у нас   — читатель предъявленного удостоверения НАКРЫВАЕТ пару
                  звеньев переданной личности и решает по её вердикту, а не
                  становится с ней в цепочку. Живёт ЗДЕСЬ.

Предок брал премисой первое, потому что оба лежали в одном дереве. Здесь премисой берётся ВТОРОЕ — наша половина построения, и она судится тем же разбором, что и всё остальное.

Это НЕ ослабление предмета, а смена ОПЕРАНДА ПРЕМИСЫ: утверждение B осталось прежним («построение живо ⇒ страница его называет»), сменилось то, чем доказывается «живо». Судить снятие у края отсюда было бы можно только чтением чужого репозитория с диска — тогда вердикт стал бы свойством того, что случайно лежит в кеше машины прогона, а не свойством коммита ни одного из двух деревьев.

───────────────────────────────────────────────────────────────────────────── ПОЧЕМУ ОБЁРТКА — ИМЕННО ПОСТРОЕНИЕ, А НЕ ПРОВЯЗКА

Носитель личности платформы устроен так, что снятие имеет приоритет над любым последующим назначением. Читатель, поставленный ПОСЛЕ пары, назначил бы вызывающего, и назначение молча не доехало бы до обработчика. Поэтому читатель прогоняет пару САМ и решает по её вердикту — решение о том, КТО звонит, принимается в одном месте, и сочетания двух форм не возникает by construction.

Разомкни обёртку — и взаимоисключение перестаёт держаться построением на нашей стороне, то есть страница начинает объяснять механизм, которого нет. Ровно это утверждение B и стережёт.

───────────────────────────────────────────────────────────────────────────── РАСПОЗНАВАТЕЛИ — ЧЕМ СУДЯТ, И ПОЧЕМУ НЕ ПОДСТРОКОЙ ПО ФАЙЛУ

Сторона ДЕРЕВА судится РАЗБОРОМ, а не текстом, и это несущее: файл читателя несёт НАДГРОБИЕ снятой ветви — связный абзац по-русски о том самом сочетании форм, — и проверка по подстроке объявила бы живым ровно то, что снято: предикат, судящий СЛОВО вместо УЗЛА, находит собственное объяснение. Поэтому считаются УЗЛЫ-ВЫЗОВЫ и литеральные аргументы, а комментарии не читаются вовсе.

Сообщение отказа собирают конкатенацией (`refuse("… " + err.Error())`), поэтому разбор аргументов идёт по дереву выражения: читатель одиночного литерала такое сообщение НЕ УВИДЕЛ БЫ — то есть дал бы молчание вместо вердикта.

Сторона СТРАНИЦЫ судится по абзацу — прозы иначе не судить, и это сказано прямо, а не спрятано. Смягчает три вещи:

  • корень предмета один и это ИМЯ предмета (`взаимоисключ`), а не оборот речи: переформулировать объяснение, не назвав предмета, значит перестать его объяснять, и это ловит утверждение B;
  • регистр снимается. Страница пишет `ОБЕ` прописными, и предикат, читающий написанное, промолчал бы на живом производителе;
  • вердикт выносится ПОАБЗАЦНО. Соседний абзац той же страницы законно говорит об отказе — о единообразии его текста, — и файл целиком читать нельзя: отказ соседа зачёлся бы обещанием предмета.

client_truth_module_set.go — извлечение для гейта «перечень модулей платформы, названный клиентской поверхностью, ПОЛОН» (задача #17, порт семейства `clienttruth_iam_moduleset` с монорепо `internal/repohygiene/clienttruth_iam_moduleset.go`, снятого выносом службы — `kacho#2597`).

───────────────────────────────────────────────────────────────────────────── ПРЕДМЕТ — и почему цена неполноты в БЕЗОПАСНОСТИ, а не в удобстве

Набор модулей закрыт, и его единственный источник — приставки ключей закрытой таблицы типов объекта (`objectTypes` пакета `internal/authzmap`). Модуль — то, чем клиент выражает грант (`Rule.module`).

Перечень, назвавший МЕНЬШЕ, чем принимает сервер, читается клиентом как «тонко выдать доступ к недостающему домену НЕЛЬЗЯ», а единственный документированный выход при таком чтении — системная роль на весь уровень, то есть заведомое расширение доступа. Клиент платит доступом за нашу опечатку в прозе.

Замер, на котором семейство заведено (kacho#1627): сервер принимал ШЕСТЬ модулей, а называли ЧЕТЫРЕ и справочная страница ролей, и комментарий поля контракта; шапка функции членства рядом называла ПЯТЬ. Разошлись не документ с кодом, а ТРИ места об одном предмете, из которых верно было ни одно.

───────────────────────────────────────────────────────────────────────────── ЧТО ИЗМЕНИЛ ПЕРЕЕЗД, А ЧТО НЕТ

Предмет НЕ изменился. Изменились координаты: приставка `services/iam/` ушла вместе с монорепо, поверхности стали `docs/content` и `proto/kaname/cloud/iam` (копия контракта приехала сюда с `kaname#49`), объявление набора — `internal/authzmap`. ОБА операнда лежат в этом дереве, поэтому семейство судится здесь целиком, а не половиной.

Прежняя посылка задачи #17 называла семейство кросс-репозиторным. Она опровергнута замером операндов: пакет объявления — 61 файл, поверхности — 68.

───────────────────────────────────────────────────────────────────────────── НАБОР ВЫВОДИТСЯ РАЗБОРОМ, А НЕ ЧТЕНИЕМ ТЕКСТА

Считаются узлы-ключи составного литерала. Имена модулей стоят и в комментариях рядом с объявлением — и в том самом абзаце, который объясняет выбор написания ключа, — поэтому предикат по подстроке краснел бы на собственном объяснении таблицы: судящий СЛОВО вместо УЗЛА находит сам себя.

Объявление разрешается по ПАКЕТУ, а не по файлу. В монорепо оно переезжало между файлами дважды (`fga_types.go` → `tables_gen.go`), и оба раза привязка к имени файла давала не находку, а «анализатор не отработал» — третью категорию, поданную как красное. Пакет и есть единица области видимости Go: package-level имя в нём ровно одно by construction, и перенос между файлами о нём ничего не меняет.

Приставка берётся до ПЕРВОЙ точки — то же разбиение, каким его делает `authzmap.SplitObjectType`. Ключ без точки модуля НЕ ДАЁТ и себя целиком не отдаёт: он не «модуль без ресурса», а ключ неверной формы, и записать его в набор значило бы объявить модулем то, чем таблица его не называет.

───────────────────────────────────────────────────────────────────────────── ЧТО СЧИТАЕТСЯ ПЕРЕЧНЕМ — И ЧЕГО ГЕЙТ НЕ СУДИТ, НАЗВАНО ЧИСЛОМ

Перечень — имена модулей в КОД-ФОРМАТИРОВАНИИ (`имя` либо <code>имя</code>), соединённые косой чертой, ТРИ и более подряд. Каждый такой перечень обязан назвать набор целиком.

  1. СПАН ИЗ ДВУХ ИМЁН перечнем не считается — это законная пара («`vpc`/`compute` остаются label-selectable»). Порог в три оставлен потому, что гейт, у которого находки ложные, отключают первым. Сколько таких пар встречено — печатает перепись, а не утверждает эта шапка: прежняя редакция абзаца в монорепо называла четыре, и гейт опроверг её на первом же прогоне. Способность молчать на паре доказана инъекцией.
  2. ПРОЗА без код-форматирования не судится: «модули iam, vpc и compute» распознавателю не видны. Расширение на голый текст не замерялось и потому не вводится — оно находило бы имена модулей в любом предложении, где они соседствуют законно.
  3. ПОРЯДОК не судится — только состав.

contract_names_live_machinery.go — МАШИНЕРИЯ, НАЗВАННАЯ КОММЕНТАРИЕМ КОНТРАКТА, ОБЯЗАНА СУЩЕСТВОВАТЬ В ДЕРЕВЕ.

───────────────────────────────────────────────────────────────────────────── ПРЕДМЕТ

Комментарий публичного контракта читает ИНТЕГРАТОР — у него нет ни нашей истории, ни возможности перемерить. Обещание механизма, снятого миграцией, для него неотличимо от действующего.

Класс тот же, что у поля запроса, которое принимают и не читают: возможность ОБЪЯВЛЕНА, и за неё никто не отвечает. Исходов у него три — реализовать · отвергать явно · снять с контракта; «оставить как есть» исходом не является, потому что вызывающий узнаёт о несделанном только по последствиям и только в своей отладке.

Наблюдалось (kacho#2486): `rpc ForceLogout` обещал строку в очереди федеративного уведомления и рассылку по каналу, обновляющую кэш отзыва на крае. Очередь снята миграцией, канал снят вместе со своим триггером, а рядом стояла ссылка на файл контракта, которого в модуле нет. Три утверждения пережили свой предмет и продолжали читаться как действующие.

───────────────────────────────────────────────────────────────────────────── СУЖЕНИЕ ИДЁТ ПО МАРКЕРУ, КОТОРЫЙ СТАВИТ САМ КОММЕНТАРИЙ

Голый предикат «слово в обратных кавычках обязано резолвиться» негоден, и это ИЗМЕРЕНО, а не предположено: на дереве службы он даёт 239 токенов, из которых 159 не резолвятся ни в таблицу, ни в канал, ни в колонку — 66 % ложных находок. Предикат с такой долей не читают, а гейт, который не читают, не держит ничего.

Поэтому заявлением считается не токен, а токен ВМЕСТЕ С МАРКЕРОМ, который комментарий ставит сам:

`<имя>_outbox`        суффикс очереди — заявлена ТАБЛИЦА
`<имя>` table         слово сразу после — заявлена ТАБЛИЦА
`<имя>` channel       слово сразу после — заявлен КАНАЛ
NOTIFY … on `<имя>`   оборот перед    — заявлен КАНАЛ

Замер того же дерева этим предикатом ДО правки: заявлений 9, резолвятся 6 (`audit_outbox`, `fga_outbox`, `session_revocations`), не резолвятся 3 — ровно те три, ради которых гейт заведён. Ложных находок ноль.

ПОСЛЕ правки заявлений о ТАБЛИЦЕ десять и все резолвятся, а заявлений о КАНАЛЕ НОЛЬ: оба, что были, называли снятый канал и сняты вместе с ним. Ноль здесь не прячется — перепись печатает виды РАЗДЕЛЬНО, поэтому «про каналы никто не писал» отличимо от «про каналы не спрашивали». Предмет у этой ветви производим в любой момент: она оживёт от первой же строки, назвавшей канал.

───────────────────────────────────────────────────────────────────────────── ЧТО СЧИТАЕТСЯ ИСТИНОЙ

Схему называет ПРИМЕНЁННОЕ дерево миграций, а не намерение: таблицы — `CREATE TABLE`, каналы — `pg_notify`. Обе половины читаются из одного источника, поэтому снятие механизма миграцией немедленно делает заявление о нём находкой, и держать запись ради зелёного негде.

───────────────────────────────────────────────────────────────────────────── ВТОРАЯ ОСЬ: ССЫЛКА НА СОСЕДНИЙ КОНТРАКТ

Комментарий, называющий `<имя>.proto` БЕЗ каталога, называет контракт ЭТОГО модуля — так в дереве и пишут (`internal_iam_service.proto`, `user.proto`). Такое имя обязано резолвиться.

Ссылка С КАТАЛОГОМ (`kacho/cloud/validation.proto`) под ось НЕ подпадает, и это решение, а не пропуск: у платформы свой репозиторий, её файла в этом модуле нет by construction, и утверждение о чужом дереве предикатом ЭТОГО дерева не судится. Замер: таких ссылок 2, обе законны; включив их, гейт начал бы с двух ложных находок и потребовал бы ведомости прощений — то есть исключения, выданного вперёд.

deferred_work.go — СВОЯ часть гейта отложенной работы: корень обхода и виды вычитания. Разбор общий и живёт в фундаменте.

Предмет

Запреты «никакого тех-долга» и «всегда production-grade, НИКОГДА MVP» стоят в корпусе правил с самого начала. В ЭТОМ дереве их не держало ничего: держателем был гейт монорепо (`PRO-Robotech/kacho:TestNoDeferredWorkInTheTree`), а после вынесения службы (`kacho#2597`, `kacho#2598`) он судит ЧУЖОЕ дерево — его зелёный о `PRO-Robotech/kaname` не говорит ничего. Четыре приёмки службы продолжали называть его своим держателем. Предмет закрыт задачей #40.

Разбор переехал в фундамент — копии здесь больше нет

Словарь форм, образец, отсев по затравке, граница употребления и упоминания, обход и перепись живут в github.com/PRO-Robotech/corelib/treehygiene и приезжают сюда ПИНОМ версии. Здесь они не пересказываются — пересказ и есть то второе место об одном предмете, ради снятия которого переезд и сделан.

Цена копии была измерена, а не предположена (#51): разбор отложенной работы совпадал с близнецом платформы на 99 строках кода из 186, разбор имён — на 17 из 34, а словарь форм совпадал по составу ТОЧНО. Совпадение содержимого нарушением не смягчалось, а доказывало его: держателя у одинаковости не было ни одного, и расхождение наступило бы молча — заведут в одном дереве тринадцатую форму, в другом её не будет, и написанное в ней окажется не находкой и не чистотой, а НЕВИДИМОСТЬЮ. Ban #20 корпуса правил говорит это прямо: файл, чей владелец — другой репозиторий, в этом дереве не лежит; нужен предмет — берут пином, не нужен — файла нет.

Что осталось СВОИМ — и почему именно это

Ровно две вещи, и обе суть утверждения об ЭТОМ дереве, а не об общем разборе:

  • КОРЕНЬ ОБХОДА. Его даёт гейт, и это корень МОДУЛЯ службы: судить дерево платформы отсюда значило бы краснеть на чужом, а в самостоятельном клоне его нет вовсе;
  • ВИДЫ ВЫЧИТАНИЯ (treehygiene.DeferralSkip). Перечень вычитаемого есть утверждение о составе конкретного дерева, и предмет каждого вида измерен ЗДЕСЬ. Готовых видов фундамент не раздаёт намеренно: раздавая их, он утверждал бы о чужом дереве то, чего не измерял, и предикат «вид без предмета» обессмыслился бы.

Что СНЯТО вместе с переездом — и чем свойство держится теперь

Прежняя редакция несла отдельный вычет имени функции стандартной библиотеки: вызова через точку, синтаксически похожего на обращение к читателю кода. Ветвь НЕ перенесена, потому что она недостижима — класс границы в самом образце фундамента уже отличает вызов через точку от обращения, и инъекция фундамента это измерила: с отключённым вычетом вердикт суиты не изменился ни на одной пробе.

Свойство при этом не потеряно и держится с ОБЕИХ сторон шва: TestDeferralGateStaysSilentOnStdlibContextTODO — здесь, на кроне этого дерева; TestDottedCallIsNotADeferral — в фундаменте, на самом образце. Ослабят класс границы — покраснеют обе.

derived_id_single_source.go — разбор объявлений деривации детерминированного идентификатора (приёмка `docs/engineering/acceptance/roles-come-as-data-not-migrations.md` §3.3; приёмка `seed-identity-names-its-own-service.md` §6, держатель `TestDeterministicIDDerivationIsDeclaredOnce`).

Предмет

Идентификатор системной роли, служебной учётки модуля и связки OAuth есть функция ИМЕНИ: применённые миграции адресуют строки выражением `'<префикс>' || substr(md5('<имя>'), 1, 17)`, и на эти идентификаторы ссылаются выданные права. Вторая копия формулы разойдётся с первой МОЛЧА — и разойдётся ровно там, где обе отвечают «идентификатор вычислен»: полученное значение остаётся синтаксически верным и перестаёт находить строку. Наблюдаемо это только по отказу в доступе у арендатора, у которого право не отзывали.

Порт с монорепо (`internal/repohygiene/derivedidsinglesource.go`, снят вынесением службы — `kacho#2597`): формула не переехала с кодом целиком, а была написана заново рядом с единственным домом — `internal/domain/derived_id.go`, чей собственный комментарий уже называет этот гейт держателем и ожидает его присутствия. До этой правки объявление не охранялось ничем: единственность была фактом дня, а не удержанным свойством.

Что здесь считается ОБЪЯВЛЕНИЕМ

Файл прод-дерева, импортирующий `crypto/md5`. Иных потребителей MD5 в этом продукте нет и быть не должно: как примитив защиты MD5 запрещён (сам импорт в доме несёт отметку `#nosec G501`), а как контрольная сумма он здесь не применяется — значит всякое его вычисление есть деривация идентификатора.

Распознаватель знает ВСЕ формы импорта by construction

Он читает ПУТЬ импорта из разобранного дерева, а не имя пакета в тексте, поэтому псевдоним (`md5b "crypto/md5"`), точечный (`. "crypto/md5"`) и пустой (`_ "crypto/md5"`) импорты опознаются одинаково. Упоминание пути в комментарии или в строковом литерале импортом НЕ является — разбор судит узел, а не подстроку.

Чего разбор НЕ видит — названо, а не спрятано

  1. **своя реализация MD5 руками** — развёрнутый алгоритм без импорта. Это другой класс, и ловит его обзор, а не этот гейт;
  2. **вычисление на стороне базы** — `md5()` в тексте миграции. Это ВТОРАЯ сторона равенства, а не вторая копия Go-функции, и этот гейт её не судит.

granted_relation_in_model.go — разбор: отношение, которое ВЫДАЁТ миграция, обязано СУЩЕСТВОВАТЬ в модели, которую применяет решение о доступе.

Предмет

Выдача права живёт в двух артефактах, и они доезжают до решения РАЗНЫМИ путями: отношение объявляет модель прав, а саму выдачу пишет миграция — строкой в очередь. Если миграция называет отношение, которого в применяемой модели нет, запись отвергается со значением «такого отношения нет», дренаж верно считает такой отказ ПОСТОЯННЫМ, и строка травится: счётчик попыток выставляется в потолок, и больше её не возьмут никогда.

Что это стоит

У этой очереди НЕТ переезда отравленных строк обратно в работу: разбор партиций идёт по идентификатору ресурса, которого у неё нет by construction (она партиционирована по ключу кортежа). Следствие названо честно: отравленная строка не «подождёт», а ЛЕЖИТ ДО ВМЕШАТЕЛЬСТВА ОПЕРАТОРА. Право, которое она несла, не выдаётся.

Почему разбор дерева, а не внимание

Расхождение не видно НИ ОДНОЙ из двух сторон. Миграция — обычный SQL: она применяется без ошибки, потому что про модель ничего не знает. Модель — обычный DSL: он проходит проверку, потому что про миграции ничего не знает. Сборка цела, пробы обеих сторон зелёные, а право не выдано. Единственное место, где два факта встречаются, — дерево.

Чего этот разбор НЕ ловит (названо, чтобы на него не сослались шире предмета)

Он про СОСТАВ, а не про ПОРЯДОК. Если отношение в модели есть, но новая её редакция ещё не применена, а дренаж уже взял строку, — пара сойдётся, разбор промолчит, а строка отравится ровно так же. Порядок двух путей доставки деревом не проверяется.

Порт с монорепо — пара файлов названа, а не умолчана

Перенесено с `PRO-Robotech/kacho:internal/repohygiene/grantedrelationinmodel_test.go` (снято вынесением службы — `kacho#2598`; предмет жив здесь, задача #17). Изменилось: координаты обоих операндов (приставки `services/iam/` в самостоятельном клоне нет), разбор вынесен из пробы в пакет `check`. Осталось дословно: имя гейта, ОБЕ формы записи кортежа и то, что применяемая модель читается ВСТРОЕННАЯ, а не каноническая.

Близнеца в платформе нет: семейство снято там вместе со службой (ban #20).

identity_growth_reader.go — разбор: у величины роста числа личностей есть ЧИТАТЕЛЬ, и он назван.

Предмет

Величина, которую никто не смотрит, наблюдаемостью не является: она печатается на витрине, ничего не утверждает и создаёт уверенность, которой нет. Задача, заведшая семейство, просила именно наблюдаемость — «число личностей и скорость их появления видны, превышение порога порождает оповещение», — и ряд без правила закрывал бы её формой, а не существом.

Что считается читателем

ТОЛЬКО выражение правила оповещения (`expr:`). Упоминание имени ряда в пояснении к тревоге или в таблице метрик читателем НЕ является: пояснение не срабатывает. Различие несущее — оба текста лежат в одном файле, и разбор, ищущий имя по всему документу, зеленел бы на ряде, о котором лишь написано.

Граница названа

Судится ОДНО семейство, и его состав выводится из файла коллектора, а не из выписанного перечня. На прочие ряды службы разбор не распространяется, и это не оплошность: у части из них правил сегодня нет, и заведение им читателей — отдельная работа с отдельным предметом. Расширение на всё семейство метрик обязано прийти ВМЕСТЕ с этими правилами, иначе оно потребует перечня исключений — то есть заведёт ровно ту форму, в которой послабление переживает свой предмет.

Порт с монорепо — пара файлов названа, а не умолчана

Перенесено с `PRO-Robotech/kacho:internal/repohygiene/identitygrowthreader_test.go` (семейство снято вынесением службы, `kacho#2597`; предмет жив здесь — задача #17). Изменилось: координаты обоих операндов (приставки `services/iam/` в самостоятельном клоне нет), разбор вынесен из пробы в пакет `check`, приставка рядов берётся у того же имени, которым пакет уже называет свой словарь. Осталось дословно: имя гейта (`TestIdentityGrowthMetricsHaveANamedReader`), разбор выражений и граница «исполняемое против объяснения».

Близнец в платформе снят вместе с предметом — там этих рядов больше нет, поэтому пары файлов этот порт НЕ заводит.

injection_named_exists.go — разбор: доказательство способности упасть, НАЗВАННОЕ пробой, обязано существовать (#2479).

───────────────────────────────────────────────────────────────────────────── ПРЕДМЕТ

Проба, чья шапка говорит «способность упасть доказана инъекцией — такой-то файл», делает утверждение о ДЕРЕВЕ. Утверждение это не компилируется и никем не сверяется: файл переименовали, унесли вместе с рефакторингом либо не написали вовсе — а шапка продолжает обещать доказательство. Гейт, потерявший способность краснеть, на чистом дереве выглядит РОВНО ТАК ЖЕ, как исправный, поэтому обещание доказательства читается как само доказательство.

Замер, из которого разбор выведен: на ревизии заведения упоминаний в комментариях было 122, не резолвилось ОДНО — шапка гейта осей адреса называла файл, которого в дереве не было с первого её дня.

───────────────────────────────────────────────────────────────────────────── У ЭТОГО РАЗБОРА ЕСТЬ БЛИЗНЕЦ В ПЛАТФОРМЕ — И ЭТО НАЗВАНО, А НЕ УМОЛЧАНО

Тот же разбор, поднятый до корня МОНОРЕПО, живёт в `tools/injectionproofgate` (задача #2519): этот обходит корень своего модуля и о платформе не высказывается — в самостоятельном клоне службы монорепо нет вовсе. Обещания соседних модулей платформы этому модулю не принадлежат.

Свести обе реализации в одну сегодня НЕЛЬЗЯ: модуль службы пинит платформу псевдоверсией, поэтому импортировать пакет, которого в пинованной ревизии ещё нет, он не может. Предикат сведения: пин указывает на ревизию, где тот пакет существует; до этого две реализации об одном предмете живут рядом осознанно.

───────────────────────────────────────────────────────────────────────────── СУДЯТСЯ КОММЕНТАРИИ, И ЭТО РЕШЕНИЕ, А НЕ УПРОЩЕНИЕ

Координата доказательства пишется ПРОЗОЙ — это её законное место, и разбор читает разобранные группы комментариев, а не сырой текст файла. Строковые литералы намеренно НЕ судятся: в них живут синтетические имена, которые инъекции кладут во временные каталоги, и дерева они не называют вовсе. Судить их значило бы краснеть на чужой фикстуре — то есть на собственном доказательстве.

Величина «в строках» всё равно печатается переписью: молчание о целом виде вхождений неотличимо от их отсутствия.

───────────────────────────────────────────────────────────────────────────── ЗАКОННЫХ ФОРМ КООРДИНАТЫ ТРИ, И РАСПОЗНАВАТЕЛЬ ЗНАЕТ ВСЕ ТРИ

Форма, о которой он не знает, даёт не красное и не зелёное, а МОЛЧАНИЕ. Измерено на этом дереве: наивный резолвер («имя рядом с называющим») дал 4 непопадания из 138, и все четыре оказались ЗАКОННЫМИ формами, а не находками.

СОСЕД        `<имя>_injection_test.go` — файл в каталоге называющего;
ПО МОДУЛЮ    то же имя, но доказательство лежит в ДРУГОМ пакете модуля
             (проба одного пакета ссылается на инъекцию соседнего);
КООРДИНАТОЙ  `internal/<пакет>/<имя>_injection_test.go` — путь от корня
             МОДУЛЯ службы, а не от корня монорепо: в самостоятельном клоне
             приставки `services/iam/` нет, и счёт от неё указывал бы наружу
             дерева.

Имя в примерах — ОБРАЗЕЦ с угловыми скобками, а не координата, и это не подгонка текста под инструмент: координата, названная в прозе, есть утверждение о дереве, и выдуманная — ложное. Разбор судит объявленные координаты, поэтому пример обязан не выглядеть ею.

job_knob_has_a_reader.go — разбор: у КАЖДОЙ величины секции фоновых заданий есть читатель вне пакета настроек (задача #2647).

Предмет

Ручка настроек, которую принимают, валидируют и не читают, — это «принято-и-проигнорировано» на уровне НАСТРОЙКИ, и там оно тише, чем в поле запроса. Оператор, выставивший величину, получает УСПЕХ: значение принято, провалидировано, отказа нет. Он уверен, что изменил поведение. Поведение осталось прежним.

Три обстоятельства делают это неотличимым от исправной работы, и все три наблюдались вместе на `jobs.catalog-snapshot.refresh-interval`:

  • величина объявлена ДВАЖДЫ — секцией настроек и ручкой окружения в композиционном корне, — а петлю ведёт одна;
  • умолчания РАСХОДЯТСЯ (минута против пятнадцати секунд), то есть даже незаданная ручка описывает поведение неверно вчетверо;
  • страж старта у поля ЕСТЬ и отвергает непозитивное — и тем создаёт вид живого механизма: «ручка работает».

Наблюдаемого отличия нет ни одного: снимок обновляется, просто не с тем периодом. Заметить можно только замером окна отставания.

Что считается ЧИТАТЕЛЕМ, и почему собственная валидация им не является

Читателем считается обращение к полю в композиционном корне — там, где величина попадает в механизм. Метод `Validate` самой секции читателем НЕ является by construction: он живёт в пакете настроек, и его вызов доказывает ровно то, что величину проверили, — а не то, что ею кто-то пользуется. Именно поэтому предикат задачи звучал «читатель ВНЕ собственной валидации»: у поля без механизма читателей было два, и оба — его собственная проверка.

Почему разбор УЗЛОВ, а не поиск имени

Имя поля (`Interval`, `Enabled`, `Grace`) — из самых частых в дереве, и поиск по нему засчитал бы читателем одноимённое поле ЧУЖОЙ структуры, комментарий и строку журнала. Поэтому читатель опознаётся цепочкой узлов: обращение к полю через `…Jobs.<секция>` либо через ПСЕВДОНИМ, связанный с этой цепочкой (`c := cfg.Jobs.ExpiredCredentialReclaim`, дальше `c.Interval`) — ровно та форма, которой пользуется корень.

Граница названа: секция, переданная ЦЕЛИКОМ

Секция, ушедшая в вызов целиком (`f(cfg.Jobs.X)`), пофайлово не разбирается: о её полях этот гейт не утверждает ничего. Такие секции НЕ прощаются молча — они печатаются переписью отдельной величиной, потому что «поле прочитано» и «секция уехала целиком, а поле, может, и не прочитано» — разные вердикты, и второй обязан быть видим.

judge_target_wiring.go — разбор: у ЕДИНСТВЕННОГО судьи оси обязан быть вызывающий среди того, что исполняется само.

Предмет

Часть осей этого дерева судит ровно один исполнитель, поднимаемый целью рецепта: форму манифеста модуля — загрузчик `internal/manifest` (цель `module-manifest-check`), сходимость блоков модели доступов с манифестами — `tools/model-canon-check.sh` (цель `model-canon-check`). Единственность судьи назначена намеренно, и второго заводить нельзя: две копии одного суждения расходятся молча и расходятся там, где обе зелены.

У единственности есть цена. Если у такого судьи нет ВЫЗЫВАЮЩЕГО, то ось, которую судит только он, не встречает НИ ОДНОЙ автоматической проверки — и молчание неотличимо от исправной работы. Это вторая половина класса «проверка с формой, но без содержания»: страж, который ничего не проверяет, и страж, которого никто не зовёт. Здесь — вторая.

Чем этот разбор НЕ является

Он не судит форму манифеста и не сверяет блоки модели: второй судья тех же осей запрещён. Его предмет — ПРОВЯЗКА.

Почему разобранный YAML, а не текст

Имя цели встречается в носителях чаще, чем её вызов: в заголовке шага, в условии, в комментарии, который эту же провязку объясняет. Поиск подстрокой зеленел бы на собственном объяснении и оставался бы зелёным при СНЯТОЙ провязке. Поэтому вызов ищется в теле `run:` разобранного задания, а комментарии из тела снимаются (`ExecutableRunBodies`), и форма вызова требуется исполняемая (`CallsMakeTarget`).

Порт с монорепо — пара файлов названа, а не умолчана

Перенесено с `PRO-Robotech/kacho:internal/repohygiene/gatetargetwiring.go` вместе с двумя его семействами (`modulemanifestcheckwiring`, `modelcanoncheckwiring`; сняты вынесением службы — `kacho#2598`, предмет жив здесь, задача #17). Изменилось: операндов у обхода не «Makefile каждого сервиса», а ОДИН корневой рецепт — у самостоятельного модуля сервисных подкаталогов нет by construction; носителей провязки тоже один род (задания конвейера), потому что локального прогонщика `scripts/ci-local.sh` в этом дереве не существует. Примитивы разбора не копируются: они уже живут в пакете (`MakefileDeclaresTarget`, `ExecutableRunBodies`, `CallsMakeTarget`) и приехали сюда портом гейта сверки каталога прав.

Близнеца в платформе у этого разбора нет: оба семейства сняты там вместе со службой, поэтому пары файлов порт НЕ заводит (ban #20).

key_algorithm_dictionary.go — разбор словаря зарегистрированного алгоритма в СХЕМЕ.

Предмет

Словарь алгоритмов ключа объявлен дважды: ограничением схемы и закрытым перечнем кода. Совпадение двух объявлений держится ГЕЙТОМ, а не совпадением формулировок: разойдясь, они дают либо строку, которую схема примет, а проверяющий не признает, либо алгоритм, который проверяющий считает допустимым, а вставить его нельзя.

Пустое значение — ЗАКОННЫЙ вход, и означает оно «ключа нет»

Ограничение допускает пустую строку, и это не расхождение с кодом: пустое значение означает «ключа нет», а не «любой алгоритм». Клиент с пустым зарегистрированным алгоритмом аутентифицироваться утверждением не может — и это свойство держится проверкой на непустоту, а не словарём. Разбор поэтому выносит пустое значение отдельно, а не считает его алгоритмом.

Что здесь считается ДЕЙСТВУЮЩИМ объявлением

Миграции применяются по порядку и не правятся (ban #5), поэтому действует ПОСЛЕДНЕЕ объявление ограничения с этим именем, а снятое `DROP CONSTRAINT` не действует вовсе. Разбор читает файлы в том же порядке, в котором их применяет накат.

Какие формы записи словаря разбор ЗНАЕТ

Их две, и обе законны в этом дереве (предмет [dictionaryListOpensAt]):

key_algorithm IN ('', 'ES256', 'RS256', 'EdDSA')                       -- рука
key_algorithm = ANY (ARRAY[''::text, 'ES256'::text, 'RS256'::text])    -- снимок

Вторую производит сведённый свод миграций: свод написан инструментом, и членство он записывает только так. Разбор, знавший одну форму, не краснел и не молчал, а ОСЛЕП: находил ноль объявлений и сообщал об этом словами «столбец не сужен ничем» — утверждение о СЕБЕ, сказанное о схеме.

Чего разбор НЕ видит — названо, а не спрятано

  1. **ограничение, наложенное функцией или триггером**, а не перечнем значений. Форма другая, и предмет у неё другой.
  2. **словарь, собранный из значений другой таблицы** (внешний ключ на справочник): тогда объявления в тексте миграции нет вовсе, и сверять нечего — счётчик найденных ограничений это покажет.
  3. **значение, собранное выражением** — конкатенация, вызов функции. Приведение типа на литерале в этот пункт НЕ входит: имя типа стоит за кавычками, поэтому значением оно не становится.
  4. **перечень ЗАПРЕЩЁННОГО** — не по слепоте, а по решению: гейт сверяет словарь с перечнем ДОПУСТИМОГО кода, и засчитать дополнение множества значило бы сравнить его с самим множеством.

Порт с монорепо — пара файлов названа, а не умолчана

Перенесено с `PRO-Robotech/kacho:internal/repohygiene/keyalgorithmdictionary.go` (снято вынесением службы — `kacho#2598`; предмет жив здесь, задача #17). Изменилось: накат миграции подаёт ВЫЗЫВАЮЩИЙ (та же форма, что у соседа по пакету — `SQLCreateTableBody`), поэтому зависимости на пакет миграций у разбора нет; помощник чтения идентификатора переименован, чтобы не переобъявлять соседского. Осталось дословно: имя гейта, обе формы словаря и граница «пустое — не алгоритм».

Близнеца в платформе нет: семейство снято там вместе со службой (ban #20).

limit_export_procedure.go — разбор инструкций установки на предмет процедуры, которой оператор сохраняет строки таблицы ПЕРЕД её сносом (задача продукта #2134, приёмка KAN-QUOTA-1 §9 `ПР-3`, сценарий `KAN-Q4-07`).

Предмет

Накат отказывает, увидев живые строки в таблице, которую снесёт ещё не применённая миграция, и называет оператору два шага: сохранить и разрешить снос. Первый — команда, и производит её РОВНО ОДНО место, `dropguard.PreserveCommand`.

Оператор читает эту команду дважды и в двух РАЗНЫХ местах: в отказе, когда накат уже встал, и в инструкции обновления, когда он к обновлению готовится. Два написания одной команды расходятся молча — и расходится то, которое НЕ исполняется, то есть документ. Поэтому документ обязан нести её ДОСЛОВНО, а не пересказом.

Оси находки — две, и они с разных сторон

  1. **инструкция службы доступа обязана нести команду для таблицы величин.** Версия, снимающая домен величин, сносит `kaname.limits`; счёт её строк ненулевой у ЛЮБОЙ установки (цепочка сеет умолчания, администратор пишет сверх), значит отказ наступит у каждого, и процедура обязана быть записана ЗАРАНЕЕ. Ось привязана к координате намеренно: без неё «команды нет вовсе» давало бы ноль предметов, то есть зелёное на достигнутой потере;
  2. **всякая процедура выгрузки в любой инструкции обязана совпадать с производителем побайтово.** Ось ловит ВТОРОЕ написание — то, что заведут соседи, скопировав абзац и поправив под себя.

Порт с монорепо — пара файлов названа, а не умолчана

Перенесено с `PRO-Robotech/kacho:internal/repohygiene/limitexportprocedure.go` (семейство снято вынесением службы, `kacho#2597`; предмет жив здесь — задача #17: INSTALL.md службы несёт команду для `kaname.limits`). Изменилось: дом производителя (`PRO-Robotech/corelib:dropguard`, приезжает пином — своей копии порт НЕ заводит), пакет, координата инструкции (приставки `services/iam/` в самостоятельном клоне нет) и имена трёх внутренних помощников, разведённые с соседями по пакету. Осталось дословно: имя гейта, обе оси находки и разбор.

Чего разбор НЕ видит — названо, а не спрятано

Команду, разорванную переносом строки: строка документа читается целиком, и перенос внутри неё разорвал бы и саму команду для того, кто её копирует. Отдельно: разбор судит ТЕКСТ инструкции, а не то, что psql её исполнит, — исполнимость против живой схемы утверждает интеграционная проба службы доступа, где база поднимается.

list_scope_double.go — разбор: пакет, чей дублёр области видимости объявляет её НЕОГРАНИЧЕННОЙ, обязан называть живого держателя настоящего отбора.

Предмет, и почему требуется именно это

Снисходительность здесь НАМЕРЕННА, и её цена названа в самих пробах: строк выдачи у их фикстуры нет вовсе, поэтому назвать кандидатов она не может, а сузив набор до пустого — вернула бы пустую страницу везде и стёрла бы предмет своих же проб (вердикт: каким отношением судится строка страницы). Требовать «почините дублёров» значило бы сломать работающее.

Опасно другое. Отбор кандидатов держит РОВНО ОДИН пакет, и держит он его на настоящей базе. Выпадет он из набора — по недосмотру, из-за недоступных контейнеров, при переименовании — и свойство перестанет проверяться НИГДЕ, а ссылки на него останутся и будут читаться как покрытие. Форма остаётся, содержание исчезает молча.

Поэтому разбор требует не сужения у дублёров, а РЕЗОЛВИМОСТИ ссылки: снятие держателя роняет прогон с ЕГО ИМЕНЕМ, а не тишиной.

Почему разбор синтаксиса для одной части и комментарии для другой

Снисходительность — свойство ИСПОЛНЯЕМОГО кода (значение поля в литерале области), и ищется разбором: поиск подстроки нашёл бы слово в комментарии, объясняющем эту же проверку. Ссылка на держателя — наоборот, живёт ИМЕННО в комментарии, потому что адресована читателю; её и ищем в комментариях, разобранных парсером, а не в сыром тексте файла.

ДВА написания координаты — обе законны, и разбор обязан знать обе

Здесь порт расходится с монорепошным оригиналом, и расходится ЗАМЕРОМ. Там координата была одна — `services/iam/internal/apps/kaname/api/<пакет>`. Здесь в дереве живут ОБЕ формы, и обе законны: приставка `services/iam/` остаётся канонической для вызовов `platformtree` (`treeposture.PathOf` принимает координату ОТ КОРНЯ ДЕРЕВА ПЛАТФОРМЫ и снимает приставку сам, когда модуль стоит самостоятельным клоном), а без приставки пишут там, где адресуют каталог этого модуля напрямую.

Замер на дереве: строк-комментариев с приставкой — 53 в 31 файле, строк кода с ней же — 20, и КАЖДАЯ из двадцати законна by construction: это аргументы `platformtree`.

ЧТО ЭТА ОСЬ СЕГОДНЯ МЕНЯЕТ, НАЗВАНО ЧЕСТНО — вердикта она не меняет, и сказать это надо прямо, иначе следующий прочтёт её как закрытый дефект. Перемер образцом только с приставкой: пакетов 27, снисходительных 7, держателя называют те же 7, находок 0 — то есть ровно столько же. Голая форма слепой не бывает by construction (она совпадает и ВНУТРИ приставочной), а приставочная теряет сегодня лишь 4 ссылки переписи из 54.

Ось заведена не ради сегодняшнего числа, а ради ЗАВТРАШНЕГО: ссылка, написанная в голой форме в пакете, где другой ссылки нет, при однобразцовом распознавателе дала бы не красное и не зелёное, а невидимость. Перепись печатает обе величины порознь, поэтому смена соотношения будет видна числом, а не догадкой.

Граница, объявленная самим разбором

Судятся только пакеты, которые снисходительного дублёра ЗАВОДЯТ. Пакет без него под разбор не подпадает — там нечему быть снисходительным. «Ноль находок» означает «у каждого снисходительного назван живой держатель», а не «снисходительных нет»: перепись печатает оба числа.

Порт с монорепо — пара файлов названа, а не умолчана

Перенесено с `PRO-Robotech/kacho:internal/repohygiene/listscopedoubleisnotlenient_test.go` (семейство снято вынесением службы — `kacho#2598`; предмет жив здесь, задача #17). Изменилось: корень обхода (приставки `services/iam/` в самостоятельном клоне нет), разбор вынесен из пробы в пакет `check`, распознаватель знает обе формы координаты. Осталось дословно: имя гейта (`TestLenientScopeDoubleNamesALiveHolder`), предмет, граница и то, что снисходительность ищется разбором, а ссылка — в комментариях.

Близнеца в платформе нет: семейство снято там вместе со службой (ban #20).

manifest_verb_class_rule.go — два распознавателя для свойств ДЕРЕВА, которых проба пакета утверждать не может.

  1. правило «класс действия из его ИМЕНИ» объявлено в дереве РОВНО ОДИН РАЗ. Проба пакета о числе объявлений не утверждает ничего: она зелена при любом. Единственность объявления делает второе место НЕПРЕДСТАВИМЫМ, и это сильнее тождества импорта: появится генератор — импортировать ему будет нечего, кроме одной функции, by construction;

  2. правило вывода «тип объекта из имени ресурса» СНЯТО и не возвращено тихо. Приёмка сняла его замером, и без держателя его можно вернуть молча: ключ перестал бы быть обязательным, а восстанавливающее правило поселилось бы в ДВУХ местах — в генераторе (когда опускать) и в загрузчике (как восстановить).

Как распознаётся правило «класс из имени» — и почему НЕ по набору литералов

Наивный распознаватель («объявление, чей набор строковых литералов равен пяти каноническим») даёт ЛОЖНУЮ находку: рядом живёт ПОРЯДОК ПОКАЗА глаголов, набор у которого тот же, а референт другой. Гейт, краснеющий на верном коде, отключают первым.

Поэтому распознаётся ПАРА: функция, отвечающая «класс и получилось ли» (результаты `(string, bool)`), и набор ровно пяти канонических токенов, до которого она дотягивается — своим телом либо объявлением того же файла. Порядок показа под это не подпадает: его читает функция с ОДНИМ результатом.

Порт с монорепо — пара файлов названа, а не умолчана

Перенесено с `PRO-Robotech/kacho:internal/repohygiene/manifestverbclassrule_test.go` (семейство снято вынесением службы, `kacho#2597`; предмет жив здесь — задача #17). Изменилось: каталог загрузчика (приставки `services/iam/` в самостоятельном клоне нет), пакет, и вход распознавателей — исходник вместо уже разобранного узла: разбор живёт теперь в одном месте, а проба и инъекция подают ему текст. Осталось дословно: имена обоих гейтов, пара признаков и тексты находок.

migration_not_a_writer_of_module_role.go — разбор миграций и манифестов: роль модуля, у которого ЕСТЬ манифест, пишет применитель, а не миграция.

Предмет

Миграция, вставившая такую роль, заводит ВТОРОГО писателя одного предмета: два места разойдутся молча — правка манифеста не доедет до строки, потому что строку держит миграция, а перепись применителя об этом ничего не скажет.

Перечень модулей с манифестом ВЫВОДИТСЯ, а ведомость НЕ заводится

Ведомость «модули без манифеста» есть второе место об одном предмете, и расходится оно МОЛЧА — ровно в тот день, когда у модуля появляется или исчезает манифест. Производный перечень истекает BY CONSTRUCTION: запись исчезает вместе с появлением манифеста, и истекать вручную нечему.

Число манифестов здесь намеренно НЕ выписано вторым местом: оно растёт с каждым новым модулем и устарело бы молча. Узнаётся одной командой:

git ls-files '*manifest.yaml' | wc -l    # сколько их в дереве СЕЙЧАС

Как узнаётся манифест — по СОДЕРЖИМОМУ, а не по пути

Разбор, привязанный к пути, молчал бы вечно, окажись путь другим, — и его молчание было бы неотличимо от чистоты. Поэтому манифест опознаётся парой ключей верхнего уровня: объявлением версии контракта и именем модуля.

Форм записи имени роли ДВЕ, и обе законны

Рукописная выводит идентификатор ИЗ имени, поэтому имя стоит аргументом деривации; снимочная подставляет уже вычисленный идентификатор и перечисляет колонки явно. Разбор, знавший одну, извлекал ноль имён при сорока восьми блоках — это не находка и не молчание, а невидимость: каждая вставленная роль оказалась вне наблюдения. Ловят это ДВЕ величины переписи: «имён извлечено» и «блоков с непрочитанным именем».

Чего разбор НЕ видит — названо

  1. **фикстуры проб** — они объявляют чужой модуль и сделали бы его «модулем с манифестом», превратив каждую его миграцию в находку. Исключены по каталогу, и это единственное исключение;
  2. **манифест, приезжающий не файлом дерева** (карта настроек, том) — его в дереве нет by construction, и разбор о нём ничего не утверждает;
  3. **имя роли, записанное литералом идентификатора** — такие роли вне закрытого набора модулей, то есть находкой быть не могут ни при каком манифесте.

Порт с монорепо — пара файлов названа, а не умолчана

Перенесено с `PRO-Robotech/kacho:internal/repohygiene/migrationnotawriterofmodulerole.go` (снято вынесением службы — `kacho#2598`; предмет жив здесь, задача #17). Разбор перенесён БЕЗ правок логики: его операнды — текст манифеста и текст миграции, и ни один не несёт координаты дерева. Изменились только координаты в гейте рядом.

Близнеца в платформе нет: семейство снято там вместе со службой (ban #20).

mirror_catalog_condition.go — разбор: УСЛОВИЕ КАТАЛОГА НЕСЁТ КАЖДЫЙ ПИСАТЕЛЬ ЗЕРКАЛА.

Предмет

Зеркало каталога ресурсов — проекция, которую владельцы присылают через проксируемую полосу регистрации. Требование «тип обязан иметь живую строку каталога» выражено ОПЕРАТОРОМ записи, а не внешним ключом: постоянное ограничение запретило бы платформе снять тип, пока у арендатора есть ресурс этого типа, то есть сделало бы решение платформы заложником данных арендатора.

Цена выбора: инвариант стал свойством ПОЛОСЫ, а не свойством ТАБЛИЦЫ. Инвариант, выраженный в одном операторе из нескольких, — это инвариант, которого нет: второй писатель обходит его молча, и обнаруживается это тогда, когда данные уже записаны. Этот разбор — второй рубеж под тем же утверждением.

Требование ВЫВОДИТСЯ из эталонной полосы, а не задаётся литералом

Две копии одного условия разошлись бы молча — и разошлись бы именно там, где расхождение не видно: обе выглядели бы исправными. Поэтому условие берётся у полосы, через которую идёт регистрация от владельцев, и сверка идёт МЕЖДУ полосами. Переедет эталон — разбор объявит ОТКАЗ, а не промолчит.

Каталог берётся ИЗ ТОГО ЖЕ ЛИТЕРАЛА

Обещание сверки, данное в комментарии рядом, условием не является — иначе писателю довольно было бы пообещать её словами.

Признак таблицы каталога — ПРЕФИКС, а не перечень

Каталог растёт, и выписанный перечень отстал бы от него молча: новое условие оказалось бы вне наблюдения, не будучи нарушением.

Порт с монорепо — пара файлов названа, а не умолчана

Перенесено с `PRO-Robotech/kacho:internal/repohygiene/mirrorcatalogcondition_test.go` (снято вынесением службы — `kacho#2598`; предмет жив здесь, задача #17). Изменилось: координаты эталонной полосы и владельца таблицы (приставки `services/iam/` в самостоятельном клоне нет — модуль и есть владелец, поэтому проверка «писатель вне владельца» здесь выродилась бы в тождество и заменена проверкой, что писатель лежит В ДЕРЕВЕ МОДУЛЯ); разбор вынесен из пробы в пакет `check`. Осталось дословно: имя гейта, перечень глаголов записи с признаком «вводит строку», вывод условия из эталона и самоистечение ведомости.

Близнеца в платформе нет: семейство снято там вместе со службой (ban #20).

mirror_divergence_wiring.go — у ЧТЕНИЯ РАЗНОСТИ зеркала и каталога обязан быть ВЫЗЫВАЮЩИЙ в композиционном корне (kacho#1828).

Предмет

Разность зеркала и живого каталога — величина, от которой зависит решение владельца об отзыве, а отзыв ОТНИМАЕТ доступ. Читатель этой разности в дереве есть и хорошо построен; до этого гейта его не спрашивал НИ ОДИН путь исполнения — только интеграционные пробы. Механизм без вызывающего от отсутствующего неотличим: на поднятом стенде величина не производится, и «разности нет» читается ровно так же, как «никто не мерил».

Почему гейт судит УЗЕЛ ВЫЗОВА, а не слово

Имя читателя встречается в этом дереве и прозой — в объяснениях, включая объяснение самого гейта. Проверка по подстроке краснела бы на собственном комментарии, а зеленела бы на закомментированном вызове.

Какие формы записи вызова гейт знает

Обе законные: `resource_mirror.Divergence(…)` и вызов через АЛИАС импорта (`mirror "…/resource_mirror"` → `mirror.Divergence(…)`). Локальное имя пакета берётся из блока импортов каждого файла, а не предполагается равным последнему сегменту пути. Форма, о которой распознаватель не знает, — не редкость, а слепая зона: всё, записанное в ней, оказывается вне наблюдения.

Чем этот гейт НЕ является

Он не утверждает, что разность ПУСТА, и не вправе: непустая разность на стенде арендатора — предмет решения владельца, а не находка проверки. Предмет здесь один — ВЫЗЫВАЮЩИЙ существует.

module_identity_seeded_only_by_baseline.go — личность модуля заводит ТОЛЬКО применённая базовая миграция (ПР-5 приёмки WIRE-1, задача продукта #2098).

Порт с монорепо (`internal/repohygiene/moduleidentityseededonlybythebaseline_test.go`, снят вынесением службы — `kacho#2597`). В монорепо предикат жил ЦЕЛИКОМ внутри `_test.go` (пакет-«внешний тест», без отдельного `.go`); здесь он вынесен в не-тестовый файл, потому что кроме гейта его читает пересчёт.

ПРЕДМЕТ (дословно из монорепо)

Личности модулей посеяны БАЗОВОЙ миграцией, то есть приезжают и в установку, где платформы нет вовсе. Строка, которую арендатор, развернувший службу доступа отдельно, нести не обязан, — это данные окружения, и в миграцию они не идут ни при каких условиях (§«Данные СТЕНДА заводятся посевом»).

СОСТОЯНИЕ НА ДЕНЬ ПЕРЕНОСА — ДРУГОЕ, чем в монорепо, и это названо числом

В монорепо (на день заведения гейта) долг был НЕПОДВИЖЕН: применителя у раздела `seed` манифеста не было, применённую миграцию не поправить (ban #5), а свежая установка без платформы несла пять личностей чужого продукта.

В kaname этот долг ЗАКРЫТ отдельной задачей — #2452 (`20260909202745_module_identities_leave_the_baseline.sql`, применена ДО выноса службы из монорепо, то есть закрытие произошло в исходном дереве, а не в этом порту): пять личностей (`kacho-vpc`, `kacho-compute`, `kacho-nlb`, `kacho-registry`, `kacho-storage`) СНЯТЫ этой миграцией, а применитель заведён (`internal/apps/kaname/moduleseed`), позван из композиционного корня. Остаются ДВЕ: `bootstrap-admin` (личность самой службы, не модульная — `IsModule()` false) и `kacho-api-gateway` (модульная, остаток, названный вслух в шапке миграции — у края манифеста нет вовсе, применителя заводить некому, снимается вместе со своим производителем).

Обе остаются посеянными БАЗОВОЙ миграцией (`0001_initial.sql`, первой в порядке применения) — то есть `moduleIdentitiesSeededOutsideTheBaseline` сегодня находит ноль нарушений. Это НЕ делает гейт вакуумным: он и дальше судит регресс — появление НОВОЙ миграции, сеющей модульную личность НЕ через применитель (ровно тот класс, который #2452 только что убрал). Обновлять эту прозу нормой `#2098` больше не нужно: предмет её первой половины («свежая установка без платформы несёт ноль модульных СА, кроме остатка api-gateway») закрывает #2452, а не этот гейт; гейт стережёт РОСТ.

РОДСТВО, КОТОРОЕ НАДО НАЗВАТЬ — И РАЗЛИЧИЕ (дословно из монорепо)

У ролей модуля такой судья есть отдельным семейством (Г2, `migrationnotawriterofmodulerole`, НЕ входит в этот батч) — запрещает миграции писать роль модуля, у которого есть манифест, ПОЛНОСТЬЮ (у ролей применитель есть). У личностей применитель тоже теперь есть — но не для ВСЕХ (api-gateway — остаток), поэтому запрет здесь остаётся УЗКИМ: не «личность модуля не сеет никакая миграция», а «личность модуля не сеет НИКАКАЯ МИГРАЦИЯ КРОМЕ БАЗОВОЙ» — тот же периметр, что был в монорепо.

ЧЕГО ГЕЙТ НЕ ЛОВИТ (названо, чтобы на него не сослались шире предмета)

Он про ПОСЕВ, а не про живую базу: строку, заведённую не миграцией, он не читает by construction. И он ничего не утверждает о ПОЛНОТЕ посева.

named_verb_form_expiry.go — разбор ПАРЫ: отвергается ли поимённая форма права роли прод-кодом манифеста и есть ли в дереве пробы шести сценариев её полноты. Находка — ровно одно их сочетание: форма принята, полнота не проверяется.

Порт с монорепо (`internal/repohygiene/namedverbformexpiry.go`, снят вынесением службы — `kacho#2597`). Изменилось: пакет (`repohygiene` → `check`), путь домена (`services/iam/internal/manifest/` → `internal/manifest/`, префикс `services/iam/` снят — в kaname код службы лежит от корня репозитория). Осталось дословно: разбор узла (не подстроки), закрытый перечень шести сценариев, различение двух законных причин молчания.

Почему этот перенос ОБЯЗАТЕЛЕН, а не факультативен

Прод-код `internal/manifest/roleexport/check.go` (написанный ДО выноса службы, когда `internal/repohygiene` был тем же репозиторием) буквально называет держателя: «ЧЕМ ДЕРЖИТСЯ ЗАПРЕТ ... гейтом дерева `internal/repohygiene` `TestNamedVerbFormReturnsOnlyWithItsCompletenessCheck`». До этого файла держателя в дереве kaname не было ни одного: цитата утверждала присутствие проверки, которой не существует.

Предмет — ПАРА, а не любая её половина (дословно из монорепо)

Принять перечень ИМЁН, не умея проверить его полноту по классу, значит свести его к классу МОЛЧА и выдать право ШИРЕ просимого (замер приёмки: 55 вхождений из 92 в черновике vpc совпадают с именем класса). Молчание гейта законно ПО ДВУМ причинам, и различать их вызывающему не нужно: форма отвергается сентинелом (возвратов > 0) ЛИБО она вернулась вместе со своей проверкой (все шесть проб MOD-RL найдены).

Замер на дне переноса (kaname@issue-2597, kacho#2597)

Сентинел `ErrRoleRuleVerbsRetired` в `internal/manifest/` не объявлен и не возвращается (задача #1844 сняла его вместе с формой, которую он отвергал — `f5bb097046` в истории монорепо). Все шесть проб MOD-RL (04, 04a, 18, 18a, 19, 19a) в дереве ЕСТЬ (`internal/manifest/rolenamedverbs_test.go`, `internal/manifest/roleexport/namedverbs_test.go`). Гейт сегодня молчит по ВТОРОЙ законной причине — форма вернулась вместе со своей проверкой, ровно как того требует приёмка #1844, — а не по первой. Это и есть содержание переноса: без держателя регресс (снятие одной из шести проб при живом возврате перечня имён) не был бы замечен НИЧЕМ.

Чего разбор НЕ видит — названо, а не спрятано (дословно из монорепо)

Возврат сентинела, собранный в рантайме (через переменную, через таблицу видов). Такой формы в этом пакете нет, и появись она — гейт увидит ноль возвратов и покраснеет, то есть ошибётся В СТОРОНУ находки, а не молчания.

probe_home.go — РЕЗОЛВ НАЗВАННОГО ДОМА: координата чужого дерева проверяется В НЁМ, а не просто считается.

───────────────────────────────────────────────────────────────────────────── ПРЕДМЕТ

Приставка `<владелец>/<репозиторий>:` снимает координату с суждения соседнего гейта: подтвердить объявление функции в чужом репозитории он не мог. Пока это было так, у приставки была вторая, незаявленная роль — СПОСОБ СНЯТЬ КООРДИНАТУ С ПРОВЕРКИ. Имя, снятое в чужом дереве завтра, здесь не покраснело бы ни разу, и приёмка посылала бы читателя по адресу, которого нет.

ПОЧЕМУ ЭТО НЕ ЗАВОДИЛОСЬ РАНЬШЕ — И ПОЧЕМУ ДОВОД БЫЛ ВЕРЕН. Ветвь резолва без производителя входа есть мёртвый страж: объявлен и никогда не исполняется. Он заводится ВМЕСТЕ с производителем, и производитель здесь — две синтетические копии с РАЗНЫМИ идентичностями (`probe_home_injection_test.go`).

───────────────────────────────────────────────────────────────────────────── ПОРЯДОК КАНДИДАТОВ ЗАКРЫТ И ОБЪЯВЛЕН

  1. переменная `KACHO_HOME_<ИМЯ>` — оператор назвал копию явно;
  2. соседний клон: у каждого предка своего корня — `<предок>/<имя>` и `<предок>/project/<имя>`;
  3. ничего — ТРЕТЬЯ КАТЕГОРИЯ.

ДОМ ОПОЗНАЁТСЯ ИДЕНТИЧНОСТЬЮ `origin`, А НЕ ИМЕНЕМ КАТАЛОГА. Каталог зовут как угодно, и совпадение имени ничего не обещает: копия под именем `kacho` бывает клоном чего угодно. Поэтому кандидат, чей `origin` не тот, ОТВЕРГАЕТСЯ и называется в причине — «указатель, ведущий в чужой репозиторий, дома не даёт».

ПРИЧИНА ПЕРЕЧИСЛЯЕТ КАЖДОГО ОТВЕРГНУТОГО. Без перечня «дома нет» читается как «искали одно место», а починки у «переменная указывает мимо» и «клона нет» разные — и первая состоит в правке того, что уже объявлено.

───────────────────────────────────────────────────────────────────────────── ГДЕ СУДИТСЯ — В СТВОЛЕ ДОМА, А НЕ В ИНДЕКСЕ ЛЕЖАЩЕЙ РЯДОМ КОПИИ

Координата резолвится по `origin/main` дома. Копия ОБЩАЯ: её ревизию переключает соседняя сессия, не спрашивая отправляющего, и вердикт, прочитанный с индекса, есть функция чужого переключения. Класс наблюдался целиком (`PRO-Robotech/kacho-workspace#543`): копия стояла на линии, где каталог переименован, и проверка объявила несуществующими координаты, которые в стволе ЕСТЬ.

Координата, СВЯЗАННАЯ РЕВИЗИЕЙ (`owner/repo@<хеш>:Имя`), судится на ЭТОЙ ревизии, а не на стволе: она указывает в прошлое состояние чужого дерева намеренно, и сводить её к стволу значило бы судить не то, что написано.

Ствол не резолвится (клон без этой ссылки) — ТРЕТЬЯ КАТЕГОРИЯ, а не находка: судить не по чему, и молчаливый откат на индекс копии здесь запрещён той же причиной, что выше.

───────────────────────────────────────────────────────────────────────────── ЧТО ЭТОТ РЕЗОЛВ СЕГОДНЯ ДАЁТ В КОНВЕЙЕРЕ — СКАЗАНО ПРЯМО, А НЕ ПОДРАЗУМЕВАЕТСЯ

На машине разработчика, где копия дома лежит рядом, резолв ИСПОЛНЯЕТСЯ: замер на дереве службы — домов 2, координат проверено в доме 101, находок 0.

В конвейере службы копии дома рядом НЕТ: единственная выборка чужого дерева (`ci.yml`, задание сверки каталога прав) кладёт его в каталог с ДРУГИМ именем и берёт один подкаталог. Кандидатом она поэтому не становится, и резолв даёт ТРЕТЬЮ КАТЕГОРИЮ со своим числом — то есть безопасный исход, а не ложную находку: «дома нет» никогда не читается как «имени нет».

ОСТАТОК НАЗВАН С ПРЕДИКАТОМ, А НЕ ОБЕЩАНИЕМ. Чтобы резолв исполнялся и в конвейере, заданию, гоняющему этот гейт, нужна выборка дома и переменная `KACHO_HOME_KACHO`, указывающая на неё. Предикат снятия: прогон конвейера печатает «координат проверено в доме N > 0». Цена шага не измерена здесь и решается своим изменением: у разрежённой выборки другой состав и другой вес.

quota_authority_retired.go — АВТОРИТЕТ ВЕЛИЧИН УШЁЛ ИЗ СЛУЖБЫ ДОСТУПА ЦЕЛИКОМ.

Задача продукта `PRO-Robotech/kacho#2117`, приёмка `KAN-QUOTA-1`, стадия S4, сценарии `KAN-Q4-08`, `KAN-Q4-10`, `KAN-Q4-14`; условие готовности `DoD S4` пп. 1, 13.

───────────────────────────────────────────────────────────────────────────── ПРЕДМЕТ — ОТСУТСТВИЕ, А НЕ ПРИСУТСТВИЕ, И ПОТОМУ ГЕЙТ НУЖЕН ОСОБЕННО

Проверка, ищущая ОТСУТСТВИЕ формы, на исчезнувшем предмете замолкает: её образец не совпадёт больше никогда, обход и перепись целы, вердикт зелёный. Отличить это от исправной работы можно только переписью ОБЪЁМА: «находок ноль» и «прочитано ноль» обязаны быть разными вердиктами, и оба напечатаны.

Предмет разбора — ВОЗВРАТ: авторитет величин, заведённый заново в службе, чей продукт отвечает «кому что разрешено», а не «сколько чего можно завести».

───────────────────────────────────────────────────────────────────────────── РАЗБОР СУДИТ УЗЕЛ-ИДЕНТИФИКАТОР, А НЕ ТЕКСТ — И ЭТО НЕСУЩЕЕ

Гейт по подстроке краснел бы на СОБСТВЕННОМ объяснении: перечень снятых имён стоит в этом же файле, а надгробие снятого метода — в `authzguard`. Проверка, судящая ТЕКСТ, не отличает исполняемую часть от комментария, который эту же часть объясняет, — и снимают её первой, как непонятную.

Поэтому ось прод-кода разбирает файл `go/parser`-ом и судит ТОЛЬКО узлы `*ast.Ident`. Комментарий, строковый литерал и запись о снятом предмете под неё не подпадают by construction — и это намеренно: снятое называется в отрицательной форме, надгробием, а не стирается молча. Читатель, пришедший за методом, которого больше нет, обязан узнать, что его СНЯЛИ, а не решить, что он ищет не там.

Ось контракта разбирает СТРОКУ ОБЪЯВЛЕНИЯ (`service` / `message` / `enum` / `rpc` в начале строки).

Отступ в образцах записан `[ \t]`, а НЕ `[[:space:]]`, и это не придирка: второй класс включает перевод строки, поэтому совпадение начиналось на строку РАНЬШЕ объявления и находка называла чужую координату. Поймала это инъекция, а не чтение: сам факт находки был верен, неверно было место — то есть гейт послал бы читателя искать не туда. `.proto` не разбирается тем же парсером, но объявление от комментария отличимо: комментарий начинается с `//`, а объявление — с ключевого слова. Граница названа честно: объявление, записанное внутри многострочного комментария `/* */`, разбору невидимо.

───────────────────────────────────────────────────────────────────────────── ПОЧЕМУ ПРЕДИКАТ ПО СЛОВУ `limit` ОТВЕРГНУТ — ЭТО ИЗМЕРЕНО, А НЕ ВЫБРАНО

Прежняя редакция условия снятия #2117 считала слово `limit` в контракте и была НЕДОСТИЖИМА by construction (`kacho#2457`): под неё попадали имя поля размера страницы (`int32 limit = 2`), предел веерного ответа и проза об учёте у владельцев. Чтобы предикат дал ноль, пришлось бы снять имя поля страницы — ломающее изменение, к величинам отношения не имеющее.

Здесь предмет назван ИМЕНЕМ АВТОРИТЕТА, а не словом: закрытый перечень снятых символов и объявления, чьё имя несёт `Limit`. Поле `limit` объявлением не является и разбору невидимо.

───────────────────────────────────────────────────────────────────────────── ЗАКОННЫЙ ОСТАТОК НАЗВАН ПОИМЁННО — ИНАЧЕ ГЕЙТ ПОТРЕБОВАЛ БЫ РАСШИРЕНИЯ ПОВЕРХНОСТИ

Из службы уходит АВТОРИТЕТ величин. НЕ уходят три вещи, и каждая обязана молчать под всеми осями:

`LimitKind` и словарь посадки  три собственных потолка службы берут величину
                              из посадки (`П25`, `KAN-Q3-01`); снять их
                              значило бы оставить самостоятельную установку
                              без ограничения на число аккаунтов и
                              удостоверений — расширение поверхности, не
                              названное ни в одном артефакте;
`IdentityQuotaService`,       арендаторское чтение СВОЕГО потолка; переехало
`Quota`                       в контракт службы решением `Д9` именно затем,
                              чтобы пережить уход модуля;
предел СКОРОСТИ приёма        защита от злоупотребления, а не потолок
                              количества; слово «квота» в её отказе —
                              совпадение написания.

Ни одно из трёх в перечень снятых имён не входит, и каждое стоит законным близнецом в инъекции (`quota_authority_retired_injection_test.go`): без второй половины «находок нет» было бы неотличимо от «разбор не смотрит».

read_path_concat.go — разбор: НА ПУТИ ЧТЕНИЯ СРАВНИВАЮТСЯ КОЛОНКИ, А НЕ ИХ СКЛЕЙКА.

Предмет

Склейка колонки внутри УСЛОВИЯ выводит колонку из-под индекса: сравнивать приходится вычисленное значение, а вычисленное значение отбирает строки только ПОСЛЕ того, как они прочитаны. Ответ от этого не меняется, стоимость растёт с числом строк в системе, и заметно это только под нагрузкой.

Класс измерен, а не предположен. Починка горячего пути перевела на пару колонок два места — вердикт и перечисление объектов. Перепись ПО СВОЙСТВУ («колонка склеивается там, где значение сравнивается») дала на том же дереве ЧЕТЫРЕ: два обратных вопроса и две точки прибора замера, гасившие индекс области. У одной из четырёх комментарий рядом обещал «колонками, а не склейкой» — то есть был ложен.

Поведенческой пробы для этого мало: она мерит ту точку входа, которую зовёт, и молчит об остальных — ровно это и позволило долгу прожить. Свойство — свойство ДЕРЕВА, и держать его обязан обход дерева.

Объём ВЫВОДИТСЯ, а не выписывается

Каталоги берутся у объявления предмета замера (`scalegrid/fingerprint.go`) — того же источника, которым определяется предмет прибора. Выписанный перечень не двинулся бы от нового каталога и продолжал бы сторожить прежние.

Читается ИСПОЛНЯЕМАЯ часть

Литералы разбираются по синтаксическому дереву Go (SQL в Go-комментарии кодом не является), внутри литерала снимаются SQL-комментарии, а содержимое строковых литералов SQL ЗАКРЫВАЕТСЯ с сохранением длины — иначе слово внутри литерала читается как ключевое, условие обрывается, и гейт молчит ровно на той форме, ради которой написан.

Порт с монорепо — пара файлов названа, а не умолчана

Перенесено с `PRO-Robotech/kacho:internal/repohygiene/readpathconcat_test.go` (снято вынесением службы — `kacho#2598`; предмет жив здесь, задача #17). Изменилось: координата объявления предмета замера (приставки `services/iam/` в самостоятельном клоне нет), разбор вынесен из пробы в пакет `check`, разбор литералов Go взят у соседнего семейства того же дерева и живёт здесь одной копией. Осталось дословно: имя гейта, перечни ключевых слов условия, границы цепочки склейки и счёт законного близнеца.

Близнеца в платформе нет: семейство снято там вместе со службой (ban #20).

role_operation_response_state.go — анализатор «ответ операции над ролью не несёт вычисленного состояния, и это ОБЕСПЕЧЕНО, а не совпало».

Порт с монорепо (`internal/repohygiene/roleoperationresponsestate.go`, снят вынесением службы — `kacho#2597`). Дословно: весь анализатор. Изменилось: пакет (`repohygiene` → `check`); `ServiceRoot` теперь пустая строка у вызывающего — в kaname дерево службы лежит от корня, а не под `services/iam`.

Предмет

Контракт роли обещает арендатору буквально следующее: нулевое значение `health` и `lifecycle` означает «ЭТИМ ОТВЕТОМ НЕ ВЫЧИСЛЕНО» и никогда «роль здорова» либо «роль объявлена»; его несут ответы операций `Create`/`Update`, а `Get` и `List` заполняют состояние всегда.

Обещание держится ТОЛЬКО ТЕМ, что производителя вычисленного состояния никто не звал на пути мутации. Свойство «by construction» тем и плохо, что его снятие ТИХОЕ.

Что судится

ПЕРЕВОДЧИК ответа операции над ролью — не-тестовая функция, у которой (а) результаты ровно `(*anypb.Any, error)`, (б) есть параметр типа `domain.Role` и (в) в теле стоит вызов перевода `dto.Transfer`. Каждый такой переводчик обязан звать проекцию (`domain.Role.WithoutComputedState`). Не зовёт — находка с координатой.

ЧЕГО ОН НЕ СУДИТ

  1. ПОЛНОТУ набора производных полей — предмет пробы самой проекции;
  2. ЛИШНЮЮ РАБОТУ — расход без последствий для контракта;
  3. ЧТЕНИЯ (`Get`/`List`) — у них результат не `(*anypb.Any, error)`.

Падает на ПУСТОМ ОБХОДЕ

Ноль прочитанных файлов, ноль разобранных функций либо ноль найденных переводчиков роли — «находок ноль» неотличимо от «прочитано ноль».

role_scope_chain_stays_empty.go — САМОИСТЕКАЮЩИЙ гейт решения «меточную ось сужать НЕ НАДО» (задача продукта #1913, приёмка `docs/engineering/acceptance/role-withdrawal-has-a-producer.md` §2.8, §10 шаг 8).

Порт с монорепо (`internal/repohygiene/rolescopechainstaysempty.go`, снят вынесением службы — `kacho#2597`). Дословно: весь предикат, распознаватели, закрытый перечень ярусных источников. Изменилось: пакет (`repohygiene` → `check`), путь-приставка обхода (`services/iam/` снята — в kaname код службы лежит от корня).

Что здесь стережётся — ФАКТ О ДЕРЕВЕ, на котором стоит решение

Приёмка решила НЕ сужать меточную ось выдачи по живости роли, и решение стоит целиком на одном факте: у роли МОДУЛЯ цепь областей ПУСТА, поэтому меточная выдача не достаёт её ни живую, ни снятую. Факт измерен и верен сегодня — и НЕ ЗАЩИЩЁН НИЧЕМ:

  • роль модуля всегда кластерного яруса, потому что `owner_module` и `cluster_id` пишет ОДИН оператор, а не ограничение схемы;
  • у роли кластерного яруса цепь пуста, потому что ни одна ветвь производителя звеньев её не отбирает: ветви берут `account_id` и `project_id`, а у роли модуля они пусты оба.

Значит производителя звена для `iam_role` может завести любая соседняя работа. Появится он — решение §2.8 станет неверным, а доступ вернётся МОЛЧА. Этот гейт и есть то единственное, что об этом скажет.

ЧТО СЧИТАЕТСЯ НАХОДКОЙ — ИСТОЧНИК ветви, а не имя типа

Ветвей, производящих звено для `iam_role`, две, и обе ЗАКОННЫ:

(5a) роль АККАУНТА  → источник `account_id`
(5b) роль ПРОЕКТА   → источник `project_id`

Находка — ТРЕТЬЯ ветвь: та, что производит звено для `iam_role`, не спрашивая ни одного из двух ярусных столбцов.

ЧЕГО РАЗБОР НЕ ВИДИТ — НАЗВАНО, А НЕ СПРЯТАНО

  1. звено, приехавшее ЗЕРКАЛОМ ресурса (writer одинаков для всех типов);
  2. запрос, собранный из кусков в рантайме;
  3. производителя вне дерева kaname.

role_verb_projection_sole_writer.go — разбор операторов записи в проекции роли: «кто АВТОРУЕТ строку, кто её СНИМАЕТ, переселяет ли снимающий-не-автор снятое» (порт с монорепо `internal/repohygiene/roleverbsolewriter_test.go`, держатель `TestIAMRV112_RoleVerbProjectionHasASoleWriter`, снят вынесением службы доступа — `kacho#2597`).

Предмет

Таблицы `kaname.role_verb` и `kaname.role_rule_ref` — проекции роли, то, из чего цепь вердикта собирает ответ «разрешено ли действие». Класс, ради которого гейт заведён: ДВЕ реализации знают, что такое законная строка, и расходятся МОЛЧА — обе компилируются, у обеих есть пробы, и различаются они только на входе, который ни одна проба не подаёт.

Единица — «авторует», а не «пишет» (решение kacho#1034, перенесено дословно)

Что такое законная строка, объявляет ТОЛЬКО `INSERT`: он называет колонки и значения. `DELETE`/`UPDATE` строку не авторуют — они её снимают или правят. Значит класс живёт в АВТОРСТВЕ, а не в записи вообще, и единица гейта — функция, ВНОСЯЩАЯ строку. Снимающий не-автор обязан ПЕРЕСЕЛИТЬ снятое в `kaname.role_grant_orphan` ТЕМ ЖЕ оператором — иначе отобранное право неотличимо от никогда не выданного.

Что изменилось при переносе, а что осталось дословно

Изменилось: пакет (`repohygiene` → `check`), путь-константа слоя (без префикса `services/iam/` — код лежит от корня модуля kaname), обход дерева (`gitenv`+`git ls-files` вручную → `github.com/PRO-Robotech/kacho/pkg/treecorpus` и `internal/testsupport/platformtree.RequireCorpus`, потому что предмет — внутри службы, дерева платформы модулю не нужно). Осталось дословно: имена таблиц-проекций, форма распознавателя (узел-литерал разобранного AST, а не текст файла), три оси проверки (авторство · переселение · слой) и имя держателя `TestIAMRV112_RoleVerbProjectionHasASoleWriter` — на нём стоят цитаты `docs/engineering/acceptance/role-verb-projection-sole-writer.md`, `rule-segments-have-a-referent.md` и `module-manifest-roles-and-seed-grants.md`, написанные ДО выноса, когда `internal/repohygiene` был тем же репозиторием.

Граница названа, а не умолчана

Гейт читает СТРОКОВЫЕ ЛИТЕРАЛЫ непроверочного кода Go, разобранного в дерево, и приписывает находку объемлющей функции. Он НЕ видит: SQL миграций (там запись законна — миграция и есть схема), проб (им положено готовить состояние), имя таблицы, собранное из кусков (слепая зона, предикатом по подстроке не ловится ничем).

seed_identity_census.go — разбор ДВУХ текстов об одном предмете: вывода переписи посевной идентичности и чисел, объявленных приёмкой `docs/engineering/acceptance/seed-identity-names-its-own-service.md` §0.

ПРЕДМЕТ

У приёмки есть исполняемый предикат, лежащий рядом с ней (`seed-identity-names-its-own-service.py`), и числа §0 — его вывод. Пока предиката никто не зовёт, эти два текста расходятся МОЛЧА: документ продолжает называть числа, верные для ревизии, которой в стволе уже нет, и отличить «перемерено» от «переписано по памяти» нечем.

ПРИЗНАК — ИЗМЕРЕН, А НЕ ПРЕДПОЛОЖЕН

Расхождение наступило до заведения этого гейта и было найдено вручную: объявление называло по ведру ПРЕДМЕТА `130 · 54 ф.`, предикат на стволе давал `130 · 56 ф.`. Вхождений СТОЛЬКО ЖЕ — двигались файлы, — поэтому расхождение не видно ни по одному числу в отдельности и обнаруживается только сверкой обоих текстов целиком.

ЕДИНСТВЕННЫЙ ИСТОЧНИК ПЕРЕЧНЯ ВЁДЕР — САМ ПРЕДИКАТ

Перечень вёдер здесь НЕ выписан. Он берётся из того, что предикат напечатал: выписанный был бы вторым местом об одном предмете и разошёлся бы с предикатом ровно тогда, когда тот заведёт новое ведро, — то есть остался бы зелёным на ведре, о котором никто не спросил.

ЧЕГО ЭТОТ РАЗБОР НЕ СУДИТ

  • ИСТИННОСТЬ вёдер. Правильно ли предикат раскладывает вхождение по вёдрам — вопрос его собственной адъюдикации, и машинного предиката у него нет;
  • ПРОЗУ §0. Числа, названные прозой в тексте, здесь не ищутся: их формы столько же, сколько предложений, и разбор по образцу нашёл бы собственное объяснение. Судится ОБЪЯВЛЕНИЕ — блок, названный ревизией измерения.

seeded_service_accounts.go — разбор посева служебных учёток по цепочке миграций: вставка заводит строку, удаление её снимает.

Порт ОБЩЕГО вспомогательного разбора с монорепо (жил как package-private `seededSA`/`foldSeededServiceAccounts` в `internal/repohygiene/moduleserviceaccounthasacomponent_test.go`, снят вынесением службы — `kacho#2597`). Перенесён в НЕ-тестовый файл и экспортирован, потому что нужен как минимум ДВУМ гейтам монорепо: `moduleidentityseededonlybythebaseline` (перенесён этим же изменением, `module_identity_seeded_only_by_baseline.go`) и `moduleserviceaccounthasacomponent` (семейство, НЕ входящее в батч `kacho#2597` этого агента — предмета оно судит компоненты дерева, отдельная от «когда посеяно» ось). Держать разбор внутри теста значило бы, что следующий перенос его продублирует, не заметив: инструкция переноса прямо требует проверить, не появился ли общий помощник, и переиспользовать его — вместо копии.

subject_change_flush_parity.go — извлечение для гейта «полоса производителей очереди смены субъекта не пополняется МОЛЧА» (задача #17, порт-ПОЛОВИНА семейства `subjectchangeflushparity` с монорепо `internal/repohygiene/subjectchangeflushparity.go`, снятого выносом службы — `kacho#2597`).

───────────────────────────────────────────────────────────────────────────── ПРЕДМЕТ ПРЕДКА — ДВЕ ПОЛОСЫ ОДНОГО МЕХАНИЗМА, СВЕРЯЕМЫЕ МЕЖДУ СОБОЙ

Смена прав доезжает до кэша решений края ДВУМЯ независимыми полосами:

  • НЕМЕДЛЕННО, на реплике, обслужившей мутацию, — самосбросом по полному имени метода (набор `subjectChangingFQNs` у края);
  • С ЗАДЕРЖКОЙ, на соседних репликах, — через очередь смены субъекта (`kaname.subject_change_outbox`), которую край читает сам.

Полосы кормит ОДНО событие, но перечни у них РАЗНЫЕ и ведутся врозь. Заведя шестого производителя очереди, легко не вспомнить о самосбросе: соседние реплики сойдутся за интервал опроса, а та, что мутацию обслужила, продолжит отвечать по закешированному вердикту — то есть по ОТОЗВАННОМУ праву, и дольше всех именно там, где пользователь только что нажал «отозвать».

Заметить это по одной полосе нельзя: каждая исправна сама по себе. Предок поэтому спрашивал не «верен ли перечень» (это и есть спорный вопрос), а РЕШАЛ ЛИ КТО-НИБУДЬ, что полосы различаются.

───────────────────────────────────────────────────────────────────────────── ЧТО РАЗРЕЗ СДЕЛАЛ С ЭТИМ ГЕЙТОМ — СКАЗАНО ЧИСЛОМ, А НЕ ОГОВОРКОЙ

Полосы развело по РАЗНЫМ РЕПОЗИТОРИЯМ. Замер этого дерева (`61053691` плюс дифф этого изменения):

производители очереди   internal/apps/kaname/api            5  ЗДЕСЬ
набор самосброса        gateway/internal/middleware/authz.go 0  у края платформы

Предикат второй строки: `git grep -l subjectChangingFQNs` → 0; каталога `gateway` в составе этого дерева нет вовсе (`git ls-files gateway | wc -l` → 0).

Сверить полосы МЕЖДУ СОБОЙ отсюда нельзя, и обходить это чтением чужого репозитория с диска — НЕЛЬЗЯ ТЕМ БОЛЕЕ: вердикт стал бы свойством того, что случайно лежит в модульном кеше машины прогона, а не свойством коммита ни одного из двух деревьев. Тот же довод, по которому соседнее семейство (`subject_change_gap_detection_test.go`) судит два звена из трёх.

───────────────────────────────────────────────────────────────────────────── ЧТО ЭТА ПОЛОВИНА ДЕРЖИТ — И ЧЕГО ОНА НЕ ДЕРЖИТ

ДЕРЖИТ: полоса производителей не пополняется молча. Перечень объявлен в дереве, и гейт сверяет его с разбором. Шестой производитель делает вердикт красным, а правку перечня — ВИДИМОЙ В ДИФФЕ, где обзор и спрашивает: «а краю сказали?». Без этого добавление производителя не оставляет в этом репозитории следа ВООБЩЕ, и расхождение полос наступает молча.

НЕ ДЕРЖИТ: что край свой набор пополнил. Это утверждение о ЧУЖОМ дереве, и сделать его отсюда нечем. Объявленный здесь перечень — ОПЕРАНД для той стороны: пинить его вправе гейт платформы, потому что перечень отслеживается git и меняется только изменением.

Сказано прямо, потому что половина, выдающая себя за целое, хуже отсутствия: зелёный вердикт читался бы как «полосы сошлись».

───────────────────────────────────────────────────────────────────────────── СУДИТСЯ УЗЕЛ ОБРАЩЕНИЯ, А НЕ УЗЕЛ ВЫЗОВА — ЦЕНА ИЗМЕРЕНА ПРЕДКОМ

Обращений к методу в дереве ДВЕ формы, и обе законны:

w.AccessBindingsW().EmitSubjectChangeEvent(ctx, …)              // вызов на месте
fanout(ctx, …, w.AccessBindingsW().EmitSubjectChangeEvent, …)   // передан значением

Вторая появляется, когда строка пишется НА КАЖДОГО субъекта привязки общим развёртывателем: сам вызов уезжает в него, а производителем остаётся use-case, который метод отдал. Распознаватель, знавший только первую, объявлял вторую отсутствующей — не нарушением, а НЕВИДИМОСТЬЮ: два живых производителя пропадали из переписи. Поэтому судится `*ast.SelectorExpr`: узел вызова его содержит, поэтому обе формы считаются по разу и ни одна дважды.

В этом дереве вторая форма ЖИВАЯ — её несут `access_binding/delete.go` и `access_binding/revoke.go`, то есть два производителя из пяти. Слепота стоила бы ровно их.

system_role_row_is_never_deleted.go — разбор прод-кода kaname на предмет удаления строки СИСТЕМНОЙ роли (порт с монорепо `internal/repohygiene/systemrolerowisneverdeleted.go`, снят вынесением службы доступа — `kacho#2597`; решение `docs/engineering/architecture/role-withdrawal-is-a-mark.md`, задача продукта #1913).

Предмет

Роль, объявленная манифестом модуля, системная BY CONSTRUCTION: применитель ставит `IsSystem: true`, а `roles.is_system` вычисляется из `cluster_id`. Значит вопрос «как снять роль модуля» есть вопрос «что делает прод-код со строкой системной роли», и у него два взаимоисключающих ответа: удалить строку либо пометить её снятой. Линия выбрала ВТОРОЙ:

  1. **роль в работе не удалится вовсе.** Выдачи ссылаются на роль ключом `access_bindings_role_fk … ON DELETE RESTRICT`; удаление роли, за которой стоит хоть одна строка выдачи, отвергается `SQLSTATE 23503`;
  2. **если бы не отвергалось — три проекции уехали бы МОЛЧА**: селекторы правил, проекция глаголов и проекция объявленных сегментов;
  3. **отзыв перестал бы достигать ПРЕДЪЯВЛЕНИЯ наблюдаемо.** У снятой пометкой строки есть что читать на пути запроса; у удалённой читать нечего.

Что здесь считается находкой — ОДНА ось, и она про оператор

Оператор `DELETE` над таблицей `roles`, не сужённый на ПОЛЬЗОВАТЕЛЬСКУЮ роль. Сужение опознаётся в ДВУХ законных написаниях: `is_system = false` (и `NOT is_system`) — прямо по вычисляемой колонке; `cluster_id IS NULL` — по кластерному якорю, из которого она и вычисляется.

Ось судит СТРОКОВЫЙ ЛИТЕРАЛ узла разбора, а не текст файла: слово `DELETE` стоит и в комментариях, объясняющих сам запрет. Оператор отличается от ПРОЗЫ, цитирующей оператор, по ПРОДОЛЖЕНИЮ за именем таблицы (`WHERE`, `RETURNING`, `USING`, `;`, конец литерала) — привязки к началу строки недостаточно.

Что изменилось при переносе, а что осталось дословно

Изменилось: пакет (`repohygiene` → `check`), путь-константа (`iamGoPrefix = "services/iam/"` → обход всего дерева модуля без префикса, код лежит от корня). Осталось дословно: обе регулярки сужения и продолжения, форма распознавателя (`ScanRoleDeletes`), имя держателя `TestSystemRoleRowIsNeverDeleted`.

Чего разбор НЕ видит — названо, а не спрятано

  1. **миграции.** Каждая снимала роль удалением до решения — это СТАТУС-КВО, который решение и заменяет, а не находка сегодняшнего дерева;
  2. **каскад по чужому ключу.** Строка роли уезжает вместе со своим ярусом (аккаунт, проект). Для СИСТЕМНОЙ роли ярус — кластер;
  3. **запрос, собранный из кусков в рантайме** либо приехавший параметром.

terminal_refusal_wrapping.go — разбор для двух гейтов приёмки #2439: репозиторий операций попадает в use-case только ОБЁРНУТЫМ, и тексты отказа объявлены в одном месте.

Приёмка: `docs/engineering/acceptance/refusal-text-names-the-lane-that-can-retry.md`, сценарии KN-RTX-06 и KN-RTX-08.

Что предикат устанавливает, а что НЕТ — сказано здесь, а не в заголовке

Он устанавливает ОДНО: всякий сырой конструктор репозитория операций в прод-коде обёрнут надстройкой прямо на месте вызова. Всеобщности вида «всякий терминальный исход проходит надстройку» он НЕ устанавливает и не обязан: четвёртый писатель терминального исхода — реконсайлер осиротевших операций — идёт мимо контракта репозитория и вынесен исключением приёмки (§2.3).

Различие несущее. Две первые редакции приёмки были отвергнуты ровно за заголовок шире предиката: читатель пишет гейт по заголовку, а не по телу.

Почему разбор синтаксический, а не по подстроке

Имя конструктора встречается в комментариях — в этом дереве четыре вхождения, из которых настоящий вызов ОДИН. Проверка по подстроке краснела бы на собственном объяснении соседнего файла; разбор судит узел ВЫЗОВА.

token_claim_foreign_brand.go — разбор ИМЁН КЛЕЙМ выпущенного токена: не называет ли клеймо, которое читает предъявитель токена БЕЗ нашего исходного кода, чужой платформенный бренд (порт, СУЖЕННЫЙ ДО ОСИ А, с монорепо `internal/repohygiene/tokenclaimforeignbrand.go`, снят вынесением службы доступа — `kacho#2597`; задача продукта #2127, семейство приёмки IAM-SEV-NAME-05).

Предмет

Служба — самостоятельный продукт, ставящийся в чужом облаке. Норма разделения (решение владельца, kacho#2076): продукт наследует КОД, но не ИМЯ. Имя клейма читается оператором чужого облака без нашего исходного кода — достаточно раскодировать токен, — поэтому приставка имени клейма есть идентичность, а не код. Свой словарь — `kaname_`; чужой, платформенный — `kacho_`. `internal/domain/principal_claims.go` уже несёт три клейма формы `kaname_*` — предмет живой, не гипотетический.

Что здесь ПОРТИРОВАНО (ось А), а что НЕТ (ось Б) — сказано прямо

Монорепошный предок судил ДВЕ оси: А — имя клейма принадлежит своему словарю; Б — у имени из своего словаря нет двойника в чужом словаре НИГДЕ в отслеживаемом дереве, включая не-Go текст (посевные наборы, профиль развёртывания, собранные коллекции проб, клиентская страница). Здесь перенесена ТОЛЬКО ось А — разбор Go-кода по четырём позициям чеканки и чтения. Ось Б требует единого свода дерева kaname И его нынешних потребителей (документация арендатора, коллекции проб), который на дату переноса не собран в одном месте; расширение до неё — отдельная работа, не сделанная здесь умышленно, а не забытая молча.

Позиции, которые СУДЯТСЯ (перенесены дословно)

claims := map[string]any{"kacho_user_id": …}     ← ключ состава
pt, _ := claims["kacho_principal_type"].(string) ← чтение по имени
case "kacho_mfa_at":                             ← разбор по имени
verifiedClaim(vt, "kacho_principal_type")        ← имя передано вызовом

Чего разбор НЕ видит — названо, а не спрятано

  1. имя клейма, собранное из частей либо взятое переменной;
  2. приставка, отданная предикату (`strings.HasPrefix(k, "kacho_")`) — ось Б предка ловила и её; здесь эта форма вне наблюдения;
  3. не-Go текст.

token_claim_single_source.go — разбор мест, СОБИРАЮЩИХ состав утверждений выданного токена (порт с монорепо `internal/repohygiene/tokenclaimsinglesource.go`, снят вынесением службы доступа — `kacho#2597`; приёмка F2, сценарий F2-42, §2.11).

Предмет

Токен принципалу выдают ДВА пути: обратный вызов прежнего провайдера, пока он жив, и собственный эндпоинт (`internal/service/token_enrichment_own_lane.go`). Пока перечень утверждений и правила их вычисления живут у каждого свои, различие между ними НЕ ЯВЛЯЕТСЯ НИЧЬЕЙ НАХОДКОЙ: оно не выражено и потому не может покраснеть. Первая же правка одной стороны разойдётся с другой молча — у ПРИНЦИПАЛА, чей токен выдан не тем путём.

Что здесь считается СБОРКОЙ, а что ПОТРЕБЛЕНИЕМ

claims := map[string]any{"kaname_user_id": …, "kaname_account_id": …}  ← СБОРКА
return s.userTokenClaims(row, user, subject, hookCtx)                ← потребление

Потребителей должно быть МНОГО — они и есть цель: второй способ дойти до той же сборки, а не второй состав. Находкой является ВТОРАЯ СБОРКА.

Почему судится ИМЯ КЛЮЧА, а не тип отображения

Предмет — СЛОВАРЬ утверждений, поэтому место опознаётся по именам ключей, а тип значений в счёт не идёт.

Почему порог по числу ключей, а не «хоть один»

Префикс утверждений встречается и вне состава — им же названы метрики и поля контекста. Место, назвавшее один ключ, состава не объявляет.

Что изменилось при переносе, а что осталось дословно

Изменилось: пакет (`repohygiene` → `check`), путь-константа владельца (без префикса `services/iam/`). Осталось дословно: обе функции разбора, форма узла (составной литерал `map[string]…`, узел вызова), имя держателя `TestTokenClaimsAreAssembledInOnePlace`.

Чего разбор НЕ видит — названо, а не спрятано

  1. состав, собранный присваиваниями по одному ключу за раз;
  2. имя ключа, собранное из частей или взятое переменной;
  3. состав, объявленный в чужом языке.

withdrawal_producer_arrives_with_the_applier.go — разбор прод-дерева на СОГЛАСИЕ двух фактов: применитель ролей модуля приводится в действие, и производитель отзыва роли существует (порт с монорепо `internal/repohygiene/withdrawalproducerarriveswiththeapplier.go`, снят вынесением службы доступа — `kacho#2597`; задача продукта #1913).

Предмет

Сверка `moduleroles.Reconcile` объявляет вид расхождения `LiveNotDeclared` — «строка живёт, объявления у неё больше нет». Пока применитель НЕ приводится в действие в проде, отсутствие производителя снятия — остаток, а не дефект. Как только применитель начинают звать (`cmd/kaname/serve.go`, `moduleroles.NewApplier`, задача #1034/#2010 — В KANAME ЭТО УЖЕ ПРОИЗОШЛО), остаток становится дефектом, необратимым ДЛЯ АРЕНДАТОРА: роль, которую нельзя снять, живёт вечно, и право, выданное через неё, продолжает действовать после того, как модуль перестал её объявлять.

Что здесь считается находкой — ОДНО согласие, а не два запрета

Находка — состояние «применитель приводится в действие, производителя отзыва нет». Ни одна половина по отдельности находкой не является:

приводится в действие · производитель есть  → норма, работа сделана
приводится в действие · производителя нет   → НАХОДКА
не приводится        · производителя нет    → остаток
не приводится        · производитель есть   → норма, производитель приехал раньше

Обе половины судятся по УЗЛУ РАЗБОРА, а не по слову

«Применитель приводится в действие» — это ВЫЗОВ через импортированный пакет, а не упоминание его имени. «Производитель отзыва» — это оператор ЗАПИСИ над `roles`, ставящий пометку снятия В СПИСКЕ ПРИСВОЕНИЙ.

Что изменилось при переносе, а что осталось дословно

Изменилось: пакет (`repohygiene` → `check`), путь импорта применителя (без `services/iam/` — код лежит от корня модуля kaname: путь становится `github.com/PRO-Robotech/kaname/internal/apps/kaname/moduleroles`). Осталось дословно: обе регулярки, форма связывания импорта (по псевдониму, а не по последнему сегменту пути), различение узла разбора и узла-прозы, имя держателя `TestWithdrawalProducerArrivesWithTheApplier`.

Чего разбор НЕ видит — названо, а не спрятано

  1. миграцию как производителя (запрещена отдельным гейтом её же смысла);
  2. производителя вне дерева модуля;
  3. запрос, собранный из кусков в рантайме.

Index

Constants

View Source
const (
	// FormFieldLiteral — литерал прямо в поле `Payload`.
	FormFieldLiteral = "литерал-в-поле"
	// FormHelperDecl — объявление построителя `…Payload(…) map[string]any`.
	FormHelperDecl = "построитель"
	// FormIndexAssign — ключ, добавленный присваиванием по индексу.
	FormIndexAssign = "присваивание-по-индексу"
	// FormFieldIdent — `Payload: p`, где `p` собран выше в той же функции.
	FormFieldIdent = "имя-собранное-рядом"
	// FormHelperCall — ВЫЗОВ построителя в поле `Payload`. Ключей не несёт:
	// они судятся у объявления. Считается, чтобы вызов был виден переписи
	// учтённым, а не пропал между формами.
	FormHelperCall = "вызов-построителя"
	// FormOpaque — значение поля `Payload`, не сводящееся ни к одной форме.
	// Литеральным разбором НЕ судится; печатается числом.
	FormOpaque = "непрозрачное"
)

Формы построения нагрузки. Имена уезжают в перепись: раскладка по формам показывает, какая из них перестала встречаться, — а перестать она может и оттого, что разбор её больше не видит.

View Source
const (
	// CarriedOutcomeKept — оставлено как путь к прежнему контуру. ТОЛЬКО этот
	// исход требует предиката снятия.
	CarriedOutcomeKept = "оставлено"
	// CarriedOutcomeRemoved — снято.
	CarriedOutcomeRemoved = "снято"
	// CarriedOutcomeRewritten — переписано на наш идентификатор.
	CarriedOutcomeRewritten = "переписано"
	// CarriedOutcomeNotSubject — предметом не является.
	CarriedOutcomeNotSubject = "не предмет"
)

Закрытый словарь исходов.

View Source
const (
	// CensusMirrorTable / CensusEdgeTable — таблицы, чья совместная
	// упомянутость в ОДНОМ SQL-литерале и есть перепись покрытия: она
	// спрашивает про рёбра у строк зеркала, то есть квантифицирует по
	// множеству.
	CensusMirrorTable = "kaname.resource_mirror"
	CensusEdgeTable   = "kaname.resource_parent_edge"
	// RawEdgeWriteMarker — прямая запись рёбер в обход производителя.
	RawEdgeWriteMarker = "INSERT INTO kaname.resource_parent_edge"
	// EdgeProducerCall — имя экспортированной функции-производителя.
	EdgeProducerCall = "UpsertTx"
	// EdgeProducerDir — каталог пакета-производителя, ОТ КОРНЯ своего модуля
	// (было `services/iam/internal/repo/kaname/pg/resource_mirror`).
	EdgeProducerDir = "internal/repo/kaname/pg/resource_mirror"
	// EdgeProducerImport — хвост пути импорта. В самостоятельном модуле
	// службы совпадает с каталогом (расхождение, из-за которого монорепо
	// нёс ДВЕ константы, было следствием сегмента `services/iam`, которого
	// у своего модуля нет).
	EdgeProducerImport = EdgeProducerDir
)
View Source
const (
	// MigrationsDirRel — дом миграций службы.
	MigrationsDirRel = "internal/migrations"
	// AppliedModelRelPath — модель, которую ПРИМЕНЯЕТ решение о доступе.
	//
	// Каноническая копия (`proto/kaname/cloud/iam/v1/fga_model.fga`) сюда
	// намеренно НЕ подставляется: две копии держит байт-идентичными своя цель, а
	// разбор обязан читать ту, которая ИСПОЛНЯЕТСЯ.
	AppliedModelRelPath = "internal/authzmodel/fga_model.fga"
)
View Source
const (
	// IdentityGrowthCollectorFile — где объявлено семейство величин.
	IdentityGrowthCollectorFile = "internal/observability/metrics/identity_growth_collector.go"
	// IdentityGrowthReadersFile — где живут правила оповещений службы.
	IdentityGrowthReadersFile = "docs/engineering/components/32-observability.md"
)
View Source
const (
	// ResourceMirrorTable — зеркало каталога ресурсов.
	ResourceMirrorTable = "kaname.resource_mirror"
	// MirrorReferenceLane — каталог ЭТАЛОННОЙ полосы: путь, по которому
	// регистрация от владельца ресурса доходит до строки зеркала.
	//
	// Переедет каталог — гейт объявит ОТКАЗ, а не промолчит: сверять «тем же
	// условием» станет не с чем. Правь эту константу тем же изменением, каким
	// двигаешь пакет.
	MirrorReferenceLane = "internal/repo/kaname/pg/resource_mirror/"
)
View Source
const (
	AxisContract  = "контракт"
	AxisGoCode    = "прод-код"
	AxisCatalogue = "каталог видов"
	AxisModel     = "модель прав"
)

Названия осей. Вынесены константами, потому что их называет и инъекция: ось, переименованная в одном месте из двух, дала бы пробу, утверждающую о другой.

View Source
const (
	TokenClaimOwnNamespace     = "kaname"
	TokenClaimForeignNamespace = "kacho"
)

TokenClaimOwnNamespace / TokenClaimForeignNamespace — свой и чужой словарь.

View Source
const AcceptanceHistoryFloor = 2

AcceptanceHistoryFloor — глубина истории дома приёмок, ниже которой признак «правлено после вердикта» НЕВЫРАЗИМ.

Два коммита — минимум, при котором отметка строки состояния и отметка файла МОГУТ разойтись. При одном они равны у каждого документа, поэтому ветвь сравнения не исполняется ни разу, и её молчание не означает ничего.

View Source
const CatalogCheckTarget = "check-permission-catalog"

CatalogCheckTarget — имя цели Makefile, СВЕРЯЮЩЕЙ копии и ничего не пишущей. Ровно её обязан звать конвейер.

View Source
const CatalogLockKeyIdent = "CatalogLockKey"

CatalogLockKeyIdent — имя константы ключа.

View Source
const CatalogLockKeyValue = "kaname.module_catalog"

CatalogLockKeyValue — её значение (принимается и литералом).

View Source
const CatalogSyncTarget = "sync-permission-catalog"

CatalogSyncTarget — имя цели Makefile, ПЕРЕПИСЫВАЮЩЕЙ каталог прав из копии края. Ручная операция выпуска: конвейер её звать не вправе.

View Source
const DerivedIDPackage = "crypto/md5"

DerivedIDPackage — путь импорта, вычисляющий дайджест.

View Source
const EmitSubjectChangeSelector = "EmitSubjectChangeEvent"

EmitSubjectChangeSelector — имя метода порта, которым производится строка очереди смены субъекта.

View Source
const ExclusionEdgeStripHome = "PRO-Robotech/kacho:gateway/internal/principalmeta/credential_strip.go"

ExclusionEdgeStripHome — дерево и файл, где живёт ВТОРАЯ половина построения.

View Source
const ExclusionGuideRel = "INSTALL.md"

ExclusionGuideRel — страница установки: то, что читает оператор.

View Source
const ExclusionReaderDeclFileRel = "internal/presentedcred/reader.go"

ExclusionReaderDeclFileRel — файл, ОБЪЯВЛЯЮЩИЙ обёртку.

Его собственные определения вызовами не являются: объявление без вызывающего механизма не даёт — ровно тот класс, ради которого предок отделял объявление снятия от его вызовов.

View Source
const ExclusionReaderDirRel = "internal/presentedcred"

ExclusionReaderDirRel — не-тестовый код читателя предъявленного удостоверения.

View Source
const ExclusionRefuseFunc = "refuse"

ExclusionRefuseFunc — имя конструктора отказа читателя.

View Source
const FingerprintSourceRel = "services/iam/internal/repo/kaname/pg/scalegrid/fingerprint.go"

FingerprintSourceRel — объявление предмета замера, из которого ВЫВОДИТСЯ объём этого разбора.

Координата дана ОТ КОРНЯ ДЕРЕВА ПЛАТФОРМЫ, как и всё, что резолвится `treeposture`: приставка снимается самим резолвом, когда модуль стоит самостоятельным клоном. Своя, «модульная» форма здесь была бы вторым написанием одной координаты — а сам предмет замера объявляет каталоги именно в этой форме, и разбор обязан читать ту же.

View Source
const GeneratedStubsPrefix = "pkg/api/"

ScanClassRuleDeclarations — объявления правила «класс из имени» в одном исходнике, с координатой каждого.

Неразбираемый исходник отдаёт признак, а не пустой перечень: «объявлений ноль» иначе означало бы и «их нет», и «разбор не состоялся». GeneratedStubsPrefix — каталог сгенерированных стабов: правило, найденное там, принадлежало бы генератору, а не дереву.

View Source
const InstallGuideSuffix = "INSTALL.md"

exportCopyMarker — по чему строка документа опознаётся как процедура выгрузки. Это мета-команда оболочки psql, и в прозе она не встречается: у разбора нет риска принять за процедуру объяснение процедуры. InstallGuideSuffix — по чему инструкции обновления опознаются в составе дерева.

View Source
const JobsConfigTypeName = "JobsConfig"

JobsConfigTypeName — структура, чьи поля суть секции фоновых заданий.

View Source
const JobsSelectorName = "Jobs"

JobsSelectorName — поле, через которое корень добирается до секций.

View Source
const ManifestLoaderDir = "internal/manifest"

ManifestLoaderDir — прод-файлы загрузчика манифеста. Гейт читает их как ТЕКСТ дерева: импортировать пакет отсюда нельзя (правило видимости `internal` тут ни при чём — импорт завёл бы зависимость гейта от предмета, который он судит).

View Source
const MirrorDivergenceFunc = "Divergence"

MirrorDivergenceFunc — имя читателя, чей вызывающий здесь стережётся.

View Source
const MirrorDivergencePkgSuffix = "/repo/kaname/pg/resource_mirror"

MirrorDivergencePkgSuffix — хвост пути пакета-читателя разности.

View Source
const ModuleSetPkgRel = "internal/authzmap"

ModuleSetPkgRel — каталог пакета, объявляющего закрытую таблицу типов.

View Source
const ModuleSetVarName = "objectTypes"

ModuleSetVarName — имя переменной, чей составной литерал разбирается.

View Source
const RoleGrantOrphanTable = "kaname.role_grant_orphan"

RoleGrantOrphanTable — куда обязано переселяться снятое не-автором.

View Source
const RoleRuleRefTable = "kaname.role_rule_ref"

RoleRuleRefTable — вторая проекция того же объявления: каждый объявленный сегмент правила (kacho#1030). Предмет у таблиц разный, а требование к автору — одно.

View Source
const RoleRuleVerbsSentinel = "ErrRoleRuleVerbsRetired"

RoleRuleVerbsSentinel — имя сентинела, которым пред-разборная проверка отвергает снятый ключ. Объявлено ЗДЕСЬ, потому что гейт живёт в общем пакете, а сентинел — в `internal/manifest`, закрытом правилом видимости Go. Что имя не разошлось с продуктом, утверждает сам гейт: ноль возвратов на живом дереве — находка, а не молчание.

View Source
const RoleScopeChainTable = "resource_parent_edge"

RoleScopeChainTable — таблица звеньев цепи.

View Source
const RoleScopeChainType = "iam_role"

RoleScopeChainType — тип объекта модели прав, чью цепь областей стережёт гейт.

View Source
const RoleVerbTable = "kaname.role_verb"

RoleVerbTable — проекция «роль → тип объекта × глагол».

View Source
const RoleVerbWriterLayer = "/internal/repo/"

RoleVerbWriterLayer — слой, которому принадлежит SQL проекции. Писатель вне него — находка, даже если он один.

View Source
const SeedCensusFrozenBucket = "ПРЕДМЕТ: свод и миграции"

SeedCensusFrozenBucket — ведро, которому ноль НЕДОСТИЖИМ by construction: применённая миграция посеяла прежнее написание и правке не подлежит (ban #5), а переводящая обязана его назвать, чтобы найти строку.

Имя объявлено здесь ОДИН раз и сверяется с тем, что печатает предикат: ведро, переименованное у предиката и не переименованное здесь, дало бы «его нет», то есть отключило бы проверку ниже молча.

View Source
const SelfFlushSetHome = "PRO-Robotech/kacho:gateway/internal/middleware/authz.go"

SelfFlushSetHome — дерево и файл, где вторая полоса живёт.

View Source
const SelfFlushSetName = "subjectChangingFQNs"

SelfFlushSetName — имя набора самосброса У КРАЯ.

Объявлено здесь, хотя предмета в этом дереве нет: имя есть КООРДИНАТА второй полосы, и без неё текст находки не сказал бы читателю, куда идти. Пустой результат поиска по нему — не находка, а измеренное отсутствие второй стороны, и гейт называет его отдельной строкой переписи.

View Source
const SubjectChangeProducerRootRel = "internal/apps/kaname/api"

SubjectChangeProducerRootRel — каталог use-case владельца прав.

Каталог СЛОЯ, а не перечень файлов: слой — единица архитектуры службы, и он не стареет вместе с деревом. Переедет слой — обход опустеет, и гейт откажет, а не смолчит.

View Source
const TrunkBranch = "main"

TrunkBranch — ствол, чей вердикт остаётся без читателя.

View Source
const TrunkHolderJob = "trunkverdict"

TrunkHolderJob — идентификатор задания, которое его зовёт.

View Source
const TrunkHolderScript = ".github/scripts/trunk-verdict-holder.sh"

TrunkHolderScript — держатель вердикта ствола. ОДНО объявление координаты: вторая копия разошлась бы с первой молча.

View Source
const TrunkRegisterRel = ".github/TRUNK-VERDICT.md"

TrunkRegisterRel — дом перечня. ОДНО объявление координаты.

View Source
const UseCaseAPIRootRel = "internal/apps/kaname/api"

UseCaseAPIRootRel — дом пакетов use-case в дереве МОДУЛЯ.

View Source
const WithdrawalApplierImportPath = "github.com/PRO-Robotech/kaname/internal/apps/kaname/moduleroles"

WithdrawalApplierImportPath — пакет применителя ролей модуля.

View Source
const WorkflowsDirRel = ".github/workflows"

WorkflowsDirRel — дом заданий конвейера, единственный род носителей провязки в этом дереве.

Variables

View Source
var AcceptancePathCoordinateExemptions []DeadPathCoordinate

AcceptancePathCoordinateExemptions — ВЕДОМОСТЬ ПУСТА, и это её цель, а не её поломка. Заводя запись — назови номер задачи и предикат снятия рядом.

View Source
var AcceptanceProbeCoordinateExemptions []DeadProbeCoordinate

AcceptanceProbeCoordinateExemptions — ВЕДОМОСТЬ ПУСТА, и это её цель, а не её поломка. Заводя запись — назови номер задачи и предикат снятия в комментарии рядом.

View Source
var AuthorityResidueLedger = map[string]string{
	"quota_reader": "право читать действующие пределы; глаголы, его требовавшие, сняты " +
		"стадией S4, но само право ВЫДАНО применённой миграцией 0001_initial.sql " +
		"(4 строки + группа-получатель) и ТРЕБУЕТСЯ двумя записями каталога прав, " +
		"чья копия принадлежит краю платформы. Отзыв — новая миграция плюс перекат " +
		"служб на новый идентификатор модели; предмет заведён задачей kaname#59. " +
		"ПРЕДИКАТ СНЯТИЯ: объявления нет ни в одной копии модели — запись становится " +
		"находкой в тот же прогон",
}
View Source
var ErrEmptyTraversal = errors.New("обход пуст: прочитано ноль файлов")

ErrEmptyTraversal — обход не принёс НИ ОДНОГО файла.

Отдельная ошибка, а не просто текст: вызывающий вправе отличить «прочитано ноль» от «читать не удалось», и эти два исхода требуют разных действий — первый чинят предметом гейта, второй условиями прогона.

View Source
var ExclusionCoPresenceTerms = []string{"presented", "forwarded"}

ExclusionCoPresenceTerms — слова, которыми сообщение отказа называет СОЧЕТАНИЕ двух форм.

Требуются ВСЕ: отказ, назвавший одну форму, — про неё одну. Сообщения отказа читателя английские, поэтому и слова английские.

View Source
var ExclusionWrapFuncs = []string{"UnaryOver", "StreamOver"}

ExclusionWrapFuncs — имена, которыми читатель НАКРЫВАЕТ пару звеньев переданной личности. Обе полосы вызова: одиночная и потоковая.

View Source
var MirrorWriteVerbs = []struct {
	Verb       string
	Introduces bool
}{
	{"INSERT INTO " + ResourceMirrorTable, true},
	{"MERGE INTO " + ResourceMirrorTable, true},
	{"UPDATE " + ResourceMirrorTable, false},
	{"DELETE FROM " + ResourceMirrorTable, false},
}

MirrorWriteVerbs — глаголы записи. Чтение в перечень не входит намеренно: читателей у зеркала десятки, все законны, и они служат близнецом, на котором разбор обязан молчать.

Introduces — вводит ли оператор НОВУЮ строку. Предмет условия есть только у вводящих: правка существующей строки нового типа не заводит, а снятие тем более. Требовать сверки у них значило бы требовать её там, где сверять нечего.

View Source
var ModuleSetSurfaceExts = []string{".mdx", ".md", ".proto"}

ModuleSetSurfaceExts — расширения файлов поверхности.

View Source
var ModuleSetSurfaces = []string{"docs/content", "proto/kaname/cloud/iam"}

ModuleSetSurfaces — КЛИЕНТСКИЕ поверхности: то, что читает арендатор.

Инженерные записки (`docs/engineering`) сюда НЕ входят, и это решение, а не пропуск: их предмет — реализация, а не обещание клиенту. Шапка функции членства в монорепо чинилась руками ровно по этой границе.

View Source
var NamedVerbScenarios = []string{"04", "04a", "18", "18a", "19", "19a"}

NamedVerbScenarios — шесть сценариев, чья проверка полноты и есть содержание отсрочки. Перечень ЗАКРЫТ и выписан: он приезжает из приёмки `#1090`, а не из дерева, и выводить его неоткуда — проб этих сценариев в дереве ноль by construction, то есть вывод из дерева дал бы пустой перечень и гейт, которому нечего требовать.

View Source
var PathCoordinateHomeShape = regexp.MustCompile(
	`^([A-Za-z0-9][A-Za-z0-9._-]*/[A-Za-z0-9][A-Za-z0-9._-]*)(?:@([0-9a-fA-F]{7,40}))?$`)

PathCoordinateHomeShape — форма НАЗВАННОГО ДОМА: `<владелец>/<репозиторий>` и, необязательно, `@<ревизия>`. Ревизия только шестнадцатеричная и не короче семи знаков: произвольная строка после `@` сделала бы домом любую опечатку.

View Source
var ProbeCoordinateHomeShape = regexp.MustCompile(
	`^([A-Za-z0-9][A-Za-z0-9._-]*/[A-Za-z0-9][A-Za-z0-9._-]*)(?:@([0-9a-fA-F]{7,40}))?$`)

ProbeCoordinateHomeShape — форма НАЗВАННОГО ДОМА: `<владелец>/<репозиторий>` и, необязательно, `@<ревизия>`. Ревизия — только шестнадцатеричная и не короче семи знаков: короткая или произвольная строка после `@` сделала бы домом любую опечатку.

View Source
var ProbeCoordinateShape = regexp.MustCompile(`^(Test|Fuzz|Benchmark|Example)[A-Za-z0-9_]{2,}$`)

ProbeCoordinateShape — форма имени пробы Go. Три знака минимум после вида: голое `Test` резолвилось бы префиксом ко всему дереву.

View Source
var RoleProjectionTables = []string{RoleVerbTable, RoleRuleRefTable}

RoleProjectionTables — таблицы, у каждой из которых автор обязан быть один.

View Source
var RoleScopeChainTierSources = []string{"account_id", "project_id"}

RoleScopeChainTierSources — ярусные столбцы, из которых звено роли берётся ЗАКОННО. Перечень закрытый и короткий by construction.

Functions

func AcceptanceDocsOfTree added in v0.2.0

func AcceptanceDocsOfTree(root string) (map[string]string, error)

AcceptanceDocsOfTree — приёмки, живущие в каталоге приёмок службы. Перечень ВЫВОДИТСЯ обходом, а не выписывается.

Порт сужен до posture этого дерева: монорепо держало приёмки НЕСКОЛЬКИХ служб под `services/*/docs/engineering/acceptance/`, а самостоятельный клон службы несёт СВОЙ единственный каталог прямо у корня — `docs/engineering/acceptance/`. Сужение измерено, а не предположено: в дереве продукта второго дома приёмок не было никогда (§«У приёмки домов ДВА» — второй дом был именно этот, iam-only).

func AdjudicateCarriedLedger added in v0.2.0

func AdjudicateCarriedLedger(
	ledgerPath string,
	rows []CarriedLedgerRow,
	sections map[string]CarriedLedgerSection,
	treeHas func(string) bool,
	inScope func(string) bool,
	mustBeNamed []string,
) []string

AdjudicateCarriedLedger — что не так с ведомостью относительно дерева.

treeHas — состав дерева; inScope — координата принадлежит СВОЕМУ репозиторию и подлежит суждению (кросс-репо путь пропускается обеими проверками — ни полнотой, ни самоистечением: этот гейт не может судить чужой репозиторий); mustBeNamed — координаты, которые ведомость обязана назвать.

func AdjudicateSeedCensus added in v0.3.0

func AdjudicateSeedCensus(decl SeedCensusDeclaration, rep SeedCensusReport) []string

AdjudicateSeedCensus сверяет объявленное с произведённым ПО КАЖДОМУ ведру предиката. Ведро, которое предикат напечатал, а объявление не называет, — находка: иначе новое ведро уехало бы из-под наблюдения молча.

ВТОРАЯ ПОЛОВИНА — АНТИМАСКА, И БЕЗ НЕЁ ПЕРВАЯ НИЧЕГО НЕ СТОИТ

Предикат готовности перехода (§7-П2 приёмки) звучит «живое ведро даёт ноль». Ноль там наступает ДВУМЯ путями, и они неотличимы по самому числу: переход состоялся — либо обход ослеп (литерал переписан, популяция сузилась, ревизия не та). Поэтому здесь проверяется ВТОРАЯ величина: замёрзшее ведро обязано быть НЕПУСТЫМ. Оно доказывает, что обход всё ещё находит написание там, где ban #5 держит его вечно, — то есть что ноль живого есть вердикт, а не молчание прибора.

func AlertExpressionsIn added in v0.3.0

func AlertExpressionsIn(doc string) []string

AlertExpressionsIn — тела выражений `expr:` правил оповещения.

Берётся ТОЛЬКО исполняемая часть: однострочное выражение целиком либо блок, введённый `|`, до первого поля того же или меньшего отступа. Комментарии снимаются — иначе имя ряда, УБРАННОГО из выражения и оставшегося в объяснении, продолжало бы считаться читателем.

func ApplierPortVerbDeletesTheRoleRow added in v0.2.0

func ApplierPortVerbDeletesTheRoleRow(name string) (bool, string)

ApplierPortVerbDeletesTheRoleRow — предикат оси 1: удаляет ли метод порта СТРОКУ РОЛИ. Второе значение — почему, дословно для текста находки.

func AuditAcceptanceEditsAfterVerdict added in v0.2.0

func AuditAcceptanceEditsAfterVerdict(root, dir string) ([]AcceptanceEditFinding, AcceptanceEditCensus, error)

AuditAcceptanceEditsAfterVerdict — вердикт о доме приёмок.

func AuditDeferredWork added in v0.3.0

func AuditDeferredWork(root string) (
	findings []treehygiene.DeferralFinding, census treehygiene.DeferralCensus, err error)

AuditDeferredWork обходит дерево под root общим разбором фундамента, связав его с видами вычитания ЭТОГО дерева.

Связывание живёт здесь, в ОДНОМ месте, и это несущее: инъекция обязана гонять ту же функцию, что гейт. Раздай мы виды по вызывающим — каждая проба связывала бы их заново, и доказанной оказалась бы не та связка, которая судит дерево.

Возвращает находки и перепись осмотренного: «ноль находок» обязано быть отличимо и от «ноль прочитанного», и от «прочитал не там». Вердикт — падать ли и с каким текстом — выносит гейт: текст отказа обязан называть исходы, принятые в ЭТОМ дереве.

func AuditExclusionForm added in v0.3.0

func AuditMachineryClaims added in v0.3.0

func AuditMachineryClaims(f MachineryFacts) ([]MachineryClaim, MachineryCensus)

AuditMachineryClaims — заявления комментариев контрактов, которым в дереве нечего назвать. Пусто = норма.

Возвращает находки и перепись раздельно: перепись — самостоятельное утверждение, и пустой обход обязан быть отличим от чистого дерева.

func AuditNamedInjections

func AuditNamedInjections(root string) ([]InjectionFinding, InjectionCensus, error)

AuditNamedInjections обходит дерево модуля от root и возвращает находки с переписью.

Обращения к пробе здесь нет намеренно: разбор, роняющий её изнутри, инъекции не поддаётся — синтетическому дереву некуда было бы подать вход.

func AuditPayloadForms added in v0.3.0

func AuditPayloadForms() []struct {
	Name    string
	Why     string
	Example string
}

AuditPayloadForms — объявленные формы с примерами; гейт предъявляет каждую.

func AuditRoleOperationResponseState added in v0.2.0

AuditRoleOperationResponseState выносит вердикт о дереве.

func AuthorVerbOf added in v0.2.0

func AuthorVerbOf(table string) string

AuthorVerbOf — оператор, которым строка ВНОСИТСЯ.

func BaselineMigrationOf added in v0.2.0

func BaselineMigrationOf(ordered []string) string

BaselineMigrationOf — применённая базовая миграция: первая в порядке применения. Порядок goose лексикографический, поэтому перечень уже отсортирован вызывающим.

func CallsMakeTarget added in v0.2.0

func CallsMakeTarget(body, target string) bool

CallsMakeTarget — исполняемое тело шага (`run:` без строк оболочечных комментариев) зовёт названную цель формой `make <цель>` либо `make -C <каталог> <цель>` (в этом репозитории цель лежит в корневом Makefile, поэтому `-C` без аргумента либо `-C .` — тоже законная форма).

func CollectPredicateConcats added in v0.3.0

func CollectPredicateConcats(files []ReadPathFile, read func(abs string) ([]byte, error)) (
	[]ConcatFinding, ConcatCensus, error,
)

CollectPredicateConcats — находки и объём по перечню файлов.

read подаётся вызывающим: инъекция кормит разбор синтетикой, не трогая диск.

func ConstStringValue added in v0.2.0

func ConstStringValue(src []byte, name string) (string, bool, error)

ConstStringValue — значение строковой константы, объявленной в исходнике.

Возвращает признак находки отдельно от значения: «объявления нет» и «объявлено пустым» — разные состояния, и схлопывать их нельзя.

func CountRelations added in v0.3.0

func CountRelations(m map[string]map[string]bool) int

CountRelations — сколько отношений объявлено всего.

func DeclaredContexts added in v0.4.0

func DeclaredContexts(raw string, trunkProcesses []string) []string

DeclaredContexts — обязательные контексты, ОБЪЯВЛЕННЫЕ перечнем (первая колонка таблицы контекстов).

Живут они не в дереве, а в настройках ветки, поэтому перечень их копирует — и копия обязана быть сверяема. Сверку делает вызывающий (это сеть), а не эта функция; здесь — только то, что объявлено.

func DeclaredProbesOfTree added in v0.2.0

func DeclaredProbesOfTree(root string) ([]string, error)

DeclaredProbesOfTree — имена всех проб дерева, объявленных в отслеживаемых файлах проб.

func DeclaresSelfFlushSet added in v0.3.0

func DeclaresSelfFlushSet(rel, src string) (bool, error)

DeclaresSelfFlushSet — ОБЪЯВЛЯЕТ ли файл набор самосброса.

Судится УЗЕЛ ОБЪЯВЛЕНИЯ, а не вхождение имени, и это не педантизм — цена измерена на самом гейте. Первая редакция искала имя ПОДСТРОКОЙ по всем файлам Go и на первом же прогоне после посадки нашла… собственное объявление координаты второй полосы (`SelfFlushSetName = "subjectChangingFQNs"` строкой выше). То есть проверка покраснела на своём же объяснении и объявила, что вторая полоса приехала в это дерево, — ровно тот класс, что ловит проверку, судящую СЛОВО вместо УЗЛА.

Узел снимает это by construction: строковый литерал, имя типа, комментарий и сообщение об отказе объявлением не являются, а `var subjectChangingFQNs = …` является — и только оно.

func DeferralSkips added in v0.3.0

func DeferralSkips() []treehygiene.DeferralSkip

DeferralSkips — объявленные виды вычитания; гейт сверяет их предмет.

Отдаётся копия перечня: он есть предмет пробы, и проба не вправе его двигать.

func ExecutableRunBodies added in v0.2.0

func ExecutableRunBodies(raw string) ([]string, int, error)

ExecutableRunBodies — тела `run:` без строк оболочечных комментариев.

func FoldSeededServiceAccounts added in v0.2.0

func FoldSeededServiceAccounts(ordered []string, bodies map[string]string) (
	alive map[string]SeededServiceAccount, unknownForms []string, stmtsTouched int,
)

FoldSeededServiceAccounts складывает посев по цепочке: вставка заводит строку, удаление её снимает. Возвращает живые строки, находки формы и объём осмотренного.

Формы записи названы ЯВНО, и незнакомая — находка, а не молчание: форма, о которой разбор не знает, уводит предмет из-под наблюдения, ничего не нарушив (§«Гейт на класс» п. 7).

Разбор НЕ понимает PL/pgSQL-блоков `DO $$ ... $$` — наивное деление на `;` внутри такого блока даёт много фрагментов, большинство отбрасываются (не называют таблицу или несут не INSERT/UPDATE/DELETE), но статический `DELETE FROM kaname.service_accounts WHERE name IN (...)` внутри такого блока распознаётся корректно, потому что сам оператор синтаксически цел между соседними `;`. Динамическое снятие через переменную (`WHERE name = ANY(var)`) разбором НЕ узнаётся — это названо явно шапкой такой миграции продукта (`20260909202745_module_identities_leave_the_baseline.sql`): имена стоят литералами в статическом операторе именно для того, чтобы этот разбор их видел.

func HasModuleSetSurfaceExt added in v0.3.0

func HasModuleSetSurfaceExt(rel string) bool

HasModuleSetSurfaceExt — файл поверхности ли это.

func HomeEnvVar added in v0.3.0

func HomeEnvVar(identity string) string

HomeEnvVar — имя переменной, которой оператор называет копию дома явно.

func HomeRef added in v0.3.0

func HomeRef(dir, rev string) (string, string)

HomeRef — ссылка, по которой судится дом. Ствол, если ревизия не названа.

func HomeTree added in v0.3.0

func HomeTree(ownRoot, identity string) (string, string)

HomeTree — (путь, причина). Пустой путь означает: дома нет, и это ТРЕТЬЯ категория, а не вердикт о документе.

func IdentityGrowthMetricNamesIn added in v0.3.0

func IdentityGrowthMetricNamesIn(src string) []string

IdentityGrowthMetricNamesIn — имена рядов в исходнике коллектора.

Комментарии снимаются первыми: файл коллектора подробно объясняет, почему рядов два, и называет их имена в прозе. Разбор сырого текста засчитал бы объявлением упоминание в разборе.

func InvocationsOf added in v0.2.0

func InvocationsOf(script string, bodies []string) int

InvocationsOf — сколько тел `run:` действительно зовут названный скрипт.

func IsGeneratedFile added in v0.2.0

func IsGeneratedFile(f *ast.File) bool

IsGeneratedFile — узел разбора несёт отметку `Code generated … DO NOT EDIT.`

func IsModuleSetSurfaceFile added in v0.4.0

func IsModuleSetSurfaceFile(rel string) bool

IsModuleSetSurfaceFile — лежит ли файл на КЛИЕНТСКОЙ ПОВЕРХНОСТИ, перечни которой сверяются с набором.

func IsSubjectChangeProducerFile added in v0.3.0

func IsSubjectChangeProducerFile(rel string) bool

func IsVerbClassRuleSource added in v0.4.0

func IsVerbClassRuleSource(rel string) bool

IsVerbClassRuleSource — файл, в котором правило «класс глагола» вправе быть объявлено. Тестовый корпус вычитается намеренно: фикстура инъекции обязана уметь написать форму дефекта, иначе гейт нельзя проверить.

func JoinGrants added in v0.3.0

func JoinGrants(g []RelationGrant) string

JoinGrants — различные пары «тип#отношение», по порядку.

func JoinRelationSet added in v0.3.0

func JoinRelationSet(m map[string]bool) string

JoinRelationSet — отношения одного типа, по порядку.

func JudgeAuthorityResidue added in v0.3.0

func JudgeAuthorityResidue(corpus, excused map[string]string) (AuthorityResidueCensus, []AuthorityResidueFinding)

JudgeAuthorityResidue судит корпус: ключ — путь в дереве, значение — текст.

excused — ведомость отношений модели, чьё снятие объявлено чужим предметом (`AuthorityResidueLedger`). Передаётся ПАРАМЕТРОМ, а не берётся из пакета: инъекция подаёт сюда синтетику, и судья, ходящий за ведомостью сам, на ней бы не работал. Сверка идёт в ОБЕ стороны — отношение вне ведомости есть находка, запись ведомости без предмета есть находка тоже.

Вид оси выбирается по имени файла: `.go` (не `_test.go`) — прод-код, `.proto` — контракт, `.fga` — модель прав. Файл, не попавший ни под одну, не читается вовсе и в перепись не идёт: молчание о нём честнее, чем ноль.

Возвращает перепись и находки; находок ноль при непустой переписи — годно.

func JudgeCensusFixtures added in v0.2.0

func JudgeCensusFixtures(byDir map[string][]CensusFileFacts) []string

JudgeCensusFixtures выносит вердикт по КАТАЛОГАМ: ключ — каталог тестового пакета, значение — факты его файлов.

func JudgeTargetWiringFaults added in v0.3.0

func JudgeTargetWiringFaults(w JudgeTargetWiring) []string

JudgeTargetWiringFaults — находки по ОБЕИМ сторонам провязки.

Сверка идёт в обе стороны намеренно. Односторонняя («объявлена — обязана быть звана») пропускала бы обратный случай: носитель зовёт цель, которой рецепт не объявляет, — шаг молча зеленеет на несуществующей цели, потому что `make` такого имени не знает и... отказывает; а под `|| true` или в подстановке не отказывает вовсе. Это провязка в пустоту, и она хуже отсутствующей: выглядит исполненной.

func MakefileDeclaresTarget added in v0.2.0

func MakefileDeclaresTarget(makefile, target string) bool

MakefileDeclaresTarget — объявлена ли цель в тексте Makefile.

func MissingGrantedRelations added in v0.3.0

func MissingGrantedRelations(grants []RelationGrant, model map[string]map[string]bool) []string

MissingGrantedRelations — выдачи, у которых в модели нет типа либо отношения.

func MissingScenarioProbes added in v0.2.0

func MissingScenarioProbes(funcNames []string) []string

MissingScenarioProbes — сценарии из закрытого перечня, у которых в дереве нет ни одной пробы.

Принимается перечень ИМЁН функций, а не текст файлов: подстрока `TestMODRL04` стои́т и внутри `TestMODRL04a`, и гейт, судящий вхождение, зачёл бы одну пробу за две. Имя сравнивается с ПРЕФИКСОМ и следующим за ним символом.

func ModuleIdentitiesSeededOutsideTheBaseline added in v0.2.0

func ModuleIdentitiesSeededOutsideTheBaseline(alive map[string]SeededServiceAccount, baseline string) []string

ModuleIdentitiesSeededOutsideTheBaseline — судья, отделённый от дерева ради инъекции. Находка — живая МОДУЛЬНАЯ учётка, чью строку завела не базовая миграция.

func NamedVerbFormFinding added in v0.2.0

func NamedVerbFormFinding(sentinelReturns int, probeNames []string) []string

NamedVerbFormFinding — РЕШЕНИЕ гейта одной функцией: сценарии, оставшиеся без пробы, когда форма уже не отвергается.

Объявлено здесь, а не внутри гейта, ровно затем, чтобы инъекция гоняла ТОТ ЖЕ предикат, что и прогон дерева: второй, написанный в пробе «по образцу», разошёлся бы с первым молча — и разошёлся бы именно там, где расхождение не видно, потому что оба отвечают одинаково на сегодняшнем входе.

Пустой результат означает молчание, и у него ДВЕ законные причины: форма отвергается (`sentinelReturns > 0`) либо она вернулась вместе со своей проверкой (пробы найдены). Различать их вызывающему не нужно — обе законны.

func OutsideTraversal added in v0.4.0

func OutsideTraversal(rel string) bool

OutsideTraversal — путь ВНЕ области обхода: система контроля версий, оснастка агента, документация, вендоренное и артефакты сборки.

Предикат один на дерево и объявлен здесь: прежде он жил в файле пробы соседнего семейства, и всякий следующий обход либо звал чужую пробу, либо заводил свою копию перечня. Копии перечня расходятся молча — и расходится та, которую не считали.

func OwnHomeOfTree added in v0.2.0

func OwnHomeOfTree(root string) (string, error)

OwnHomeOfTree — дом ЭТОГО дерева в форме `владелец/репозиторий`, выведенный из пути модуля в `go.mod`.

Нужен НЕ ядру, а гейту: ядро судит поданные значения и про дома знает только то, что дом непустой — чужой. Свой дом, названный в приёмке чужим, ядру неотличим от настоящего чужого, и именно эту дыру закрывает сторожевая ось гейта — она сверяет перепись домов с этим значением.

Путь модуля берётся у `go.mod`, а не собирается литералом: литерал разошёлся бы с переименованием репозитория молча.

func ParseCarriedCoordinateLedger added in v0.2.0

func ParseCarriedCoordinateLedger(body string) (
	[]CarriedLedgerRow, map[string]CarriedLedgerSection, CarriedLedgerCensus,
)

ParseCarriedCoordinateLedger разбирает ведомость.

func PathCoordinatesIn added in v0.4.0

func PathCoordinatesIn(doc, body string) ([]PathCoordinate, PathScanBorders)

PathCoordinatesIn разбирает документ: возвращает СУДИМЫЕ координаты и то, что разбор видел, но судить не стал.

func PathSpecResolves added in v0.4.0

func PathSpecResolves(spec string, dirs map[string]bool) bool

PathSpecResolves — путь-спецификация резолвится, когда в дереве есть её ГЛУБОЧАЙШИЙ ПРЕДОК БЕЗ МЕТАСИМВОЛА.

Судится каталог, а не соответствие шаблону: шаблон, которому сегодня не соответствует ничто, есть законный вердикт, а не мёртвый адрес.

func ProbeCoordinateResolves added in v0.2.0

func ProbeCoordinateResolves(name string, declared []string) bool

ProbeCoordinateResolves — объявленное имя начинается с координаты. declared обязан быть отсортирован: имя с префиксом P сортируется не раньше P, поэтому кандидат ровно один и находится двоичным поиском.

func ProbeDeclaredInHome added in v0.3.0

func ProbeDeclaredInHome(dir, ref, name string) bool

ProbeDeclaredInHome — объявлена ли проба в названном доме на названной ссылке.

func ProdGoRoots added in v0.2.0

func ProdGoRoots(root string, tracked []string) ([]string, error)

ProdGoRoots — верхнеуровневые каталоги дерева, несущие отслеживаемый не-тестовый Go-код. Выведены обходом, а не выписаны.

func ProductionGoFile added in v0.4.0

func ProductionGoFile(rel string) bool

ProductionGoFile — не-тестовый файл Go внутри области обхода.

Отбор, который в этом дереве повторяется чаще прочих. Объявлен один раз по той же причине, что и `OutsideTraversal`: три копии «`.go`, не `_test.go`, не служебный каталог» разошлись бы на первом же новом исключении.

func PushesToTrunk added in v0.4.0

func PushesToTrunk(raw string) (bool, string, error)

PushesToTrunk — идёт ли процесс по `push` в ствол.

func RelationsByType added in v0.3.0

func RelationsByType(text string) map[string]map[string]bool

RelationsByType — разбор DSL модели: тип → множество объявленных отношений.

Предикаты построчные и СТРОГИЕ: объявление типа занимает строку целиком, а объявление отношения начинается с ключевого слова. Готовая форма модели в JSON под эти строки не подпадает ни одной строкой.

func RemovalVerbsOf added in v0.2.0

func RemovalVerbsOf(table string) []string

RemovalVerbsOf — операторы, которыми строка СНИМАЕТСЯ либо правится.

Чтение (`SELECT … FROM`, `JOIN`) в перечень не входит намеренно: читатели у проекции законны и служат близнецом, на котором гейт молчит.

func RepoIdentity added in v0.3.0

func RepoIdentity(dir string) string

RepoIdentity — идентичность рабочей копии: `owner/name` из `origin`. Пустая строка означает, что идентичность непроверяема.

func SQLCreateTableBody added in v0.2.0

func SQLCreateTableBody(upSection, table string) string

SQLCreateTableBody — тело объявления таблицы, разобранное из НАКАТА (Up-секции без комментариев) миграции. sqlText — полный текст ФАЙЛА миграции (порт зовёт `migrations.MigrationUpSection` сам, чтобы не тянуть зависимость на пакет `migrations` из пакета `check` без нужды — вызывающий подаёт уже подготовленный текст наката).

func ScanApplierDeletes added in v0.2.0

func ScanApplierDeletes(path string, src []byte) (sites []ApplierDeleteSite, census ApplierDeleteCensus, err error)

ScanApplierDeletes разбирает один файл пакета применителя.

func ScanAuditPayloads added in v0.3.0

func ScanAuditPayloads(root string) (findings []AuditPayloadFinding, census AuditPayloadCensus, err error)

ScanAuditPayloads обходит ОТСЛЕЖИВАЕМОЕ дерево модуля и находит личные ключи в нагрузках журнала аудита.

Состав берётся из индекса git, а не выписывается: каталог, заведённый завтра, попадает под гейт в день появления.

func ScanCatalogWriteLocking added in v0.2.0

func ScanCatalogWriteLocking(files []CatalogSource) ([]CatalogWriteFinding, CatalogWriteCensus, error)

ScanCatalogWriteLocking разбирает состав прод-файлов и отвечает, какие единицы пишут строки каталога, не запирая его. Файлы группируются ПО ПАКЕТУ (каталогу).

func ScanClaimAssemblies added in v0.2.0

func ScanClaimAssemblies(path string, src []byte, prefix string, minKeys int) (
	[]ClaimAssembly, ClaimAssemblyCensus, error,
)

ScanClaimAssemblies разбирает один файл и собирает места сборки состава.

prefix — префикс имени ключа состава; minKeys — сколько РАЗНЫХ ключей делают место сборкой.

func ScanClaimBuilderCalls added in v0.2.0

func ScanClaimBuilderCalls(path string, src []byte, builders map[string]bool) (
	[]ClaimBuilderCall, ClaimAssemblyCensus, error,
)

ScanClaimBuilderCalls разбирает один файл и собирает вызовы сборщиков состава.

func ScanClassRuleDeclarations added in v0.3.0

func ScanClassRuleDeclarations(rel string, src []byte) ([]string, error)

func ScanDerivedIDDeclarations added in v0.2.0

func ScanDerivedIDDeclarations(path string, src []byte) (sites []DerivedIDImportSite, census DerivedIDCensus, err error)

ScanDerivedIDDeclarations разбирает один файл и возвращает импорты `crypto/md5` вместе с объёмом осмотренного.

func ScanFixedRefusalTexts

func ScanFixedRefusalTexts(root string, files []string) (RefusalTextCensus, []RefusalTextFinding, error)

ScanFixedRefusalTexts разбирает названные файлы и называет конструкции статуса на полосах чужой причины, чей текст не доказан фиксированным.

root служит только для печати координат. Пустой обход ошибкой ЗДЕСЬ не объявляется: пустоту судит вызывающий — у гейта дерева и у пробы инъекции законные пороги пустоты разные.

func ScanHistoryQuestions added in v0.3.0

func ScanHistoryQuestions(corpus map[string][]byte, trunkRefs []string) ([]HistoryQuestion, HistoryCensus)

ScanHistoryQuestions — все вопросы об истории в названном корпусе.

Корпус приходит ГОТОВЫМ (`rel -> содержимое`), а не читается отсюда: так инъекция подаёт разбору свой вход, не заводя второго читателя дерева.

trunkRefs — имена, которые в этом дереве ОБЪЯВЛЕНЫ стволом. Перечень — параметр, а не константа: иначе ось «ствол назван» нечем подать синтетике, и она осталась бы без доказательства падучести.

func ScanKeyAlgorithmConstraints added in v0.3.0

func ScanKeyAlgorithmConstraints(path, upSection, column string) (
	found []AlgorithmConstraint, dropped []string, census AlgorithmDictionaryCensus,
)

ScanKeyAlgorithmConstraints разбирает один файл миграции.

column — имя столбца, чей словарь стережётся.

func ScanMigrationRoleInserts added in v0.3.0

func ScanMigrationRoleInserts(path string, src []byte) (sites []MigrationRoleSite, census MigrationRoleCensus)

ScanMigrationRoleInserts извлекает имена ролей, вставляемых миграцией.

Блок — от `INSERT INTO kaname.roles` до первой строки, оканчивающейся `;`. Привязка к блоку обязательна: тот же образец идентификатора встречается во вставках в ЧУЖИЕ таблицы (селекторы, выдачи служебным учёткам), и предикат без привязки мерил бы упоминания идентификатора, а не строки роли.

Форм записи имени ДВЕ, и обе законны

… VALUES ('rol' || substr(md5('iam.account.admin'),1,17), …, 'iam.account.admin', …)
INSERT INTO kaname.roles (id, account_id, name, …) VALUES ('rol6307…', NULL, 'iam.account.admin', …)

Первая — рукописная: идентификатор ВЫВОДИТСЯ из имени, поэтому имя стоит аргументом деривации и берётся оттуда. Вторая пришла со сводом миграций iam 2026-09-04: свод написан `pg_dump`, тот подставляет уже вычисленный идентификатор и перечисляет колонки явно — деривации в нём нет НИ ОДНОЙ, и разбор, знавший только её, извлекал ноль имён при 48 блоках. Это не находка и не молчание, а невидимость: каждая вставленная роль оказалась вне наблюдения.

Вторая форма читается по ПЕРЕЧНЮ КОЛОНОК, а не по позиции: позиция колонки `name` в дампе не гарантирована ничем, кроме самого перечня, и выписать её числом значило бы завести второе место об одном предмете.

Блок, из которого имя извлечь не удалось, считается ОТДЕЛЬНО (MigrationRoleCensus.Unreadable) и молча не пропускается: неизвестная форма обязана быть видна, иначе следующая сделает то же, что сделал дамп.

func ScanModuleSetEnumerations added in v0.3.0

func ScanModuleSetEnumerations(rel, body string, modules []string) ([]ModuleSetFinding, ModuleSetScan)

func ScanObjectTypeUses added in v0.3.0

func ScanObjectTypeUses(rel string, src []byte) (reads int, writes []string, err error)

ScanObjectTypeUses — сколько раз поле типа объекта ЧИТАЕТСЯ и где ему ПРИСВАИВАЮТ.

Обе величины вместе: «присваиваний ноль» при нуле чтений означает, что распознаватель не видит поля вовсе, и тогда вердикт о присваиваниях не значит ничего.

func ScanRawOperationsRepo added in v0.3.0

func ScanRawOperationsRepo(root string) ([]RawOperationsRepoSite, TerminalRefusalCensus, error)

ScanRawOperationsRepo обходит отслеживаемое дерево и находит вызовы сырого конструктора репозитория операций, отмечая обёрнутые.

func ScanRoleDeletes added in v0.2.0

func ScanRoleDeletes(path string, src []byte) (sites []RoleDeleteSite, census RoleDeleteCensus, err error)

ScanRoleDeletes разбирает один файл Go.

func ScanRoleScopeChain added in v0.2.0

func ScanRoleScopeChain(path, src string) (found []RoleScopeChainSite, census RoleScopeChainCensus)

ScanRoleScopeChain разбирает один файл — SQL миграции либо прод-исходник Go.

func ScanRoleWithdrawalWiring added in v0.2.0

func ScanRoleWithdrawalWiring(path string, src []byte) (drive, mark []RoleWithdrawalSite, census RoleWithdrawalCensus, err error)

ScanRoleWithdrawalWiring разбирает один файл Go.

Возвращает две половины раздельно — приведение применителя в действие и производителя отзыва, — потому что находка есть их НЕСОГЛАСИЕ, а не любая из них. Сводит половины вызывающий.

func ScanSQLUpdates added in v0.2.0

func ScanSQLUpdates(path string, src []byte, tables []string) ([]SQLUpdate, SQLUpdateCensus, error)

ScanSQLUpdates разбирает один файл и собирает операторы правки названных таблиц.

func ScanTokenClaimForeignBrand added in v0.2.0

func ScanTokenClaimForeignBrand(path string, src []byte) ([]TokenClaimUse, TokenClaimCensus, error)

ScanTokenClaimForeignBrand разбирает один файл Go и возвращает употребления имени клейма из ЧУЖОГО словаря (namespace == TokenClaimForeignNamespace) в одной из четырёх законных позиций чеканки/чтения.

func ScenarioProbeName added in v0.2.0

func ScenarioProbeName(scenario string) string

ScenarioProbeName — имя пробы сценария в написании этого дерева.

func SeedScopeUnfit added in v0.2.0

func SeedScopeUnfit(ordered []string, alive map[string]SeededServiceAccount) string

SeedScopeUnfit — ПРЕДМЕТА нет. Отдельной функцией, а не тремя ветвями внутри пробы: способность гейта отличить «ноль находок» от «ноль прочитанного» проверяется инъекцией, а инъекция не может спросить `require`/`t.Fatalf` напрямую.

func SortedFuncNames added in v0.2.0

func SortedFuncNames(byFunc map[string]FunctionDatabaseCalls) []string

SortedFuncNames — имена разобранных функций для текста отказа.

func SplitAlgorithmValues added in v0.3.0

func SplitAlgorithmValues(values []string) (algorithms []string, hasEmpty bool)

SplitAlgorithmValues делит значения словаря на алгоритмы и пустое.

Пустое выносится отдельно намеренно: оно означает «ключа нет», а не «любой алгоритм», и складывать его с алгоритмами значило бы объявить отсутствие ключа одним из них.

func SubjectChangeRosterTotal added in v0.3.0

func SubjectChangeRosterTotal(declared map[string]int) int

SubjectChangeRosterTotal — сколько обращений объявляет перечень.

func TrackedPathsOfTree added in v0.4.0

func TrackedPathsOfTree(root string) ([]string, error)

TrackedPathsOfTree — отслеживаемые пути дерева. Перечень ВЫВОДИТСЯ обходом индекса git, а не выписывается: рукописный список разошёлся бы с деревом молча.

func TreeModulePath added in v0.2.0

func TreeModulePath(root string) (string, error)

TreeModulePath — путь модуля, чтобы импорт файла сопоставлялся с каталогом дерева. Читается из go.mod, а не выписывается.

Types

type AcceptanceEditCensus added in v0.2.0

type AcceptanceEditCensus struct {
	DocsRead     int
	NoStateLine  []string
	NoHistory    []string
	EditedAfter  int
	CarryingNote int
	// HistoryDepth — сколько коммитов трогали дом приёмок, со ЗНАЧЕНИЕМ,
	// обрезанным сверху на AcceptanceHistoryFloor.
	//
	// Величина несущая, а не справочная: признак «правлено ПОСЛЕ вердикта»
	// есть СРАВНЕНИЕ двух отметок git, и в дереве с одним коммитом обе отметки
	// совпадают у каждого документа BY CONSTRUCTION. Там EditedAfter равен нулю
	// не потому, что приёмки не правили, а потому, что сравнивать нечего, — и
	// без этой величины два состояния неотличимы.
	//
	// Обрезается намеренно: вопрос к ней один — «есть ли чему сравниваться», а
	// полный счёт стоил бы обхода всей истории дома приёмок на каждом прогоне.
	HistoryDepth int
}

AcceptanceEditCensus — объём осмотренного.

Величин ТРИ, и печатаются все: «приёмок N · правлено после вердикта M · из них с записью K». Одно число здесь скрывало бы ровно тот случай, ради которого гейт заведён — документ, который никто не правил, и документ, чью правку никто не назвал, дают одинаковый ноль находок.

func (AcceptanceEditCensus) String added in v0.2.0

func (c AcceptanceEditCensus) String() string

type AcceptanceEditFinding added in v0.2.0

type AcceptanceEditFinding struct {
	File           string
	StateLine      int
	StateChangedAt int64
	FileChangedAt  int64
}

AcceptanceEditFinding — приёмка, правленая ПОСЛЕ объявления своего состояния, и не объявившая этого.

func (AcceptanceEditFinding) String added in v0.2.0

func (f AcceptanceEditFinding) String() string

type AlgorithmConstraint added in v0.3.0

type AlgorithmConstraint struct {
	File string
	Line int
	// Name — имя ограничения: им же оно снимается, и по нему разбор понимает,
	// какое объявление какое переобъявляет.
	Name string
	// Values — значения словаря в том виде, в каком они записаны, включая
	// пустое.
	Values []string
}

AlgorithmConstraint — объявление словаря алгоритма ограничением схемы.

type AlgorithmDictionaryCensus added in v0.3.0

type AlgorithmDictionaryCensus struct {
	// Files — файлов миграций прочитано.
	Files int
	// Statements — объявлений ограничения с этим столбцом найдено (включая
	// переобъявленные позднее).
	Statements int
	// Drops — снятий ограничения найдено.
	Drops int
}

AlgorithmDictionaryCensus — объём осмотренного.

type ApplierDeleteCensus added in v0.2.0

type ApplierDeleteCensus struct {
	InterfaceMethods int
	StringLiterals   int
	Comments         int
}

ApplierDeleteCensus — объём осмотренного одним файлом.

type ApplierDeleteSite added in v0.2.0

type ApplierDeleteSite struct {
	File string
	Line int
	// Kind — ось: `port-verb` либо `sql-literal`.
	Kind string
	// What — что именно найдено: имя метода либо начало литерала.
	What string
}

ApplierDeleteSite — координата находки.

type AuditPayloadCensus added in v0.3.0

type AuditPayloadCensus struct {
	Tracked     int            // элементов в индексе дерева
	Read        int            // прочитано файлов Go
	Parsed      int            // из них разобрано без ошибки
	Sites       int            // мест построения нагрузки
	SitesByForm map[string]int // форма → сколько мест
	Keys        int            // ключей осмотрено
	Files       []string       // файлы, где найдено хоть одно место
}

AuditPayloadCensus — объём осмотренного. Печатается всегда: «личных ключей нет» обязано быть отличимо от «ничего не разобрано».

func (AuditPayloadCensus) String added in v0.3.0

func (c AuditPayloadCensus) String() string

String — перепись одной строкой.

type AuditPayloadFinding added in v0.3.0

type AuditPayloadFinding struct {
	Where string // путь:строка
	Form  string // какой формой он записан
	Key   string
	Why   string
}

AuditPayloadFinding — один личный ключ с координатой.

func (AuditPayloadFinding) String added in v0.3.0

func (f AuditPayloadFinding) String() string

type AuditPayloadKey added in v0.3.0

type AuditPayloadKey struct {
	Name string
	Line int
}

AuditPayloadKey — один ключ нагрузки с его строкой.

type AuditPayloadSite added in v0.3.0

type AuditPayloadSite struct {
	Form string
	Line int
	Keys []AuditPayloadKey
}

AuditPayloadSite — одно место построения нагрузки.

func ParseAuditPayloadSites added in v0.3.0

func ParseAuditPayloadSites(path string, src []byte) ([]AuditPayloadSite, error)

ParseAuditPayloadSites разбирает ОДИН файл и находит места построения нагрузки со всеми ключами, записанными любой из объявленных форм.

Вынесено отдельной функцией с экспортом затем, чтобы предикат можно было предъявить синтетическому входу: на чистом дереве находок ноль, и без такого предъявления «ноль находок» было бы неотличимо от разбора, который ничего не ищет.

type AuditPersonalKey added in v0.3.0

type AuditPersonalKey struct {
	// Key — ключ ДОСЛОВНО, как он стоит в литерале. Сверка точная: `token_id`
	// не есть `token`, и подстрочное сравнение сделало бы находкой законный
	// идентификатор.
	Key string
	// Why — чем именно ключ личен либо секретен. Текст уезжает в находку:
	// проверка, не называющая причины, снимается следующим как непонятная.
	Why string
}

AuditPersonalKey — один ключ, которому в нагрузке журнала аудита не место.

func AuditPersonalKeys added in v0.3.0

func AuditPersonalKeys() []AuditPersonalKey

AuditPersonalKeys — объявленный перечень; гейт сверяет его с деревом.

type AuthorityResidueCensus added in v0.3.0

type AuthorityResidueCensus struct {
	// GoFiles — прод-файлов Go разобрано.
	GoFiles int
	// GoIdents — узлов-идентификаторов осмотрено.
	GoIdents int
	// Contracts — файлов контракта прочитано.
	Contracts int
	// ContractDecls — объявлений контракта осмотрено.
	ContractDecls int
	// Models — объявлений модели прав прочитано.
	Models int
	// Kept — прочтений законного соседа. Ноль здесь означает, что разбор не
	// дошёл до остатка, и его вердикт недействителен.
	Kept int
	// Excused — прочтений отношения, снятие которого объявлено чужим предметом.
	// Печатается рядом с находками: послабление, о котором не сказано числом,
	// неотличимо от его отсутствия.
	Excused int
	// Unparsed — файлов Go, которые парсер не принял. Третья категория: это не
	// «находок нет», а «о файле не известно ничего».
	Unparsed []string
}

AuthorityResidueCensus — объём осмотренного.

Печатается ВСЕГДА и целиком: у проверки на отсутствие это единственное, чем «находок ноль» отличается от «прочитано ноль».

func (AuthorityResidueCensus) String added in v0.3.0

func (c AuthorityResidueCensus) String() string

type AuthorityResidueFinding added in v0.3.0

type AuthorityResidueFinding struct {
	Where string
	Axis  string
	What  string
}

AuthorityResidueFinding — одна находка: где, по какой оси и что именно.

func (AuthorityResidueFinding) String added in v0.3.0

func (f AuthorityResidueFinding) String() string

type BoolWrapperCall added in v0.2.0

type BoolWrapperCall struct {
	File string
	Line int
	Pair WrapperPair
}

BoolWrapperCall — одно употребление булевой половины из чужого пакета.

type CarriedLedgerCensus added in v0.2.0

type CarriedLedgerCensus struct {
	Lines                 int
	Sections              int
	Tables                int
	Rows                  int
	RowsWithoutCoordinate int
}

CarriedLedgerCensus — объём осмотренного.

type CarriedLedgerRow added in v0.2.0

type CarriedLedgerRow struct {
	Section     string
	Line        int
	Coordinate  string
	Outcome     string
	OutcomeCell string
}

CarriedLedgerRow — строка ведомости.

type CarriedLedgerSection added in v0.2.0

type CarriedLedgerSection struct {
	Title               string
	Line                int
	HasRemovalPredicate bool
}

CarriedLedgerSection — раздел документа.

type CatalogSource added in v0.2.0

type CatalogSource struct {
	Path string
	Src  []byte
}

CatalogSource — один прод-файл на вход разбора. Инъекция подаёт синтетический состав, не трогая рабочую копию.

type CatalogWriteCensus added in v0.2.0

type CatalogWriteCensus struct {
	Files          int
	Parsed         int
	Funcs          int
	Executors      int
	StringLiterals int
	Comments       int
	TextMatches    int
	TextFiles      int
	Executed       int
	ExecutingFiles int
	WriteUnits     int
	LockedUnits    int
	LockSites      int
}

CatalogWriteCensus — объём осмотренного.

type CatalogWriteFinding added in v0.2.0

type CatalogWriteFinding struct {
	File string
	Line int
	Unit string
	What string
	Why  string
}

CatalogWriteFinding — координата находки: писатель без замка.

type CensusFileFacts added in v0.2.0

type CensusFileFacts struct {
	Rel      string
	Census   bool
	RawWrite bool
	Producer bool
}

CensusFileFacts — то, что гейт узнаёт об одном файле.

func CensusFactsOf added in v0.2.0

func CensusFactsOf(rel string, body []byte, producerPkg string) (CensusFileFacts, error)

CensusFactsOf разбирает один файл. Разбор, а не текст: комментарий, объясняющий эту же дисциплину, производителем не является.

type ClaimAssembly added in v0.2.0

type ClaimAssembly struct {
	File string
	Line int
	Func string
	Keys []string
}

ClaimAssembly — место, собирающее состав утверждений.

type ClaimAssemblyCensus added in v0.2.0

type ClaimAssemblyCensus struct {
	MapLiterals      int
	EmptyMapLiterals int
	KeyedLiterals    int
	Calls            int
}

ClaimAssemblyCensus — объём осмотренного одним файлом.

type ClaimBuilderCall added in v0.2.0

type ClaimBuilderCall struct {
	File   string
	Line   int
	Func   string
	Callee string
}

ClaimBuilderCall — вызов сборщика состава: чем состав ПОТРЕБЛЯЕТСЯ.

type ConcatCensus added in v0.3.0

type ConcatCensus struct {
	Dirs               []string
	Files              int
	Literals           int
	Segments           int
	ConcatsInPredicate int
	// ConcatsElsewhere — законный близнец: склейка в ПРОЕКЦИИ. Без него «находок
	// ноль» неотличимо от «разбор ничего не прочитал».
	ConcatsElsewhere int
}

ConcatCensus — объём осмотренного.

type ConcatFinding added in v0.3.0

type ConcatFinding struct {
	File    string
	Line    int
	Operand string
}

ConcatFinding — одно условие, сравнивающее склейку колонки.

type DatabaseCallCensus added in v0.2.0

type DatabaseCallCensus struct {
	Structs   int
	Handles   []string
	Functions int
	Calls     int
	DBCalls   int
}

DatabaseCallCensus — объём осмотренного одним файлом.

func ScanDatabaseCallsByFunction added in v0.2.0

func ScanDatabaseCallsByFunction(path string, src []byte) (
	map[string]FunctionDatabaseCalls, DatabaseCallCensus, error,
)

ScanDatabaseCallsByFunction разбирает один файл и раскладывает обращения к базе по функциям.

type DatabaseCallSite added in v0.2.0

type DatabaseCallSite struct {
	File   string
	Line   int
	Verb   string
	Handle string
}

DatabaseCallSite — координата обращения к базе.

type DeadPathCoordinate added in v0.4.0

type DeadPathCoordinate struct {
	Path  string
	Docs  []string
	Issue int
	Note  string
}

DeadPathCoordinate — ПОСЛАБЛЕНИЕ: путь, о котором известно, что он не резолвится, и чей предмет принадлежит ДРУГОМУ кругу приёмки.

Запись заводится ПО ФАКТУ. Послабление ИСТЕКАЕТ САМО, и оба конца — находка: путь стал резолвиться → исключать нечего; путь больше не стоит ни в одном документе → исключать нечего.

type DeadProbeCoordinate added in v0.2.0

type DeadProbeCoordinate struct {
	Name  string
	Docs  []string
	Issue int
	Note  string
}

DeadProbeCoordinate — ПОСЛАБЛЕНИЕ: координата, о которой известно, что она не резолвится, и чей предмет принадлежит ДРУГОМУ кругу приёмки.

Запись заводится ПО ФАКТУ, а не с запасом. Послабление ИСТЕКАЕТ САМО, и оба конца — находка: имя стало резолвиться → исключать нечего; имя больше не стоит ни в одном документе → исключать нечего.

type DeleteRevokeCensus

type DeleteRevokeCensus struct {
	Dirs         int // каталогов под api/ осмотрено
	Files        int // не-тестовых файлов Go разобрано
	EmitCalls    int // вызовов EmitReconcileEvent найдено
	OwnTyped     int // каталогов, у которых выведен СВОЙ тип
	WithDeleteGo int // из них несущих delete.go
	Population   int // судимых каталогов (свой тип И delete.go)
	Satisfying   int // из них эмитирующих отзыв своего типа
}

DeleteRevokeCensus — перепись одного обхода. Печатается ВСЕГДА: «ноль находок» обязано быть отличимо от «ноль прочитанного».

func ScanDeleteRevokeProducers

func ScanDeleteRevokeProducers(apiDir string) (DeleteRevokeCensus, []string, error)

ScanDeleteRevokeProducers обходит каталоги use-case под apiDir и называет те, у которых путь снятия собственного объекта остался без производителя отзыва.

Возвращает перепись, находки (по одной на каталог, в порядке имён — отказ на одном и том же дереве читается одинаково от прогона к прогону) и ошибку обхода. Пустой обход ошибкой ЗДЕСЬ не объявляется: пустоту судит вызывающий, потому что у гейта дерева и у пробы инъекции законные пороги пустоты разные.

func (DeleteRevokeCensus) String

func (c DeleteRevokeCensus) String() string

type DerivedIDCensus added in v0.2.0

type DerivedIDCensus struct {
	// Imports — объявлений импорта прочитано.
	Imports int
}

DerivedIDCensus — объём осмотренного одним файлом.

type DerivedIDImportSite added in v0.2.0

type DerivedIDImportSite struct {
	File string
	Line int
	// Form — форма импорта: `plain` · `alias` · `dot` · `blank`. Печатается
	// переписью, чтобы «ноль находок» было отличимо от «форму не узнали».
	Form string
}

DerivedIDImportSite — координата импорта, вычисляющего MD5.

type ExclusionFormCensus added in v0.3.0

type ExclusionFormCensus struct {
	GuideParagraphs   int
	SubjectParagraphs int
	ExplainByRefusal  int
	ExplainByBuild    int

	ReaderGoFiles      int
	RefuseCalls        int
	CoPresenceRefusals int

	WrapGoFiles int
	WrapCalls   int
	WrapSites   []string
}

ExclusionFormCensus — объём осмотренного, по ОБЕИМ сторонам.

type ExclusionFormFinding added in v0.3.0

type ExclusionFormFinding struct {
	// Kind — "refusal-without-producer" | "construction-unnamed".
	Kind string
	Rel  string
	// Line — первая строка абзаца предмета; 0, когда абзаца предмета нет вовсе.
	Line    int
	Excerpt string
}

ExclusionFormFinding — одно расхождение страницы с деревом.

func (ExclusionFormFinding) String added in v0.3.0

func (f ExclusionFormFinding) String() string

type ExclusionFormInput added in v0.3.0

type ExclusionFormInput struct {
	GuideRel  string
	GuideBody string
	// ReaderFiles — не-тестовые файлы читателя: координата → исходник.
	ReaderFiles map[string]string
	// WrapFiles — не-тестовый код, в котором ищутся обращения-обёртки.
	// Объявляющий файл читателя вызывающим не считается.
	WrapFiles map[string]string
}

ExclusionFormInput — что судить.

Координаты и тела приходят параметрами, а не читаются внутри: инъекция подаёт синтетику тем же входом, что и гейт — настоящее дерево.

type ExportProcedureCensus added in v0.3.0

type ExportProcedureCensus struct {
	// Guides — инструкций прочитано.
	Guides int
	// Lines — строк в них прочитано.
	Lines int
	// Procedures — строк, несущих процедуру выгрузки о КОНКРЕТНОЙ таблице.
	Procedures int
	// Templates — строк-образцов, где имя таблицы оставлено оператору. Считаются
	// отдельно: образец не утверждает о таблице ничего и сверять его с
	// производителем не с чем.
	Templates int
	// Tables — таблицы, чью выгрузку эти строки называют.
	Tables []string
}

ExportProcedureCensus — объём осмотренного. Печатается всегда: «находок ноль» обязано быть отличимо от «прочитано ноль».

func JudgeExportProcedure added in v0.3.0

func JudgeExportProcedure(guides map[string]string, required map[string]string) (ExportProcedureCensus, []string)

JudgeExportProcedure судит корпус инструкций: ключ — путь, значение — текст.

required — таблицы, чья процедура выгрузки обязана быть записана, и в какой именно инструкции. Возвращает перепись и находки; находок ноль — годно.

func (ExportProcedureCensus) String added in v0.3.0

func (c ExportProcedureCensus) String() string

type FunctionDatabaseCalls added in v0.2.0

type FunctionDatabaseCalls struct {
	Name  string
	Line  int
	Calls []DatabaseCallSite
}

FunctionDatabaseCalls — обращения одной функции.

type GoSQLLiteral added in v0.3.0

type GoSQLLiteral struct {
	SQL  string
	Line int
}

GoSQLLiteral — литерал SQL, найденный в исходнике Go.

func SQLLiteralsOfGo added in v0.3.0

func SQLLiteralsOfGo(name string, body []byte) []GoSQLLiteral

SQLLiteralsOfGo — литералы, разобранные ПО СИНТАКСИЧЕСКОМУ ДЕРЕВУ Go.

Не по тексту файла: SQL, стоящий в Go-комментарии, кодом не является, и читать его как код значило бы краснеть на объяснении запрета.

СКЛЕЙКА РАЗБИРАЕТСЯ ЦЕЛИКОМ. Кусок запроса, собранный конкатенацией, сам по себе не несёт ни параметров, ни предикатов — они в соседних слагаемых, — и судить его отдельно значило бы объявлять находкой каждый второй фрагмент. Слагаемые, не являющиеся литералами, подставляются как `$?`: их значение неизвестно, но известно, что там стоит ВЫЧИСЛЯЕМОЕ.

type HistoryCensus added in v0.3.0

type HistoryCensus struct {
	// FilesRead — файлов прочитано; GoParsed — из них разобрано деревом.
	FilesRead int
	GoParsed  int
	// GoUnparsed — файлов Go, которые разобрать НЕ УДАЛОСЬ. Отдельная величина:
	// неразобранный файл невидим, и его молчание неотличимо от чистоты.
	GoUnparsed []string
	// LinesStripped — строк комментария, снятых до разбора в не-Go файлах.
	// Печатается затем, чтобы «проза о merge-base не сработала» было ЗАМЕРОМ,
	// а не обещанием.
	LinesStripped int
	// VerbOutsideRunner — вызовов, чьи литералы несут глагол, но запускателем
	// git вызов не является (`require.Contains(t, got, "merge-base")`).
	//
	// Величина печатается ОТДЕЛЬНО затем, чтобы сужение до запускателя было
	// видно числом: ноль здесь означал бы, что сужение ничего не отсекает, а
	// большое число — что оно отсекает предмет.
	VerbOutsideRunner int
	// Questions — вопросов об истории всего; по вершинам — три величины ниже.
	Questions int
	Head      int
	Trunk     int
	Unnamed   int
	// ByVerb — сколько вопросов задал каждый глагол. Глагол, давший ноль,
	// означает, что этой формы в дереве нет, а не что разбор её не знает.
	ByVerb map[string]int
}

HistoryCensus — ОБЪЁМ ОСМОТРЕННОГО. «Ноль находок» обязано быть отличимо от «ноль прочитанного», а «ноль вопросов» — от «разбор не дошёл до вызовов».

type HistoryQuestion added in v0.3.0

type HistoryQuestion struct {
	File   string
	Line   int
	Verb   string
	Vertex Vertex
	// Literals — литеральные аргументы вызова, как их прочитал разбор. Нужны
	// читателю находки: без них он не отличит свой вызов от соседнего.
	Literals []string
}

HistoryQuestion — один вызов git, задающий вопрос об истории.

func (HistoryQuestion) String added in v0.3.0

func (q HistoryQuestion) String() string

String — координата и вердикт одной строкой.

type HomeVerdict added in v0.3.0

type HomeVerdict struct {
	// Findings — имя, которого в доме НЕТ. Вердикт, а не третья категория.
	Findings []string
	// Voids — ТРЕТЬЯ КАТЕГОРИЯ: дома рядом нет либо судить в нём не по чему.
	// В проход НЕ засчитывается и находок не гасит.
	Voids []string
	// Resolved — координат, найденных в своём доме.
	Resolved int
	// HomesResolved — дома, копии которых нашлись; HomesAbsent — которых нет.
	HomesResolved []string
	HomesAbsent   []string
}

HomeVerdict — исход резолва координаты в названном доме.

func JudgeHomes added in v0.3.0

func JudgeHomes(ownRoot string, coords []ProbeCoordinate) HomeVerdict

JudgeHomes — резолв координат чужих домов В НАЗВАННОМ ДОМЕ.

НАХОДКИ И ТРЕТЬЯ КАТЕГОРИЯ РАЗВЕДЕНЫ, и вызывающий обязан объявлять находки ПЕРВЫМИ: иначе «дома нет» становится маской — одной такой строки хватило бы, чтобы настоящая находка перестала блокировать отправку.

Дом резолвится ОДИН раз на имя: без этого перепись печатала бы его столько раз, сколько координат на него ссылается.

type IdentityGrowthReaderCensus added in v0.4.0

type IdentityGrowthReaderCensus struct {
	// Metrics — ряды, объявленные коллектором.
	Metrics []string
	// Expressions — выражения правил оповещения, прочитанные у документа.
	Expressions int
}

IdentityGrowthReaderCensus — ОБЪЁМ ОСМОТРЕННОГО обеих сторон сверки.

func JudgeIdentityGrowthReaders added in v0.4.0

func JudgeIdentityGrowthReaders(collector, doc string) (IdentityGrowthReaderCensus, []string, error)

JudgeIdentityGrowthReaders — у каждого объявленного ряда есть читатель.

ПРЕМИСЫ ЖИВУТ ЗДЕСЬ, а не в теле гейта (задача #17). Прежде обе стояли в пробе, входом им служили два файла, прочитанные от корня своего модуля, и подать им пустую сторону было НЕЧЕМ: ветви читались глазами и не исполнялись ни разу. Приняв обе стороны параметрами, они стали проверяемы синтетикой.

Ноль рядов и ноль выражений — РАЗНЫЕ отказы намеренно: первый означает, что ослеп разбор коллектора, второй — что ослеп разбор правил, и чинятся они в разных местах. Слив их в один текст, гейт посылал бы читателя не туда.

type InjectionCensus

type InjectionCensus struct {
	// GoFiles — исходников модуля разобрано.
	GoFiles int
	// NamingFiles / InComments — файлов, называющих доказательство, и самих
	// упоминаний В КОММЕНТАРИЯХ (судимая полоса).
	NamingFiles int
	InComments  int
	// InStrings — упоминаний в строковых литералах (полоса НЕ судимая; названа,
	// чтобы её отсутствие в вердикте не приняли за отсутствие вхождений).
	InStrings int
	// Resolved — из судимых упоминаний нашли свой файл.
	Resolved int
}

InjectionCensus — объём осмотренного. Печатается ВСЕГДА: «ноль находок» обязано быть отличимо от «ноль прочитанного».

type InjectionFinding

type InjectionFinding struct {
	NamedBy    string // координата называющего, от корня обхода
	Coordinate string // что названо
}

InjectionFinding — упоминание, у которого нет предмета.

type JobFieldRead added in v0.4.0

type JobFieldRead struct {
	Section string
	Field   string
	File    string
	Line    int
}

JobFieldRead — прочтение величины в композиционном корне.

func JobFieldReadsIn added in v0.4.0

func JobFieldReadsIn(file, src string, sections map[string]bool) ([]JobFieldRead, []string, error)

JobFieldReadsIn разбирает ОДИН файл корня: какие величины прочитаны и какие секции ушли в вызов целиком.

Имя секции подаётся набором, а не угадывается: гейт судит те секции, которые объявлены, и на одноимённом поле чужой структуры молчит.

type JobKnobCensus added in v0.4.0

type JobKnobCensus struct {
	Sections     int
	Fields       int
	Read         int
	WholeSection []string
	Files        int
	Findings     []string
}

JobKnobCensus — объём осмотренного и вердикт.

Величин ПЯТЬ, и печатаются все: «секций N · величин M · прочитано K · секций целиком L · файлов корня F». Одно число скрывало бы ровно тот случай, ради которого гейт заведён: величина без читателя и величина, чья секция уехала целиком, дают одинаковый ноль находок.

func JudgeJobKnobReaders added in v0.4.0

func JudgeJobKnobReaders(sections []JobSection, reads []JobFieldRead, whole []string, files int) JobKnobCensus

JudgeJobKnobReaders — судящее ядро. Вход подаётся ЗНАЧЕНИЯМИ: инъекция обязана уметь дать ему свой вход, не трогая рабочую копию, из которой запущена.

func (JobKnobCensus) Summary added in v0.4.0

func (c JobKnobCensus) Summary() string

type JobSection added in v0.4.0

type JobSection struct {
	// Name — имя поля в JobsConfig (оно же сегмент ключа настроек).
	Name string
	// Type — имя структуры секции.
	Type string
	// Fields — величины секции, объявленные тегом настроек.
	Fields []string
}

JobSection — секция фоновых заданий и её величины.

func JobSectionsIn added in v0.4.0

func JobSectionsIn(src string) ([]JobSection, error)

JobSectionsIn разбирает объявление секций фоновых заданий.

Состав ВЫВОДИТСЯ из исходника, а не выписывается: выписанный перечень секций разошёлся бы с деревом на первой же новой петле — и разошёлся бы молча, потому что гейт судил бы ровно то, что ему назвали.

type JudgeTargetWiring added in v0.3.0

type JudgeTargetWiring struct {
	// Target — имя цели, о которой всё нижеследующее.
	Target string
	// Declared — объявлена ли цель корневым рецептом.
	Declared bool
	// Callers — файлы заданий, чьё тело `run:` зовёт цель исполняемой формой.
	Callers []string

	// MakefilesRead — прочитано рецептов (в этом дереве обязан быть ровно один).
	MakefilesRead int
	// WorkflowsRead — найдено файлов заданий.
	WorkflowsRead int
	// WorkflowsParsed — из них разобрано как YAML.
	WorkflowsParsed int
	// RunStepsRead — шагов с непустым телом `run:`.
	RunStepsRead int
	// Unreadable — файлы, которые прочитать или разобрать не удалось; НЕ
	// проверены, и молчать о них нельзя.
	Unreadable []string
}

JudgeTargetWiring — что дерево говорит о ПРОВЯЗКЕ одной цели-судьи.

Перепись хранится рядом с вердиктом намеренно: «вызова нет» и «не прочитано ничего» выглядят одинаково, пока объём осмотренного не назван числом.

func ReadJudgeTargetWiring added in v0.3.0

func ReadJudgeTargetWiring(root, target string) (JudgeTargetWiring, error)

ReadJudgeTargetWiring — обход дерева: кто объявляет цель и кто её зовёт.

Ошибка возвращается там, где обход БЕСПРЕДМЕТЕН (нет рецепта, нет каталога заданий): «ноль находок» обязано быть отличимо от «ноль прочитанного», и различать их обязан сам разбор, а не читатель его вывода.

func (JudgeTargetWiring) Census added in v0.3.0

func (w JudgeTargetWiring) Census() string

Census — объём осмотренного. Печатается ВСЕГДА: без него «вызывающий есть» неотличимо от «читать было нечего».

type LenientScopeCensus added in v0.3.0

type LenientScopeCensus struct {
	Packages    int
	Lenient     int
	Named       int
	Holders     int
	HolderTests int
	// RefsPrefixed / RefsBare — сколько ссылок пришло в каждой из двух законных
	// форм. Печатаются порознь намеренно: ноль в одной из них означает, что
	// форма перестала встречаться, и это повод перемерить распознаватель, а не
	// повод ему молчать.
	RefsPrefixed int
	RefsBare     int
}

LenientScopeCensus — объём осмотренного. Печатается ВСЕГДА: «ноль находок» обязано быть отличимо от «ноль прочитанного».

func AuditLenientScopes added in v0.3.0

func AuditLenientScopes(apiRoot string) (LenientScopeCensus, []string, error)

AuditLenientScopes ВОЗВРАЩАЕТ находки, а не роняет прогон сам: инъекция обязана уметь их прочитать, чтобы утверждать, ЧТО именно нашлось, а не только «покраснело». Отказ предпосылки остаётся ошибкой — на слепом обходе говорить не о чем.

func (LenientScopeCensus) String added in v0.3.0

func (c LenientScopeCensus) String() string

type MachineryCensus added in v0.3.0

type MachineryCensus struct {
	// Files — прочитано файлов контрактов.
	Files int
	// CommentBlocks — прочитано блоков комментария.
	CommentBlocks int
	// Claims — распознано заявлений всего.
	Claims int
	// ByKind — распознано заявлений по видам.
	ByKind map[MachineryKind]int
	// Resolved — из них резолвится (законные близнецы).
	Resolved int
}

MachineryCensus — объём осмотренного. Печатается всегда: «ноль находок» обязано быть отличимо от «ноль прочитанного».

type MachineryClaim added in v0.3.0

type MachineryClaim struct {
	// File — путь контракта относительно корня набора.
	File string
	// Line — строка, на которой стоит имя.
	Line int
	// Name — заявленное имя.
	Name string
	// Kind — чем комментарий его назвал.
	Kind MachineryKind
}

MachineryClaim — одно заявление комментария о машинерии дерева.

type MachineryFacts added in v0.3.0

type MachineryFacts struct {
	// Sources — путь контракта → его исходный текст.
	Sources map[string]string
	// Tables — таблицы ПРИМЕНЁННОЙ схемы.
	Tables map[string]struct{}
	// Channels — каналы уведомления, которые эта схема производит.
	Channels map[string]struct{}
	// Contracts — базовые имена контрактов, существующих в модуле.
	Contracts map[string]struct{}
}

MachineryFacts — вход предиката. Собран так, чтобы предикат прогонялся инъекцией, не трогая дерево.

type MachineryKind added in v0.3.0

type MachineryKind string

MachineryKind — что именно заявил комментарий.

const (
	// MachineryTable — заявлена таблица схемы.
	MachineryTable MachineryKind = "таблица"
	// MachineryChannel — заявлен канал уведомления.
	MachineryChannel MachineryKind = "канал"
	// MachineryContract — заявлен соседний файл контракта.
	MachineryContract MachineryKind = "контракт"
)

type MigrationRoleCensus added in v0.3.0

type MigrationRoleCensus struct {
	// Blocks — блоков `INSERT INTO kaname.roles` прочитано.
	Blocks int
	// Names — имён ролей извлечено.
	Names int
	// Unreadable — блоков, из которых имя роли извлечь НЕ УДАЛОСЬ.
	//
	// Величина отдельная и несущая: без неё «извлечено меньше, чем блоков»
	// неотличимо от «блок вставляет роль без имени», а первое означает, что
	// разбор встретил форму, которой не знает, — то есть невидимость, а не
	// находку и не молчание.
	Unreadable int
}

MigrationRoleCensus — объём осмотренного.

type MigrationRoleSite added in v0.3.0

type MigrationRoleSite struct {
	File string
	Name string
	// Owner — первый сегмент имени: модуль-владелец либо пусто.
	Owner string
}

MigrationRoleSite — роль, вставляемая миграцией.

type MirrorConditionOutcome added in v0.3.0

type MirrorConditionOutcome struct {
	// Findings — писатели, обошедшие условие эталонной полосы.
	Findings []string
	// Stale — записи ведомости, которым больше нечего исключать.
	Stale []string
	// Required — условие, выведенное из эталонной полосы (таблицы каталога).
	Required []string
	// Lanes — вводящих писателей всего.
	Lanes int
	// LaneKeys — они же поимённо: число без перечня читатель проверить не может.
	LaneKeys []string
	// Carriers — из них несущих требуемое условие целиком.
	Carriers int
	// Exempt — из них погашенных ведомостью.
	Exempt int
	// ReferenceMissing — эталонной полосы в наборе нет; сверять не с чем.
	ReferenceMissing bool
}

MirrorConditionOutcome — вердикт сверки полос вместе с переписью.

func MirrorConditionReport added in v0.3.0

func MirrorConditionReport(writes []MirrorWrite, ledger map[string]string) MirrorConditionOutcome

MirrorConditionReport — ЧИСТАЯ функция сверки: по набору записей и ведомости возвращает находки и перепись. Вынесена из обхода дерева намеренно — только так её способность краснеть и молчать доказывается инъекцией на синтетическом входе, не трогая настоящее дерево.

type MirrorWiringScan added in v0.3.0

type MirrorWiringScan struct {
	// Files — не-тестовых файлов Go разобрано.
	Files int
	// Calls — узлов вызова читателя найдено.
	Calls int
	// CallSites — файлы с вызовом, по возрастанию.
	CallSites []string
}

MirrorWiringScan — что увидел обход композиционного корня.

func ScanMirrorDivergenceWiring added in v0.3.0

func ScanMirrorDivergenceWiring(root string) (MirrorWiringScan, error)

ScanMirrorDivergenceWiring обходит названный каталог и считает вызовы читателя разности.

Вынесен отдельно от гейта затем, чтобы инъекция гоняла ТУ ЖЕ функцию на синтетическом дереве: проверка, доказанная на своей копии разбора, доказывает свойство копии.

type MirrorWrite added in v0.3.0

type MirrorWrite struct {
	// File — путь от корня дерева; заполняет обходчик.
	File string
	// Func — объемлющая функция; пустое имя означает пакетный уровень.
	Func string
	// Verb — какой оператор записи найден.
	Verb string
	// Introduces — вводит ли оператор новую строку.
	Introduces bool
	// Catalog — таблицы каталога, названные В ТОМ ЖЕ операторе, по возрастанию.
	Catalog []string
}

MirrorWrite — одна найденная запись в зеркало.

func MirrorWritesIn added in v0.3.0

func MirrorWritesIn(filename, src string) ([]MirrorWrite, int, error)

func (MirrorWrite) Key added in v0.3.0

func (w MirrorWrite) Key() string

Key — координата писателя в ведомости исключений.

type ModuleManifestSite added in v0.3.0

type ModuleManifestSite struct {
	File   string
	Module string
}

ModuleManifestSite — манифест, найденный в дереве.

func ScanModuleManifest added in v0.3.0

func ScanModuleManifest(path string, src []byte) (ModuleManifestSite, bool)

ScanModuleManifest опознаёт манифест модуля по содержимому.

type ModuleSetDecl added in v0.3.0

type ModuleSetDecl struct {
	// PkgFiles — сколько не-тестовых файлов пакета осмотрено. Без этой величины
	// «объявление найдено» неотличимо от «прочитан один файл, и повезло».
	PkgFiles int
	// DeclFile — где объявление нашлось. Печатается, потому что именно это место
	// и переезжало: читатель обязан видеть, О ЧЁМ вынесен вердикт, не заглядывая
	// в исходник гейта.
	DeclFile string
	// TypeKeys — сколько ключей прочитано. Приставок мало by construction, и одна
	// их величина не отличила бы «таблица прочитана» от «прочитаны две строки».
	TypeKeys int
}

ModuleSetDecl — перепись РАЗРЕШЕНИЯ объявления.

func ModuleSetFromDecl added in v0.3.0

func ModuleSetFromDecl(files map[string]string, varName string) ([]string, ModuleSetDecl, error)

ModuleSetFromDecl выводит закрытый набор модулей РАЗБОРОМ объявления.

`files` — содержимое не-тестовых файлов пакета: координата → исходник. Читатель отдаёт их сам, потому что гейт берёт их из индекса git, а инъекция — из синтетики, и разводить эти два источника внутри значило бы завести здесь вторую посадку.

type ModuleSetFinding added in v0.3.0

type ModuleSetFinding struct {
	File    string
	Line    int
	Named   []string
	Missing []string
	Span    string
}

ModuleSetFinding — один неполный перечень.

func (ModuleSetFinding) String added in v0.3.0

func (f ModuleSetFinding) String() string

type ModuleSetScan added in v0.3.0

type ModuleSetScan struct {
	// Enumerations — сколько перечней (три имени и более) рассужено.
	Enumerations int
	// PairSpans — сколько спанов РОВНО из двух имён встречено и НЕ рассужено.
	// Объявленная слепая зона, а не находка.
	PairSpans int
}

ModuleSetScan — перепись обхода поверхностей.

type NonASCIIIdent added in v0.3.0

type NonASCIIIdent = treehygiene.NonASCIIIdent

NonASCIIIdent — одно нелатинское имя с координатой; тип фундамента, названный здесь именем шва.

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

func ScanNonASCIIIdents added in v0.3.0

func ScanNonASCIIIdents(name string, src []byte) (seen int, findings []NonASCIIIdent, err error)

ScanNonASCIIIdents разбирает ОДИН исходник и возвращает: сколько имён осмотрено и какие из них нелатинские.

Перепись «имён осмотрено N» нужна гейту, чтобы «ноль находок» было отличимо от «разбор ничего не увидел»; неразбираемый файл отдаёт признак, а не пустой успех, — обе половины держит фундамент, и утверждают их его пробы.

type PathCoordinate added in v0.4.0

type PathCoordinate struct {
	// Path — путь-спецификация без приставки дома.
	Path string
	// Home — названный дом `владелец/репозиторий`. Пусто — дом ЭТО дерево.
	Home string
	// Rev — ревизия названного дома, если названа.
	Rev string
	// Span — токен, как он стоит в документе: без него читатель не найдёт строку.
	Span string
	// HomeMalformed — приставка есть, а домом она не является.
	HomeMalformed bool
	Doc           string
	Line          int
}

PathCoordinate — одно вхождение путевой координаты.

type PathCoordinateCensus added in v0.4.0

type PathCoordinateCensus struct {
	Docs        int
	Tracked     int
	Coordinates int
	Resolved    int
	Exempted    int
	// Foreign — координаты, назвавшие ЧУЖОЙ дом: вне суждения, но в переписи.
	Foreign int
	// RevisionBound — из них связанные РЕВИЗИЕЙ: не проверяемы даже там, где
	// дерево дома есть.
	RevisionBound int
	// ForeignHomes — различные названные дома, по алфавиту.
	ForeignHomes []string
	// Borders — что разбор видел и не судил.
	Borders  PathScanBorders
	Findings []string
}

PathCoordinateCensus — перепись обхода. «Ноль находок» обязано быть отличимо от «ноль прочитанного», поэтому объём осмотренного — отдельное утверждение.

func JudgePathCoordinates added in v0.4.0

func JudgePathCoordinates(docs map[string]string, tracked []string, exemptions []DeadPathCoordinate) PathCoordinateCensus

JudgePathCoordinates — судящее ядро. Вход подаётся ЗНАЧЕНИЯМИ, а не читается из дерева: инъекция обязана уметь дать ему свой вход, не трогая рабочую копию, из которой запущена.

type PathScanBorders added in v0.4.0

type PathScanBorders struct {
	// BareSpec — путей-спецификаций в форме `git ls-files <спец>` без `--`.
	BareSpec int
	// Magic — магических путей-спецификаций (`:!*.md`, `:(glob)…`): не пути.
	Magic int
	// Elided — многоточий-эллипсисов (`…/*.yaml`): не пути, а сокращение прозы.
	Elided int
}

PathScanBorders — то, что разбор ВИДЕЛ и НЕ СУДИЛ. Печатается переписью: слепая зона, которую видно, — остаток, а не дыра.

type ProbeCoordinate added in v0.2.0

type ProbeCoordinate struct {
	Name string
	// Home — названный дом `владелец/репозиторий`. Пусто — дом ЭТО дерево.
	Home string
	// Rev — ревизия названного дома, если названа.
	Rev string
	// Span — пролёт, как он стоит в документе. Нужен находке: без него читатель
	// не найдёт строку, у которой имя пробы лишь хвост.
	Span string
	// HomeMalformed — приставка есть, а домом она не является.
	HomeMalformed bool
	Doc           string
	Line          int
}

ProbeCoordinate — одно вхождение координаты: имя, дом и место, где оно стоит.

func ProbeCoordinatesIn added in v0.2.0

func ProbeCoordinatesIn(doc, body string) []ProbeCoordinate

ProbeCoordinatesIn разбирает документ и возвращает координаты — только их.

type ProbeCoordinateCensus added in v0.2.0

type ProbeCoordinateCensus struct {
	Docs        int
	Declared    int
	Coordinates int
	Resolved    int
	Exempted    int
	// Foreign — координаты, назвавшие ЧУЖОЙ дом: вне суждения, но в переписи.
	Foreign int
	// RevisionBound — из них связанные РЕВИЗИЕЙ чужого дома. Величина отдельная,
	// потому что отвечает на другой вопрос: сколько координат указывает в ПРОШЛОЕ
	// состояние чужого дерева, то есть не проверяемо даже там, где дерево есть.
	RevisionBound int
	// ForeignHomes — различные названные дома, по алфавиту. Печатаются, чтобы дом,
	// стоящий в корпусе один раз, был виден: опечатка в имени репозитория иначе
	// уходит молча.
	ForeignHomes []string
	// ForeignCoordinates — сами координаты чужих домов, чтобы их можно было
	// РЕЗОЛВИТЬ в названном доме, а не только сосчитать. Ядро судит значения и
	// чужих деревьев не читает: резолв делает вызывающий, у которого есть корень.
	ForeignCoordinates []ProbeCoordinate
	Findings           []string
}

ProbeCoordinateCensus — перепись обхода. «Ноль находок» обязано быть отличимо от «ноль прочитанного», поэтому объём осмотренного — отдельное утверждение.

func JudgeProbeCoordinates added in v0.2.0

func JudgeProbeCoordinates(docs map[string]string, declared []string, exemptions []DeadProbeCoordinate) ProbeCoordinateCensus

JudgeProbeCoordinates — судящее ядро. Вход подаётся значениями, а не читается из дерева: инъекция обязана уметь дать ему свой вход, не трогая рабочую копию, из которой запущена.

type RawOperationsRepoSite added in v0.3.0

type RawOperationsRepoSite struct {
	Where   string // путь:строка
	Wrapped bool   // обёрнут ли надстройкой прямо здесь
}

RawOperationsRepoSite — один вызов сырого конструктора с координатой.

type ReadPathFile added in v0.3.0

type ReadPathFile struct {
	// Rel — координата в том виде, в каком её объявляет предмет замера; ею
	// называется находка.
	Rel string
	// Abs — путь, по которому файл читается.
	Abs string
}

ReadPathFile — файл предмета замера: координата для находки и путь на диске.

func ReadPathGoFiles added in v0.3.0

func ReadPathGoFiles(root string) (files []ReadPathFile, dirs []string, err error)

ReadPathGoFiles — не-тестовые .go каталогов, составляющих предмет замера.

Координаты приводятся к посадке ДЕТЕКТОРОМ дерева (`treeposture.PathUnder`), а не складываются с корнем здесь: правило приведения живёт в одном месте дерева, и второй его копии не заводится. Первая редакция порта складывала путь сама — и её поймал гейт дерева `TestPlatformCoordinatesTouchingTheTreeAreAnchoredInTheModule` двумя находками: под чужим деревом такой путь указал бы на чужой файл, и вердикт был бы о нём.

Каталог, в котором таких файлов нет вовсе (каталог миграций), в объём просто не приносит ничего — исключать его СПИСКОМ не нужно, и списка здесь нет.

type RefusalTextCensus

type RefusalTextCensus struct {
	Files          int // файлов Go (не-тестовых) разобрано
	Constructions  int // конструкций статуса найдено всего
	Population     int // из них на полосах чужой причины (код назван синтаксически)
	Fixed          int // из них с доказуемо фиксированным текстом
	CodeNotLiteral int // конструкций с ВЫЧИСЛЯЕМЫМ кодом — вне популяции (слепая зона)
	Constants      int // пакетных строковых констант проиндексировано
}

RefusalTextCensus — перепись одного обхода. Печатается ВСЕГДА: «ноль находок» обязано быть отличимо от «ноль прочитанного».

func (RefusalTextCensus) String

func (c RefusalTextCensus) String() string

type RefusalTextDecl added in v0.3.0

type RefusalTextDecl struct {
	Where string
	Name  string
}

RefusalTextDecl — одно объявление текста отказа с координатой.

type RefusalTextFinding

type RefusalTextFinding struct {
	File string // путь относительно названного корня
	Line int
	Code string // Unavailable / Internal
	Expr string // выражение текста, как оно записано
}

RefusalTextFinding — одна конструкция, чей текст не доказан фиксированным.

type RelationGrant added in v0.3.0

type RelationGrant struct {
	ObjectType string
	Relation   string
	Where      string // путь относительно корня — координата находки
}

RelationGrant — одна выдача: какое отношение на каком типе объекта пишет миграция.

func GrantsFromMigrations added in v0.3.0

func GrantsFromMigrations(root string) (grants []RelationGrant, migrationsRead, blocksSeen int, err error)

GrantsFromMigrations — пары «тип объекта + отношение» из миграций, пишущих в очередь. Возвращает ещё и объём осмотренного: без него «ноль находок» неотличимо от «ноль прочитанного».

type RoleDeleteCensus added in v0.2.0

type RoleDeleteCensus struct {
	StringLiterals int
	Comments       int
	Statements     int
	Guarded        int
}

RoleDeleteCensus — объём осмотренного одним файлом.

type RoleDeleteSite added in v0.2.0

type RoleDeleteSite struct {
	File string
	Line int
	What string
}

RoleDeleteSite — координата находки.

type RoleOperationResponseStateCensus added in v0.2.0

type RoleOperationResponseStateCensus struct {
	Files            int
	Funcs            int
	AnypbFuncs       int
	RoleTranslators  int
	ProjectionCalled int
}

RoleOperationResponseStateCensus — объём осмотренного.

func (RoleOperationResponseStateCensus) String added in v0.2.0

type RoleOperationResponseStateFinding added in v0.2.0

type RoleOperationResponseStateFinding struct {
	File string
	Line int
	Func string
}

RoleOperationResponseStateFinding — переводчик, не зовущий проекцию.

func (RoleOperationResponseStateFinding) String added in v0.2.0

type RoleOperationResponseStateOptions added in v0.2.0

type RoleOperationResponseStateOptions struct {
	Root             string
	ServiceRoot      string
	DomainPkg        string
	RoleType         string
	TransferFunc     string
	ProjectionMethod string
}

RoleOperationResponseStateOptions — вход анализатора.

type RoleProjectionOp added in v0.2.0

type RoleProjectionOp struct {
	// Func — объемлющая функция; пустое имя означает пакетный уровень.
	Func string
	// Verb — какой оператор найден.
	Verb string
	// Authors — оператор ВНОСИТ строку.
	Authors bool
	// Relocates — ТОТ ЖЕ литерал переселяет снятое в RoleGrantOrphanTable.
	//
	// Признак читается по литералу, а не по функции: переселение и снятие
	// обязаны быть неделимы, а неделимы они ровно тогда, когда стоят в одном
	// операторе.
	Relocates bool
}

RoleProjectionOp — один найденный оператор над проекцией.

func RoleProjectionWritesIn added in v0.2.0

func RoleProjectionWritesIn(filename, src, table string) ([]RoleProjectionOp, int, error)

RoleProjectionWritesIn разбирает исходник Go и возвращает операторы над таблицей проекции, приписанные объемлющей функции, плюс число строковых литералов, называющих таблицу вообще (перепись предпосылки: читатели тоже считаются).

Признак судит УЗЕЛ-ЛИТЕРАЛ разобранного дерева, а не текст файла: имя таблицы встречается и в комментариях — в том числе в комментариях, объясняющих эту самую проверку, — и гейт по подстроке краснел бы на собственном объяснении.

func RoleVerbWritesIn added in v0.2.0

func RoleVerbWritesIn(filename, src string) ([]RoleProjectionOp, int, error)

RoleVerbWritesIn — совместимая обёртка для инъекции по первой проекции.

type RoleScopeChainCensus added in v0.2.0

type RoleScopeChainCensus struct {
	Statements  int
	Branches    int
	TierSourced int
}

RoleScopeChainCensus — объём осмотренного одним файлом.

type RoleScopeChainSite added in v0.2.0

type RoleScopeChainSite struct {
	File string
	Line int
	What string
}

RoleScopeChainSite — координата одной находки.

type RoleWithdrawalCensus added in v0.2.0

type RoleWithdrawalCensus struct {
	AppliedImports  int
	Selectors       int
	StringLiterals  int
	Comments        int
	WritesOverRoles int
}

RoleWithdrawalCensus — объём осмотренного одним файлом.

type RoleWithdrawalSite added in v0.2.0

type RoleWithdrawalSite struct {
	File string
	Line int
	What string
}

RoleWithdrawalSite — координата одной из двух половин.

type SQLUpdate added in v0.2.0

type SQLUpdate struct {
	File    string
	Line    int
	Func    string
	Table   string
	Columns []string
}

SQLUpdate — оператор правки, найденный в литерале.

type SQLUpdateCensus added in v0.2.0

type SQLUpdateCensus struct {
	StringLiterals        int
	SQLLiterals           int
	Updates               int
	UpdatesWithoutColumns int
}

SQLUpdateCensus — объём осмотренного одним файлом.

type SeedCensusCell added in v0.3.0

type SeedCensusCell struct {
	Hits  int
	Files int
}

SeedCensusCell — одна клетка переписи: вхождений и файлов.

func (SeedCensusCell) String added in v0.3.0

func (c SeedCensusCell) String() string

type SeedCensusDeclaration added in v0.3.0

type SeedCensusDeclaration struct {
	// Revision — ревизия измерения, названная ОДНОЙ строкой документа.
	Revision string
	// Buckets — объявленные величины, по ведру.
	Buckets map[string]SeedCensusCell
	// BlockLines — сколько строк объявляющего блока прочитано (перепись:
	// «ноль находок» обязано быть отличимо от «ноль прочитанного»).
	BlockLines int
	// LineOf — НОМЕР СТРОКИ документа (от нуля), на которой объявлено ведро.
	//
	// Нужен не разбору, а тому, кто правит объявление точечно — инъекции.
	// Без него порча «первого вхождения величины в файле» промахивается мимо
	// объявления, как только та же величина упомянута прозой выше: инъекция
	// тогда красит текст, которого гейт не судит, и молча ничего не доказывает.
	// Наблюдалось на этом самом файле.
	LineOf map[string]int
}

SeedCensusDeclaration — то, что объявила приёмка.

func ParseSeedCensusDeclaration added in v0.3.0

func ParseSeedCensusDeclaration(doc string, buckets []string) SeedCensusDeclaration

ParseSeedCensusDeclaration читает объявление приёмки.

Блок ищется ПО РЕВИЗИИ, а не по порядку: в документе живёт и второй блок тех же вёдер — замер в монорепо, объявленный историческим свидетельством. Разбор «первый попавшийся блок» сверял бы величины ЧУЖОГО дерева и был бы при этом зелёным ровно до тех пор, пока кто-нибудь не тронет здешние числа.

Внутри строки берётся ПОСЛЕДНЯЯ клетка: столбцов у блока два — монорепо и это дерево, — и здешний стоит правым.

type SeedCensusReport added in v0.3.0

type SeedCensusReport struct {
	Revision string
	Indexed  int
	Read     int
	Binary   int
	Buckets  map[string]SeedCensusCell
	Order    []string
}

SeedCensusReport — то, что напечатал предикат.

func ParseSeedCensusOutput added in v0.3.0

func ParseSeedCensusOutput(out string) (SeedCensusReport, error)

ParseSeedCensusOutput разбирает вывод предиката.

Отказ — не пустой отчёт: предикат, не напечатавший ни объёма осмотренного, ни одного ведра, о дереве не сказал ничего, и выдавать это за ноль находок нельзя.

type SeededServiceAccount added in v0.2.0

type SeededServiceAccount struct {
	ID, Name, Description, Where string
}

SeededServiceAccount — посеянная служебная учётка.

func (SeededServiceAccount) IsModule added in v0.2.0

func (s SeededServiceAccount) IsModule() bool

IsModule — учётка объявляет себя модульной.

type SubjectChangeProducer added in v0.3.0

type SubjectChangeProducer struct {
	File string
	Line int
}

SubjectChangeProducer — одно обращение к производителю очереди.

func SubjectChangeProducersIn added in v0.3.0

func SubjectChangeProducersIn(rel, src string) ([]SubjectChangeProducer, error)

SubjectChangeProducersIn считает обращения к производителю в ОДНОМ файле.

Возвращает координаты обращений. Разбор — не поиск по подстроке: имя метода стоит и в комментариях, объясняющих сам механизм, и предикат по слову краснел бы на собственном объяснении.

func (SubjectChangeProducer) String added in v0.3.0

func (p SubjectChangeProducer) String() string

type SubjectChangeRosterDiff added in v0.3.0

type SubjectChangeRosterDiff struct {
	// Undeclared — файл несёт больше обращений, чем объявлено (в том числе
	// файл, которого в перечне нет вовсе).
	Undeclared []string
	// Stale — перечень называет то, чего в дереве больше нет либо стало меньше.
	// Запись, которой нечего называть, — НАХОДКА: послабление обязано истекать
	// само, иначе оно переживает свой предмет, оставаясь на вид рабочим.
	Stale []string
}

SubjectChangeRosterDiff — расхождение перечня с деревом.

func CompareSubjectChangeRoster added in v0.3.0

func CompareSubjectChangeRoster(
	found []SubjectChangeProducer, declared map[string]int,
) SubjectChangeRosterDiff

CompareSubjectChangeRoster сверяет перечень с разбором — в ОБЕ стороны.

Сверяется пара «файл → сколько обращений», а не только число файлов: второе обращение, добавленное в уже объявленный файл, — такой же новый производитель, как и первый в новом файле, и полоса пополняется им ровно так же.

Число целиком (а не только состав) сверять обязательно и по другой причине: предок сравнивал ЧИСЛА полос, и величина, которую край пинит, — это число.

func (SubjectChangeRosterDiff) Empty added in v0.3.0

func (d SubjectChangeRosterDiff) Empty() bool

Empty — сошлись ли перечень и дерево.

type TerminalRefusalCensus added in v0.3.0

type TerminalRefusalCensus struct {
	Tracked  int // элементов в индексе дерева
	Read     int // прочитано файлов Go
	Parsed   int // из них разобрано
	Ctors    int // найдено вызовов сырого конструктора
	Wrapped  int // из них обёрнуто на месте
	Mentions int // упоминаний имени вне вызова (комментарий, строка)
}

TerminalRefusalCensus — объём осмотренного.

func ScanRefusalTextLiterals added in v0.3.0

func ScanRefusalTextLiterals(root string, texts []string) (
	map[string][]RefusalTextDecl, TerminalRefusalCensus, error,
)

ScanRefusalTextLiterals ищет ЛИТЕРАЛЫ обоих текстов отказа в прод-дереве.

Предмет KN-RTX-08: у каждого текста ровно одно объявление. Литерал, написанный вторым местом, заводит копию, которая разойдётся с первой молча — на всяком входе, кроме сериализационного конфликта, обе стороны отвечают одинаково.

func (TerminalRefusalCensus) String added in v0.3.0

func (c TerminalRefusalCensus) String() string

String — перепись одной строкой.

type TokenClaimCensus added in v0.2.0

type TokenClaimCensus struct {
	Literals  int
	Shaped    int
	Positions int
}

TokenClaimCensus — объём осмотренного одним файлом.

type TokenClaimForm added in v0.2.0

type TokenClaimForm string

TokenClaimForm — в какой позиции стоит имя.

const (
	TokenClaimFormKey   TokenClaimForm = "ключ состава"         // #nosec G101 -- подпись позиции разбора, не удостоверение
	TokenClaimFormRead  TokenClaimForm = "чтение по имени"      // #nosec G101 -- подпись позиции разбора, не удостоверение
	TokenClaimFormCase  TokenClaimForm = "разбор по имени"      // #nosec G101 -- подпись позиции разбора, не удостоверение
	TokenClaimFormArg   TokenClaimForm = "имя в вызове"         // #nosec G101 -- подпись позиции разбора, не удостоверение
	TokenClaimFormConst TokenClaimForm = "объявление константы" // #nosec G101 -- подпись позиции разбора, не удостоверение
)

Значения — ПРОЗА для человека, читающего находку, а не материал удостоверения. Сканер безопасности видит здесь форму «имя с `token`/`claim` получает строковый литерал» и по ней подозревает вшитое удостоверение (G101, уверенность LOW). Подозрение снимается предметом: перечисляется ПОЗИЦИЯ имени в разборе (ключ состава · чтение · разбор · аргумент · объявление), и ни одно значение не участвует ни в одной проверке подлинности — они попадают только в текст находки. Подавление стоит НА КАЖДОЙ СТРОКЕ объявления, а не на `const (`: оговорка на строке блока этим сканером к отдельным объявлениям не применяется — проверено прогоном пина (до правки level=error 5, после 0), а не прочтением. Ни на что за пределами этих пяти строк подавление не распространяется.

type TokenClaimUse added in v0.2.0

type TokenClaimUse struct {
	File      string
	Line      int
	Func      string
	Namespace string
	Name      string
	Form      TokenClaimForm
}

TokenClaimUse — одно употребление имени клейма чужого словаря.

type TreeCorpus added in v0.4.0

type TreeCorpus map[string]string

TreeCorpus — тела отобранных файлов по относительному пути от корня дерева.

func CorpusFrom added in v0.4.0

func CorpusFrom(tree *treecorpus.Tree, want func(rel string) bool) (TreeCorpus, error)

CorpusFrom — тела файлов дерева, отобранные предикатом `want`.

Отбор ПАРАМЕТР, а корпус — значение: так гейт перестаёт строить свой обход в теле пробы, а инъекция получает возможность подать тот же отбор пустому дереву.

ТРИ ИСХОДА, И ТРЕТИЙ НАЗВАН ОТДЕЛЬНОЙ ОШИБКОЙ:

корпус непуст            — вердикт выносится;
файл не прочитан         — отказ с координатой: гейт не вправе судить
                           документ, которого он не читал;
не отобрано ни одного     — ErrEmptyTraversal, и это НЕ «находок нет».

func ExclusionFormGoCorpus added in v0.4.0

func ExclusionFormGoCorpus(tree *treecorpus.Tree) (TreeCorpus, error)

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

Дерево приходит параметром, отбор объявлен один раз, пустой обход — отказ, а не «находок ноль» (задача #17). Отбор сужен `ProductionGoFile`, то есть служебные каталоги (документация, оснастка, вендоренное) из него выпадают; на этом дереве сужение не меняет НИЧЕГО — файлов Go под ними ноль, — а по построению делает обход тем же, каким его видят соседние семейства.

func ExportProcedureGuides added in v0.4.0

func ExportProcedureGuides(tree *treecorpus.Tree) (TreeCorpus, error)

ExportProcedureGuides — корпус инструкций обновления из ДЕРЕВА.

Дерево приходит параметром, а отбор объявлен здесь и больше нигде: гейт и инъекция зовут ОДНУ функцию, поэтому синтетика проверяет тот же отбор, что исполняется на боевом прогоне, а не его копию. Пустой обход — отказ (`ErrEmptyTraversal`), а не «находок ноль».

func ManifestLoaderCorpus added in v0.4.0

func ManifestLoaderCorpus(tree *treecorpus.Tree) (TreeCorpus, error)

ManifestLoaderCorpus — прод-файлы ЗАГРУЗЧИКА манифеста.

func MigrationCorpus added in v0.4.0

func MigrationCorpus(tree *treecorpus.Tree) (TreeCorpus, error)

MigrationCorpus — файлы миграций из ДЕРЕВА.

Сборщик общий на два семейства (словарь алгоритма и писатель роли модуля): обе прежде строили обход сами, и премисы «миграций прочитано ноль» у обеих стояли в теле пробы, где подать им пустое дерево было нечем (#17).

func MirrorCandidateCorpus added in v0.4.0

func MirrorCandidateCorpus(tree *treecorpus.Tree) (TreeCorpus, error)

MirrorWritesIn разбирает исходник Go и возвращает записи в зеркало, приписанные объемлющей функции, плюс число литералов, называющих таблицу вообще (перепись предпосылки: читатели тоже считаются). MirrorCandidateCorpus — непроверочные файлы Go дерева, среди которых ищутся писатели зеркала.

Дерево приходит параметром, отбор объявлен один раз (`ProductionGoFile`), и пустой обход даёт отказ, а не «находок ноль». Прежде обход строился в теле пробы от корня своего модуля, и его премиса не исполнялась ни разу (#17).

func ModuleSetDeclCorpus added in v0.4.0

func ModuleSetDeclCorpus(tree *treecorpus.Tree) (TreeCorpus, error)

ScanModuleSetEnumerations судит перечни ОДНОГО файла поверхности.

Возвращает находки и перепись; вызывающий складывает перепись по файлам сам — ему же принадлежит решение, какие файлы читать. ModuleSetDeclCorpus — файлы ПАКЕТА, из разбора которого выводится набор.

Дерево параметром, отбор объявлен здесь, пустой обход — отказ (#17).

func ModuleSetSurfaceCorpus added in v0.4.0

func ModuleSetSurfaceCorpus(tree *treecorpus.Tree) (TreeCorpus, error)

ModuleSetSurfaceCorpus — файлы клиентской поверхности из ДЕРЕВА.

func SubjectChangeProducerCorpus added in v0.4.0

func SubjectChangeProducerCorpus(tree *treecorpus.Tree) (TreeCorpus, error)

IsSubjectChangeProducerFile — лежит ли координата в слое use-case и не проба ли это. SubjectChangeProducerCorpus — корпус производителей полосы самосброса из ДЕРЕВА.

Отбор объявлен `IsSubjectChangeProducerFile` и зовётся отсюда, а дерево приходит параметром: гейт и инъекция ходят ОДНОЙ дорогой, поэтому синтетика проверяет тот же отбор, что исполняется на боевом прогоне. Пустой обход — отказ (`ErrEmptyTraversal`), а не «находок ноль».

func VerbClassRuleCorpus added in v0.4.0

func VerbClassRuleCorpus(tree *treecorpus.Tree) (TreeCorpus, error)

VerbClassRuleCorpus — корпус, в котором ищется объявление правила.

Дерево параметром, отбор объявлен здесь, пустой обход — отказ (#17): прежде обход строился в теле пробы от корня своего модуля, и его премиса «обход не прочитал ни одного файла» не исполнялась ни разу.

func (TreeCorpus) Rels added in v0.4.0

func (c TreeCorpus) Rels() []string

Rels — относительные пути корпуса в устойчивом порядке. Детерминизм входа — часть контракта проверки: обход, отдающий файлы в разном порядке, даёт находки в разном порядке, и два прогона становятся несравнимы.

type TrunkHolderCensus added in v0.3.0

type TrunkHolderCensus struct {
	// Jobs — заданий в процессе; Needed — сколько из них перечислено держателем.
	Jobs   int
	Needed int
	// Steps — шагов у держателя; RunBodies — из них с непустым телом.
	Steps      int
	RunBodies  int
	SelfTests  int
	Verdicts   int
	JobPerms   int
	FlowPerms  int
	HolderSeen bool
	// CancelInProgress — вытесняет ли процесс собственный прогон. От этого
	// зависит, чем условие держателя обязано быть.
	CancelInProgress bool
}

TrunkHolderCensus — объём осмотренного.

func AuditTrunkHolderWiring added in v0.3.0

func AuditTrunkHolderWiring(raw string) ([]string, TrunkHolderCensus, error)

AuditTrunkHolderWiring — вердикт о провязке держателя.

Вынесено ЧИСТОЙ функцией от текста объявления затем, чтобы способность гейта упасть доказывалась подачей входа, а не чтением.

func (TrunkHolderCensus) String added in v0.3.0

func (c TrunkHolderCensus) String() string

String — перепись одной строкой.

type TrunkProcessCensus added in v0.4.0

type TrunkProcessCensus struct {
	// Files — объявлений прочитано; OnTrunk — из них идущих по push в ствол;
	// WithHolder — из тех, что несут держателя.
	Files      int
	OnTrunk    int
	WithHolder int
}

TrunkProcessCensus — объём осмотренного по КОРПУСУ процессов.

func AuditTrunkProcesses added in v0.4.0

func AuditTrunkProcesses(corpus map[string]string) ([]string, TrunkProcessCensus, error)

AuditTrunkProcesses — вердикт о том, что у КАЖДОГО процесса ствола есть читатель, и что провязка каждого исправна.

Вход — имя объявления → его текст. Чистая функция от корпуса затем, чтобы инъекция подавалась входом, а не правкой дерева.

func (TrunkProcessCensus) String added in v0.4.0

func (c TrunkProcessCensus) String() string

String — перепись одной строкой. «Ноль находок» обязано быть отличимо от «ноль прочитанного», поэтому печатаются все три величины, а не последняя.

type TrunkRegisterCensus added in v0.4.0

type TrunkRegisterCensus struct {
	// Rows — строк перечня «что не переносится»; Complete — из них с непустым
	// производителем. Contexts — строк таблицы обязательных контекстов.
	Rows, Complete, Contexts int
	// JobsNamed — упомянутых заданий; JobsResolved — из них найденных в дереве.
	JobsNamed, JobsResolved int
	// ProcessesNamed — процессов ствола, названных перечнем, из ProcessesOnTrunk.
	ProcessesNamed, ProcessesOnTrunk int
}

TrunkRegisterCensus — объём осмотренного.

func AuditTrunkRegister added in v0.4.0

func AuditTrunkRegister(raw string, jobs map[string]string, trunkProcesses []string) ([]string, TrunkRegisterCensus, error)

AuditTrunkRegister — вердикт о перечне.

jobs — задания, существующие в дереве (имя задания → процесс); trunkProcesses — отображаемые имена процессов ствола. Чистая функция от входа затем, чтобы инъекция подавалась входом, а не правкой дерева.

func (TrunkRegisterCensus) String added in v0.4.0

func (c TrunkRegisterCensus) String() string

String — перепись одной строкой: «ноль находок» обязано быть отличимо от «ноль прочитанного».

type VerbFormSentinelCensus added in v0.2.0

type VerbFormSentinelCensus struct {
	// CompositeLits — составных литералов прочитано. Предпосылка оси: разбор
	// ищет присваивание внутри литерала, и ноль литералов означает, что
	// искать было негде.
	CompositeLits int
	// Idents — идентификаторов прочитано: объём разбора в самой мелкой единице.
	Idents int
	// SentinelReturns — возвратов сентинела найдено.
	SentinelReturns int
}

VerbFormSentinelCensus — объём, осмотренный разбором ОДНОГО файла.

func ScanVerbFormSentinel added in v0.2.0

func ScanVerbFormSentinel(rel string, src []byte) (VerbFormSentinelCensus, error)

ScanVerbFormSentinel считает ВОЗВРАТЫ сентинела в одном файле Go.

Возвратом считается присваивание `kind: <Сентинел>` в составном литерале, стоящем внутри `return` — то есть исход функции, а не упоминание имени.

type Vertex added in v0.3.0

type Vertex int

Vertex — вершина, относительно которой задан вопрос об истории.

const (
	// VertexUnnamed — вершина ЛИТЕРАЛОМ НЕ НАЗВАНА: она пришла переменной либо
	// оставлена умолчанию (`git log` без ревизии есть `git log HEAD`).
	//
	// Это НЕ «вершина неизвестна разбору» и не молчание: состояние объявлено,
	// считается и требует записанного довода — иначе «сказано, судит она ствол
	// или рабочую вершину» осталось бы необеспеченным ровно там, где вершину и
	// не видно.
	VertexUnnamed Vertex = iota
	// VertexHead — среди литералов стоит рабочая вершина.
	VertexHead
	// VertexTrunk — среди литералов стоит объявленный ствол.
	VertexTrunk
)

func (Vertex) String added in v0.3.0

func (v Vertex) String() string

String называет вершину словом вызывающего, а не номером.

type WrapperPair added in v0.2.0

type WrapperPair struct {
	PkgDir   string
	BoolName string
	ENames   []string
}

WrapperPair — вопрос, у которого автор пакета объявил ОБЕ формы.

func (WrapperPair) OutcomeForms added in v0.2.0

func (p WrapperPair) OutcomeForms() string

OutcomeForms — половины с исходом, перечисленные для сообщения.

type WrapperScanReport added in v0.2.0

type WrapperScanReport struct {
	Roots      []string
	Files      int
	Generated  int
	DotImports int
	Pairs      []WrapperPair
	Found      []BoolWrapperCall
}

WrapperScanReport — что именно осмотрено. Печатается ВСЕГДА.

func ScanBoolWrapperCalls added in v0.2.0

func ScanBoolWrapperCalls(root string, roots []string, under func(string) ([]string, error)) (WrapperScanReport, error)

ScanBoolWrapperCalls — два прохода по одному корпусу: сперва вывести пары, затем найти их употребления. under — обходчик поддерева (обычно `treecorpus.Under`), подаётся вызывающим, чтобы инъекция могла подставить синтетическое дерево без записи в рабочую копию.

Source Files

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL