Граф зависимостей и уровни доказательности
Типы, объявленные в репозитории, образуют замкнутый словарь. Каждое имя в исходнике резолвится в объявление в том же порядке, что использует C#: свой namespace, затем объемлющие, затем импорты файла. Имя, не совпавшее ни с одним объявлением, — внешний импорт, а не догадка; имя с несколькими кандидатами — unresolved и в граф не попадает. Доля резолва печатается в отчёте.
Каждое ребро несёт оценку EvidenceGrade:
- Proven — имя стоит там, где язык не допускает ничего, кроме типа:
new, base list, тип параметра, поля, свойства или возврата, generic-аргумент, атрибут,typeof,sizeof,default,catch, либо тип, за которым следует вводимое им имя. - Inferred — имя совпало, но позиция ничего не доказывает: member access, аргумент, локальная переменная, приведение.
Blocking-находка строится только из Proven-рёбер. Тот же Proven-граф питает циклы модулей,
инварианты sliced-dotnet и DSM-бюджет. Всё, что связывает компилятор — extension-методы, var,
перегрузки, DI, рефлексия, — невидимо; связанность занижена, никогда не завышена.
Граница модуля. Имя модуля вложено в имя объемлющего: ссылка из Shop.Orders в
Shop.Orders.Contracts — содержание, а не зависимость. Ребро поднимается до первого сегмента, которым
имена расходятся: Shop.Orders.Api → Shop.Billing.Core записывается как Shop.Orders → Shop.Billing.
namespace Shop.Orders;
public sealed class OrderService(IOrderStore store)
{
private readonly Clock clock = new Clock();
public Receipt Place(Cart cart)
{
var total = Pricing.Total(cart);
if (cart.Lines is [])
{
throw new EmptyCartException();
}
return store.Save(cart, total, clock.Now());
}
}
| тип параметра, поля, возврата | Proven: IOrderStore, Clock, Receipt, Cart |
после new, typeof, catch, is | Proven: new Clock(), new EmptyCartException() |
| member access, аргумент, локальная | Inferred: Pricing.Total — имя совпало, позиция не доказывает |
store, cart, total | не типы репозитория — рёбер нет |
Shop.Orders → Shop.Pricing не возникнет из строки с Pricing.Total: member access — только Inferred. Если Pricing нигде не стоит в типовой позиции, цикл через него не замкнётся.