`:** capture the type-arg as a
`references` to `CatalogItem` (bonus DTO coverage).
- **Name collisions:** component/model names are usually unique; rely on the
name-matcher's existing proximity scoring. Same-named class in another language is
blocked by the family gate.
- **Razor `@{ ... }` C# blocks:** contain real C# (calls, `new`) — P-future; regex
scanning the C# inside markup is noisy. Defer (the directives above are the wins).
- **`.razor` is NOT `.cs`:** must add to `grammars.ts` + the indexer's include globs
(verify `.razor`/`.cshtml` aren't in a default-exclude).
## Validation (per the engine's methodology)
1. Build `RazorExtractor`; unit tests in `__tests__/extraction.test.ts` (a `.cshtml`
with `@model X` covers `X`; a `.razor` with `` covers it; an HTML
`` does NOT create an edge).
2. Re-measure eShopOnWeb FAIR coverage before/after (`/tmp/faircov.cjs`): target
77% → ~90%; **node count stable** (only +template-file component nodes); residual
zeros are the reflection/value-read set only.
3. No regression on a non-.NET control (gin/requests) and on the Razor-free C#
repos (cs-mediatr/cs-polly unchanged).
4. Record in this doc + the coverage handoff.
## Effort
- P1: ~0.5 day (extractor skeleton + `@model`/`@inject` scan + family-gate fix + tests).
- P2: ~1 day (Blazor tags + code-behind + generic type-args).
- P3: ~0.5 day. P4 (Thymeleaf/Django): ~1–2 days, low ROI — defer.
- **Total for the ASP.NET win (P1+P2+P3): ~2 days → ASP.NET ~90%.**
## Non-goals (and what's still needed for 95% on convention apps)
This feature does NOT close: reflection/proxy registration (Spring Data repository
proxies, AutoMapper profiles, Swagger filters, DI container / middleware), property-
string data bindings (`asp-for`/`th:field`), or C# static-const value reads
(`Constants.X`). Convention apps reaching literal 95% additionally need a **reflection/
DI-registration modeling** pass and **extending the static-member pass to C#/TS** —
tracked separately. Markup parsing is the single biggest, most self-contained step.