@cratis/pi 7.102.0 → 7.103.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/package/corpus/harnesses/copilot/instructions/profiles.instructions.md +10 -1
  2. package/package/corpus/harnesses/copilot/instructions/pull-requests.instructions.md +2 -0
  3. package/package/corpus/harnesses/copilot/instructions/secrets.instructions.md +4 -0
  4. package/package/corpus/hooks/README.md +11 -1
  5. package/package/corpus/hooks/scripts/cratis-check-pr.mjs +12 -1
  6. package/package/corpus/hooks/scripts/cratis-guard-secrets.sh +79 -23
  7. package/package/corpus/hooks/scripts/cratis-guard-writes.sh +145 -40
  8. package/package/corpus/rules/profiles.md +10 -1
  9. package/package/corpus/rules/pull-requests.md +2 -0
  10. package/package/corpus/rules/secrets.md +4 -0
  11. package/package/corpus/skills/analyzing-dotnet-performance/LICENSE +23 -0
  12. package/package/corpus/skills/analyzing-dotnet-performance/NOTICE +36 -0
  13. package/package/corpus/skills/analyzing-dotnet-performance/SKILL.md +214 -0
  14. package/package/corpus/skills/analyzing-dotnet-performance/references/async-patterns.md +122 -0
  15. package/package/corpus/skills/analyzing-dotnet-performance/references/collections-and-linq.md +220 -0
  16. package/package/corpus/skills/analyzing-dotnet-performance/references/critical-patterns.md +291 -0
  17. package/package/corpus/skills/analyzing-dotnet-performance/references/io-and-serialization.md +135 -0
  18. package/package/corpus/skills/analyzing-dotnet-performance/references/memory-and-strings.md +219 -0
  19. package/package/corpus/skills/analyzing-dotnet-performance/references/regex-patterns.md +95 -0
  20. package/package/corpus/skills/analyzing-dotnet-performance/references/structural-patterns.md +38 -0
  21. package/package/corpus/skills/binlog-generation/LICENSE +23 -0
  22. package/package/corpus/skills/binlog-generation/NOTICE +22 -0
  23. package/package/corpus/skills/binlog-generation/SKILL.md +129 -0
  24. package/package/corpus/skills/check-bin-obj-clash/LICENSE +23 -0
  25. package/package/corpus/skills/check-bin-obj-clash/NOTICE +27 -0
  26. package/package/corpus/skills/check-bin-obj-clash/SKILL.md +127 -0
  27. package/package/corpus/skills/check-bin-obj-clash/references/common-causes-and-fixes.md +206 -0
  28. package/package/corpus/skills/coverage-analysis/LICENSE +23 -0
  29. package/package/corpus/skills/coverage-analysis/NOTICE +32 -0
  30. package/package/corpus/skills/coverage-analysis/SKILL.md +198 -0
  31. package/package/corpus/skills/coverage-analysis/references/guidelines.md +68 -0
  32. package/package/corpus/skills/coverage-analysis/references/output-format.md +91 -0
  33. package/package/corpus/skills/coverage-analysis/references/report-generation.md +58 -0
  34. package/package/corpus/skills/coverage-analysis/references/setup-discovery.md +307 -0
  35. package/package/corpus/skills/coverage-analysis/scripts/Compute-CrapScores.ps1 +80 -0
  36. package/package/corpus/skills/coverage-analysis/scripts/CoverageData.ps1 +272 -0
  37. package/package/corpus/skills/coverage-analysis/scripts/Extract-MethodCoverage.ps1 +65 -0
  38. package/package/corpus/skills/csharp-refactoring/LICENSE +23 -0
  39. package/package/corpus/skills/csharp-refactoring/NOTICE +22 -0
  40. package/package/corpus/skills/csharp-refactoring/SKILL.md +175 -0
  41. package/package/corpus/skills/csharp-refactoring/references/operation-catalog.md +37 -0
  42. package/package/corpus/skills/directory-build-organization/LICENSE +23 -0
  43. package/package/corpus/skills/directory-build-organization/NOTICE +21 -0
  44. package/package/corpus/skills/directory-build-organization/SKILL.md +205 -0
  45. package/package/corpus/skills/directory-build-organization/references/common-patterns.md +56 -0
  46. package/package/corpus/skills/directory-build-organization/references/multi-level-examples.md +167 -0
  47. package/package/corpus/skills/directory-build-organization/references/targetframework-props-pitfall.md +54 -0
  48. package/package/corpus/skills/dotnet-aot-compat/LICENSE +23 -0
  49. package/package/corpus/skills/dotnet-aot-compat/NOTICE +18 -0
  50. package/package/corpus/skills/dotnet-aot-compat/SKILL.md +265 -0
  51. package/package/corpus/skills/dotnet-aot-compat/references/polyfills.md +43 -0
  52. package/package/corpus/skills/dotnet-trace-collect/LICENSE +23 -0
  53. package/package/corpus/skills/dotnet-trace-collect/NOTICE +65 -0
  54. package/package/corpus/skills/dotnet-trace-collect/SKILL.md +116 -0
  55. package/package/corpus/skills/dotnet-trace-collect/references/dotnet-monitor.md +97 -0
  56. package/package/corpus/skills/dotnet-trace-collect/references/dotnet-trace-collect-linux.md +84 -0
  57. package/package/corpus/skills/dotnet-trace-collect/references/dotnet-trace-collect.md +91 -0
  58. package/package/corpus/skills/dotnet-trace-collect/references/perfcollect.md +200 -0
  59. package/package/corpus/skills/dotnet-trace-collect/references/perfview.md +141 -0
  60. package/package/corpus/skills/dotnet-trace-collect/references/tool-selection.md +160 -0
  61. package/package/corpus/skills/dump-collect/LICENSE +23 -0
  62. package/package/corpus/skills/dump-collect/NOTICE +40 -0
  63. package/package/corpus/skills/dump-collect/SKILL.md +97 -0
  64. package/package/corpus/skills/dump-collect/references/container-dumps.md +412 -0
  65. package/package/corpus/skills/dump-collect/references/coreclr-dumps.md +108 -0
  66. package/package/corpus/skills/dump-collect/references/nativeaot-dumps.md +280 -0
  67. package/package/corpus/skills/eliminate-redundant-restores/LICENSE +23 -0
  68. package/package/corpus/skills/eliminate-redundant-restores/NOTICE +19 -0
  69. package/package/corpus/skills/eliminate-redundant-restores/SKILL.md +112 -0
  70. package/package/corpus/skills/extension-points/LICENSE +23 -0
  71. package/package/corpus/skills/extension-points/NOTICE +18 -0
  72. package/package/corpus/skills/extension-points/SKILL.md +248 -0
  73. package/package/corpus/skills/filter-syntax/LICENSE +23 -0
  74. package/package/corpus/skills/filter-syntax/NOTICE +17 -0
  75. package/package/corpus/skills/filter-syntax/SKILL.md +179 -0
  76. package/package/corpus/skills/including-generated-files/LICENSE +23 -0
  77. package/package/corpus/skills/including-generated-files/NOTICE +17 -0
  78. package/package/corpus/skills/including-generated-files/SKILL.md +139 -0
  79. package/package/corpus/skills/microbenchmarking/LICENSE +23 -0
  80. package/package/corpus/skills/microbenchmarking/NOTICE +36 -0
  81. package/package/corpus/skills/microbenchmarking/SKILL.md +131 -0
  82. package/package/corpus/skills/microbenchmarking/references/bdn-internals-and-tuning.md +143 -0
  83. package/package/corpus/skills/microbenchmarking/references/comparison-strategies.md +200 -0
  84. package/package/corpus/skills/microbenchmarking/references/diagnosers-and-exporters.md +150 -0
  85. package/package/corpus/skills/microbenchmarking/references/project-setup-and-running.md +189 -0
  86. package/package/corpus/skills/microbenchmarking/references/writing-benchmarks.md +310 -0
  87. package/package/corpus/skills/msbuild/LICENSE +23 -0
  88. package/package/corpus/skills/msbuild/NOTICE +55 -0
  89. package/package/corpus/skills/msbuild/SKILL.md +117 -0
  90. package/package/corpus/skills/msbuild/references/antipatterns/additional-antipatterns.md +291 -0
  91. package/package/corpus/skills/msbuild/references/antipatterns/incremental-build-inputs-outputs.md +57 -0
  92. package/package/corpus/skills/msbuild/references/antipatterns/private-assets.md +29 -0
  93. package/package/corpus/skills/msbuild/references/binlog-failure-analysis.md +85 -0
  94. package/package/corpus/skills/msbuild/references/binlog-generation.md +69 -0
  95. package/package/corpus/skills/msbuild/references/build-perf-baseline.md +493 -0
  96. package/package/corpus/skills/msbuild/references/build-perf-diagnostics.md +268 -0
  97. package/package/corpus/skills/msbuild/references/copy-to-output-directory.md +183 -0
  98. package/package/corpus/skills/msbuild/references/eval-performance.md +190 -0
  99. package/package/corpus/skills/msbuild/references/extension-points.md +281 -0
  100. package/package/corpus/skills/msbuild/references/incremental-build.md +365 -0
  101. package/package/corpus/skills/msbuild/references/msbuild-antipatterns.md +401 -0
  102. package/package/corpus/skills/orleans/LICENSE +21 -0
  103. package/package/corpus/skills/orleans/NOTICE +64 -0
  104. package/package/corpus/skills/orleans/SKILL.md +140 -0
  105. package/package/corpus/skills/orleans/references/anti-patterns.md +660 -0
  106. package/package/corpus/skills/orleans/references/configuration-api.md +933 -0
  107. package/package/corpus/skills/orleans/references/examples.md +66 -0
  108. package/package/corpus/skills/orleans/references/grain-api.md +784 -0
  109. package/package/corpus/skills/orleans/references/grains.md +75 -0
  110. package/package/corpus/skills/orleans/references/hosting.md +71 -0
  111. package/package/corpus/skills/orleans/references/implementation.md +591 -0
  112. package/package/corpus/skills/orleans/references/official-docs-index.md +250 -0
  113. package/package/corpus/skills/orleans/references/patterns.md +811 -0
  114. package/package/corpus/skills/orleans/references/persistence-api.md +495 -0
  115. package/package/corpus/skills/orleans/references/primitive-selection.md +35 -0
  116. package/package/corpus/skills/orleans/references/scheduling-and-services.md +295 -0
  117. package/package/corpus/skills/orleans/references/serialization-api.md +299 -0
  118. package/package/corpus/skills/orleans/references/streaming-api.md +396 -0
  119. package/package/corpus/skills/orleans/references/testing-patterns.md +210 -0
  120. package/package/corpus/skills/platform-detection/LICENSE +23 -0
  121. package/package/corpus/skills/platform-detection/NOTICE +17 -0
  122. package/package/corpus/skills/platform-detection/SKILL.md +230 -0
  123. package/package/corpus/skills/platform-detection/references/command-mode.md +27 -0
  124. package/package/corpus/skills/profiling/LICENSE +21 -0
  125. package/package/corpus/skills/profiling/NOTICE +50 -0
  126. package/package/corpus/skills/profiling/SKILL.md +144 -0
  127. package/package/corpus/skills/profiling/references/commands.md +439 -0
  128. package/package/corpus/skills/profiling/references/patterns.md +586 -0
  129. package/package/corpus/skills/profiling/references/profiling.md +190 -0
  130. package/package/corpus/skills/run-tests/LICENSE +23 -0
  131. package/package/corpus/skills/run-tests/NOTICE +19 -0
  132. package/package/corpus/skills/run-tests/SKILL.md +305 -0
  133. package/package/corpus/skills/target-authoring/LICENSE +23 -0
  134. package/package/corpus/skills/target-authoring/NOTICE +17 -0
  135. package/package/corpus/skills/target-authoring/SKILL.md +165 -0
  136. package/package/corpus/skills/vectorization/LICENSE +23 -0
  137. package/package/corpus/skills/vectorization/NOTICE +17 -0
  138. package/package/corpus/skills/vectorization/SKILL.md +189 -0
  139. package/package/profile-catalog.json +85 -1
  140. package/package.json +1 -1
@@ -0,0 +1,248 @@
1
+ ---
2
+ name: extension-points
3
+ description: 'Owns MSBuild import and hook discovery: CustomBefore and CustomAfter hooks, ordered wildcard and NuGet auto-imports, control properties, build and buildTransitive packed layout, package ID and file-name matching, per-TFM forwarders, and tracing why assets or hooks are missing, broken, or replaced. Use when imports or hooks do not run, run in the wrong order, or are overwritten. Not for a verdict on whether one Import needs an Exists guard (use the msbuild skill''s antipatterns reference), target Inputs/Outputs or incremental skipping (use target-authoring), or props-versus-targets placement (use directory-build-organization).'
4
+ license: MIT
5
+ ---
6
+
7
+ <!-- Modified by Cratis from dotnet's original (MIT): frontmatter, applicability, navigation and the changes listed in NOTICE. Upstream: https://github.com/dotnet/skills (plugins/dotnet-msbuild/skills/extension-points/SKILL.md; see NOTICE) -->
8
+
9
+ # MSBuild Extension Points
10
+
11
+ Cratis rules in `.cratis/ai/rules/` (including `csharp.md`, `specs.csharp.md`, and `orleans.md`) and the `cratis-*` skills win where they differ.
12
+
13
+ How the MSBuild pipeline provides hooks for SDKs, NuGet packages, repos, and users to inject custom logic.
14
+
15
+ ## CustomBefore / CustomAfter Hooks
16
+
17
+ Every major `.targets` file defines import hooks:
18
+
19
+ ```xml
20
+ <PropertyGroup>
21
+ <CustomBeforeMicrosoftCommonTargets Condition="'$(CustomBeforeMicrosoftCommonTargets)' == ''">
22
+ $(MSBuildExtensionsPath)\v$(MSBuildToolsVersion)\Custom.Before.Microsoft.Common.targets
23
+ </CustomBeforeMicrosoftCommonTargets>
24
+ </PropertyGroup>
25
+
26
+ <Import Project="$(CustomBeforeMicrosoftCommonTargets)"
27
+ Condition="'$(CustomBeforeMicrosoftCommonTargets)' != '' and Exists('$(CustomBeforeMicrosoftCommonTargets)')"/>
28
+ <!-- ... core targets ... -->
29
+ <Import Project="$(CustomAfterMicrosoftCommonTargets)"
30
+ Condition="'$(CustomAfterMicrosoftCommonTargets)' != '' and Exists('$(CustomAfterMicrosoftCommonTargets)')"/>
31
+ ```
32
+
33
+ ### Rules
34
+
35
+ - Default path includes version (`v$(MSBuildToolsVersion)`) for side-by-side installations.
36
+ - Always check `Exists()`. The file may not be present on every machine.
37
+ - **Append** to the property (don't overwrite) to chain multiple hooks:
38
+
39
+ ```xml
40
+ <PropertyGroup>
41
+ <CustomBeforeMicrosoftCommonTargets>
42
+ $(CustomBeforeMicrosoftCommonTargets);$(MSBuildThisFileDirectory)MyExtension.targets
43
+ </CustomBeforeMicrosoftCommonTargets>
44
+ </PropertyGroup>
45
+ ```
46
+
47
+ ## Wildcard Import Directories
48
+
49
+ MSBuild imports all files in extension directories, sorted alphabetically:
50
+
51
+ ```xml
52
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Imports\Microsoft.Common.props\ImportBefore\*"
53
+ Condition="'$(ImportByWildcardBeforeMicrosoftCommonProps)' == 'true'
54
+ and Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Imports\Microsoft.Common.props\ImportBefore')" />
55
+ ```
56
+
57
+ ### Key paths
58
+
59
+ | Property | Resolves to | Scope |
60
+ |---|---|---|
61
+ | `$(MSBuildUserExtensionsPath)` | `%APPDATA%\Microsoft\MSBuild` | Per-user |
62
+ | `$(MSBuildExtensionsPath)` | MSBuild install directory | Machine-wide |
63
+ | `$(MSBuildProjectExtensionsPath)` | `obj/` directory | Per-project (NuGet) |
64
+
65
+ Name files with numeric prefixes for ordering: `01-first.props`, `02-second.props`.
66
+
67
+ ## Import Gating — Control Properties
68
+
69
+ Every wildcard import is gated by a boolean property:
70
+
71
+ ```xml
72
+ <PropertyGroup>
73
+ <ImportByWildcardBeforeMicrosoftCommonProps
74
+ Condition="'$(ImportByWildcardBeforeMicrosoftCommonProps)' == ''">true</ImportByWildcardBeforeMicrosoftCommonProps>
75
+ <ImportDirectoryBuildProps
76
+ Condition="'$(ImportDirectoryBuildProps)' == ''">true</ImportDirectoryBuildProps>
77
+ </PropertyGroup>
78
+ ```
79
+
80
+ ### Available control properties
81
+
82
+ | Property | What it disables |
83
+ |---|---|
84
+ | `ImportDirectoryBuildProps` | Directory.Build.props auto-discovery |
85
+ | `ImportDirectoryBuildTargets` | Directory.Build.targets auto-discovery |
86
+ | `ImportProjectExtensionProps` | NuGet-generated `*.props` in obj/ |
87
+ | `ImportProjectExtensionTargets` | NuGet-generated `*.targets` in obj/ |
88
+ | `ImportByWildcardBefore*` | Machine-level ImportBefore extensions |
89
+ | `ImportByWildcardAfter*` | Machine-level ImportAfter extensions |
90
+
91
+ ## NuGet Package Build Extension Layout
92
+
93
+ NuGet packages inject build logic via `build/` or `buildTransitive/` folders:
94
+
95
+ ```text
96
+ MyPackage/
97
+ build/
98
+ MyPackage.props ← imported via *.props wildcard
99
+ MyPackage.targets ← imported via *.targets wildcard
100
+ buildTransitive/
101
+ MyPackage.props ← imported by transitive consumers
102
+ MyPackage.targets
103
+ ```
104
+
105
+ ### Rules
106
+
107
+ - File names **must match the package ID** exactly.
108
+ - `build/` affects direct consumers only. `buildTransitive/` affects the entire dependency chain.
109
+ - Props are imported early (before the project), targets are imported late (after the project).
110
+
111
+ ### Forwarding chain: `buildTransitive/` → `build/` → shared
112
+
113
+ Forward `buildTransitive/*.props` and `buildTransitive/*.targets` through their sibling `build/*.props` / `build/*.targets` files (chain `buildTransitive → build → shared`) instead of importing `buildMultiTargeting/` directly. This keeps `build/` as the single source of truth with a clear ownership chain, so transitive consumers stay in sync with direct consumers instead of the two layouts drifting apart.
114
+
115
+ When `build/` is packed **per-TFM** (`build/<tfm>/`, via `TfmSpecificPackageFile`, a per-TFM `<PackagePath>`, or SDK conventions) while `buildMultiTargeting/` is not, a `buildTransitive/<tfm>/` forwarder **must include the TFM segment** — dropping it resolves to a non-existent package-root `build/MyPackage.props` and fails transitive consumers with **`MSB4019`**. Derive the segment from the file's own folder, never `$(TargetFramework)` (NuGet nearest-match can serve a `net10.0` consumer the `net9.0` folder, so `$(TargetFramework)` may name a folder that was never restored):
116
+
117
+ ```xml
118
+ <!-- buildTransitive/<tfm>/MyPackage.props -->
119
+ <Import Project="$(MSBuildThisFileDirectory)..\..\build\$([System.IO.Path]::GetFileName($([System.IO.Path]::GetDirectoryName('$(MSBuildThisFileDirectory)'))))\MyPackage.props" />
120
+ ```
121
+
122
+ ## Source Tree vs Packed Layout
123
+
124
+ When reviewing a NuGet build-extension package, the **source layout** in the repository can legitimately differ from the **packed layout** inside the produced `.nupkg`. This is a common source of false-positive "import points at a missing file" findings.
125
+
126
+ Three packaging mechanisms reshape the layout at pack time:
127
+
128
+ 1. **`.nuspec` `<file src=… target=…>` mappings** — copy a single source file into multiple per-TFM targets:
129
+
130
+ ```xml
131
+ <!-- Source tree has ONE shared file:
132
+ buildTransitive\common\MyAdapter.props
133
+ Pack rewrites it to per-TFM targets inside the .nupkg:
134
+ buildTransitive\net462\MyAdapter.props
135
+ buildTransitive\net8.0\MyAdapter.props
136
+ buildTransitive\net9.0\MyAdapter.props -->
137
+ <files>
138
+ <file src="buildTransitive\common\MyAdapter.props" target="buildTransitive\net462\MyAdapter.props" />
139
+ <file src="buildTransitive\common\MyAdapter.props" target="buildTransitive\net8.0\MyAdapter.props" />
140
+ <file src="buildTransitive\common\MyAdapter.props" target="buildTransitive\net9.0\MyAdapter.props" />
141
+ </files>
142
+ ```
143
+
144
+ In the `<file>` element, a `target` ending in `\` is treated as a folder (filename preserved from `src`); a `target` ending in a filename renames the file.
145
+
146
+ 2. **`.csproj` `<PackagePath>` metadata** on `<None Update=…>` or `<Content Include=…>` items — same effect via SDK pack. Use one item per destination to keep the mapping unambiguous:
147
+
148
+ ```xml
149
+ <ItemGroup>
150
+ <None Include="buildTransitive\common\MyAdapter.props" Pack="true" PackagePath="buildTransitive\net8.0\MyAdapter.props" />
151
+ <None Include="buildTransitive\common\MyAdapter.props" Pack="true" PackagePath="buildTransitive\net9.0\MyAdapter.props" />
152
+ </ItemGroup>
153
+ ```
154
+
155
+ NuGet/SDK pack also accepts a semicolon-separated list (`PackagePath="buildTransitive\net8.0\;buildTransitive\net9.0\"`) to fan one source out to multiple destinations, but the multi-item form above is harder to misread.
156
+
157
+ 3. **SDK conventions** — `IncludeBuildOutput`, `BuildOutputTargetFolder`, `IncludeContentInPack` automatically place built outputs under `lib/<tfm>/` or `build/<tfm>/`.
158
+
159
+ ### Implication for reviewers
160
+
161
+ A forwarder like the following inside a packed `build/net462/` folder is **not** a "missing-file" bug, even if the source tree has no `buildTransitive/net462/` directory:
162
+
163
+ ```xml
164
+ <!-- In packed build/net462/MyAdapter.props -->
165
+ <Project>
166
+ <Import Project="$(MSBuildThisFileDirectory)..\..\buildTransitive\net462\MyAdapter.props" />
167
+ </Project>
168
+ ```
169
+
170
+ Before flagging an unguarded `<Import>` inside a `build/<tfm>/` or `buildTransitive/<tfm>/` folder:
171
+
172
+ 1. Look for `*.nuspec` in the project directory and its immediate parent directory (do not walk further up). Read every `<file target=…>` whose `target` matches the imported path.
173
+ 2. Read the `.csproj` for `<PackagePath>` metadata on `<None>`/`<Content>` items.
174
+ 3. Only flag the import if the target path is missing from **both** the source tree *and* the projected package layout.
175
+
176
+ See also msbuild antipatterns AP-13 ("NuGet package forwarders" exception).
177
+
178
+ ## Import Guard Pattern
179
+
180
+ The `.targets` file ensures `.props` was imported using a guard property:
181
+
182
+ ```xml
183
+ <!-- End of Microsoft.Common.props -->
184
+ <PropertyGroup>
185
+ <MicrosoftCommonPropsHasBeenImported>true</MicrosoftCommonPropsHasBeenImported>
186
+ </PropertyGroup>
187
+
188
+ <!-- Top of Microsoft.Common.CurrentVersion.targets -->
189
+ <Import Project="Microsoft.Common.props"
190
+ Condition="'$(MicrosoftCommonPropsHasBeenImported)' != 'true'" />
191
+ ```
192
+
193
+ This handles projects that only import `.targets`.
194
+
195
+ ## Directory.Build Discovery
196
+
197
+ MSBuild walks up the directory tree to find the nearest `Directory.Build.props`:
198
+
199
+ ```xml
200
+ <_DirectoryBuildPropsBasePath>
201
+ $([MSBuild]::GetDirectoryNameOfFileAbove('$(MSBuildProjectDirectory)', 'Directory.Build.props'))
202
+ </_DirectoryBuildPropsBasePath>
203
+ ```
204
+
205
+ Only the **nearest** file is discovered. Nested hierarchies must explicitly import parents:
206
+
207
+ ```xml
208
+ <!-- src/Directory.Build.props -->
209
+ <PropertyGroup>
210
+ <_ParentPropsPath>$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))</_ParentPropsPath>
211
+ </PropertyGroup>
212
+ <Import Project="$(_ParentPropsPath)" Condition="'$(_ParentPropsPath)' != ''" />
213
+ ```
214
+
215
+ ## Creating Your Own Extension Point
216
+
217
+ ```xml
218
+ <!-- MySDK.targets -->
219
+ <Project>
220
+ <Import Project="MySDK.props" Condition="'$(MySDKPropsImported)' != 'true'" />
221
+
222
+ <PropertyGroup>
223
+ <CustomBeforeMySDK Condition="'$(CustomBeforeMySDK)' == ''">$(MSBuildProjectDirectory)\MySDK.Before.targets</CustomBeforeMySDK>
224
+ <CustomAfterMySDK Condition="'$(CustomAfterMySDK)' == ''">$(MSBuildProjectDirectory)\MySDK.After.targets</CustomAfterMySDK>
225
+ </PropertyGroup>
226
+
227
+ <Import Project="$(CustomBeforeMySDK)" Condition="Exists('$(CustomBeforeMySDK)')" />
228
+
229
+ <PropertyGroup>
230
+ <MySDKBuildDependsOn>BeforeMySDKBuild;CoreMySDKBuild;AfterMySDKBuild</MySDKBuildDependsOn>
231
+ </PropertyGroup>
232
+ <Target Name="MySDKBuild" DependsOnTargets="$(MySDKBuildDependsOn)" />
233
+ <Target Name="BeforeMySDKBuild" />
234
+ <Target Name="AfterMySDKBuild" />
235
+ <Target Name="CoreMySDKBuild">
236
+ <!-- implementation -->
237
+ </Target>
238
+
239
+ <Import Project="$(CustomAfterMySDK)" Condition="Exists('$(CustomAfterMySDK)')" />
240
+ </Project>
241
+ ```
242
+
243
+ ## Common Pitfalls
244
+
245
+ - **Missing `Exists()` on optional imports** causes build failures when files are absent. **Exception**: imports inside published `build/<tfm>/` and `buildTransitive/<tfm>/` folders of a NuGet package are a package contract — the target is guaranteed by the packed layout (see "Source Tree vs Packed Layout" above). Don't guard them and don't flag them.
246
+ - **Overwriting Custom* properties** drops prior hooks. Append with `;` separator.
247
+ - **NuGet package file names not matching package ID** silently skips the import.
248
+ - **Nested Directory.Build.props** without parent import loses repo-root settings.
@@ -0,0 +1,23 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) .NET Foundation and Contributors
4
+
5
+ All rights reserved.
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
@@ -0,0 +1,17 @@
1
+ Test Filter Syntax Reference
2
+ Copyright (c) .NET Foundation and Contributors
3
+ Licensed under the MIT License. See LICENSE.
4
+
5
+ Upstream source: https://github.com/dotnet/skills/blob/a6bf43ab61967c30919334986515163ab24d7635/plugins/dotnet-test/skills/filter-syntax/SKILL.md
6
+
7
+ Changes made by Cratis:
8
+
9
+ LICENSE:
10
+ - Copy upstream MIT license and copyright verbatim.
11
+
12
+ SKILL.md:
13
+ - Normalize frontmatter serialization, add MIT license where absent; move user-invocable, disable-model-invocation under metadata as strings.
14
+ - Add marked modification/source comment and applicability/Cratis precedence line with the skill-specific safety, ownership or compatibility caveat.
15
+ - Rewrite the description to the Cratis shape (what it does, Use when, Not for) and drop references to skills that are not part of this corpus.
16
+
17
+ NOTICE: Add this attribution, change list, and any download/execution disclosure.
@@ -0,0 +1,179 @@
1
+ ---
2
+ name: filter-syntax
3
+ description: 'Reference-only filter syntax for VSTest and Microsoft Testing Platform (MTP) with MSTest, NUnit, xUnit v3, and TUnit. Use when run-tests needs to create or translate a test filter after the platform and framework are known. Not for unfiltered runs or platform detection (use platform-detection); loaded by run-tests, never invoked directly.'
4
+ license: MIT
5
+ metadata:
6
+ user-invocable: 'false'
7
+ disable-model-invocation: 'true'
8
+ ---
9
+
10
+ <!-- Modified by Cratis from dotnet's original (MIT): frontmatter, applicability, navigation and the changes listed in NOTICE. Upstream: https://github.com/dotnet/skills (plugins/dotnet-test/skills/filter-syntax/SKILL.md; see NOTICE) -->
11
+
12
+ # Test Filter Syntax Reference
13
+
14
+ Cratis rules in `.cratis/ai/rules/` (including `csharp.md`, `specs.csharp.md`, and `orleans.md`) and the `cratis-*` skills win where they differ. Specification authoring belongs to **cratis-specifications-csharp**; Cratis core repositories run xUnit v2 on VSTest.
15
+
16
+ Filter syntax depends on the **platform** and **test framework**.
17
+
18
+ ## VSTest filters (MSTest, xUnit v2, NUnit on VSTest)
19
+
20
+ ```bash
21
+ dotnet test --filter <EXPRESSION>
22
+ ```
23
+
24
+ Expression syntax: `<Property><Operator><Value>[|&<Expression>]`
25
+
26
+ **Operators:**
27
+
28
+ | Operator | Meaning |
29
+ |----------|---------|
30
+ | `=` | Exact match |
31
+ | `!=` | Not exact match |
32
+ | `~` | Contains |
33
+ | `!~` | Does not contain |
34
+
35
+ **Combinators:** `|` (OR), `&` (AND). Parentheses for grouping: `(A|B)&C`
36
+
37
+ **Supported properties by framework:**
38
+
39
+ | Framework | Properties |
40
+ |-----------|-----------|
41
+ | MSTest | `FullyQualifiedName`, `Name`, `ClassName`, `Priority`, `TestCategory` |
42
+ | xUnit | `FullyQualifiedName`, `DisplayName`, `Traits` |
43
+ | NUnit | `FullyQualifiedName`, `Name`, `Priority`, `TestCategory` |
44
+
45
+ An expression without an operator is treated as `FullyQualifiedName~<value>`.
46
+
47
+ **Examples (VSTest):**
48
+
49
+ ```bash
50
+ # Run tests whose name contains "LoginTest"
51
+ dotnet test --filter "Name~LoginTest"
52
+
53
+ # Run a specific test class
54
+ dotnet test --filter "ClassName=MyNamespace.MyTestClass"
55
+
56
+ # Run tests in a category
57
+ dotnet test --filter "TestCategory=Integration"
58
+
59
+ # Exclude a category
60
+ dotnet test --filter "TestCategory!=Slow"
61
+
62
+ # Combine: class AND category
63
+ dotnet test --filter "ClassName=MyNamespace.MyTestClass&TestCategory=Unit"
64
+
65
+ # Either of two classes
66
+ dotnet test --filter "ClassName=MyNamespace.ClassA|ClassName=MyNamespace.ClassB"
67
+ ```
68
+
69
+ ## MTP filters — MSTest and NUnit
70
+
71
+ MSTest and NUnit on MTP use the **same `--filter` syntax** as VSTest (same properties, operators, and combinators). The only difference is how the flag is passed:
72
+
73
+ ```bash
74
+ # .NET SDK 8/9 (after --)
75
+ dotnet test -- --filter "Name~LoginTest"
76
+
77
+ # .NET SDK 10+ (direct)
78
+ dotnet test --filter "Name~LoginTest"
79
+ ```
80
+
81
+ ## MTP filters — xUnit (v3)
82
+
83
+ xUnit v3 on MTP uses **framework-specific filter flags** instead of the generic `--filter` expression:
84
+
85
+ | Flag | Description |
86
+ |------|-------------|
87
+ | `--filter-class "name"` | Run all tests in a given class |
88
+ | `--filter-not-class "name"` | Exclude all tests in a given class |
89
+ | `--filter-method "name"` | Run a specific test method |
90
+ | `--filter-not-method "name"` | Exclude a specific test method |
91
+ | `--filter-namespace "name"` | Run all tests in a namespace |
92
+ | `--filter-not-namespace "name"` | Exclude all tests in a namespace |
93
+ | `--filter-trait "name=value"` | Run tests with a matching trait |
94
+ | `--filter-not-trait "name=value"` | Exclude tests with a matching trait |
95
+
96
+ Multiple values can be specified with a single flag: `--filter-class Foo Bar`.
97
+
98
+ ```bash
99
+ # .NET SDK 8/9
100
+ dotnet test -- --filter-class "MyNamespace.LoginTests"
101
+
102
+ # .NET SDK 10+
103
+ dotnet test --filter-class "MyNamespace.LoginTests"
104
+
105
+ # Combine: namespace + trait
106
+ dotnet test --filter-namespace "MyApp.Tests.Integration" --filter-trait "Category=Smoke"
107
+ ```
108
+
109
+ ### xUnit v3 query filter language
110
+
111
+ For complex expressions, use `--filter-query` with a path-segment syntax:
112
+
113
+ ```text
114
+ /<assemblyFilter>/<namespaceFilter>/<classFilter>/<methodFilter>[traitName=traitValue]
115
+ ```
116
+
117
+ Each segment matches against: assembly name, namespace, class name, method name. Use `*` for "match all" in any segment. Documentation: <https://xunit.net/docs/query-filter-language>
118
+
119
+ ```shell
120
+ # xUnit.net v3 MTP — using query language (assembly/namespace/class/method[trait])
121
+ dotnet test -- --filter-query "/*/*/*IntegrationTests*/*[Category=Smoke]"
122
+ ```
123
+
124
+ ## MTP filters — TUnit
125
+
126
+ TUnit uses `--treenode-filter` with a path-based syntax:
127
+
128
+ ```text
129
+ --treenode-filter "/<Assembly>/<Namespace>/<ClassName>/<TestName>"
130
+ ```
131
+
132
+ Wildcards (`*`) are supported in any segment. Filter operators can be appended to test names for property-based filtering.
133
+
134
+ | Operator | Meaning |
135
+ |----------|---------|
136
+ | `*` | Wildcard match |
137
+ | `=` | Exact property match (e.g., `[Category=Unit]`) |
138
+ | `!=` | Exclude property value |
139
+ | `&` | AND (combine conditions) |
140
+ | `\|` | OR (within a segment, requires parentheses) |
141
+
142
+ **Examples (TUnit):**
143
+
144
+ ```bash
145
+ # All tests in a class
146
+ dotnet run --treenode-filter "/*/*/LoginTests/*"
147
+
148
+ # A specific test
149
+ dotnet run --treenode-filter "/*/*/*/AcceptCookiesTest"
150
+
151
+ # By namespace prefix (wildcard)
152
+ dotnet run --treenode-filter "/*/MyProject.Tests.Api*/*/*"
153
+
154
+ # By custom property
155
+ dotnet run --treenode-filter "/*/*/*/*[Category=Smoke]"
156
+
157
+ # Exclude by property
158
+ dotnet run --treenode-filter "/*/*/*/*[Category!=Slow]"
159
+
160
+ # OR across classes
161
+ dotnet run --treenode-filter "/*/*/(LoginTests)|(SignupTests)/*"
162
+
163
+ # Combined: namespace + property
164
+ dotnet run --treenode-filter "/*/MyProject.Tests.Integration/*/*/*[Priority=Critical]"
165
+ ```
166
+
167
+ ## VSTest → MTP filter translation (for migration)
168
+
169
+ **MSTest, NUnit, and xUnit.net v2 (with `YTest.MTP.XUnit2`)**: The VSTest `--filter` syntax is identical on both VSTest and MTP. No changes needed.
170
+
171
+ **xUnit.net v3 (native MTP)**: xUnit.net v3 does NOT support the VSTest `--filter` syntax on MTP. Translate filters using xUnit.net v3's native options:
172
+
173
+ | VSTest `--filter` syntax | xUnit.net v3 MTP equivalent | Notes |
174
+ |---|---|---|
175
+ | `FullyQualifiedName~ClassName` | `--filter-class *ClassName*` | Wildcards required for substring match |
176
+ | `FullyQualifiedName=Ns.Class.Method` | `--filter-method Ns.Class.Method` | Exact match on fully qualified method |
177
+ | `Name=MethodName` | `--filter-method *MethodName*` | Wildcards for substring match |
178
+ | `Category=Value` (trait) | `--filter-trait "Category=Value"` | Filter by trait name/value pair |
179
+ | Complex expressions | `--filter-query "expr"` | Uses xUnit.net query filter language (see above) |
@@ -0,0 +1,23 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) .NET Foundation and Contributors
4
+
5
+ All rights reserved.
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
@@ -0,0 +1,17 @@
1
+ Including Generated Files Into Your Build
2
+ Copyright (c) .NET Foundation and Contributors
3
+ Licensed under the MIT License. See LICENSE.
4
+
5
+ Upstream source: https://github.com/dotnet/skills/blob/a6bf43ab61967c30919334986515163ab24d7635/plugins/dotnet-msbuild/skills/including-generated-files/SKILL.md
6
+
7
+ Changes made by Cratis:
8
+
9
+ LICENSE:
10
+ - Copy upstream MIT license and copyright verbatim.
11
+
12
+ SKILL.md:
13
+ - Normalize frontmatter serialization, add MIT license where absent; preserve name and description.
14
+ - Add marked modification/source comment and applicability/Cratis precedence line.
15
+ - Rewrite the description to the Cratis shape (what it does, Use when, Not for) and drop references to skills that are not part of this corpus.
16
+
17
+ NOTICE: Add this attribution, change list, and any download/execution disclosure.
@@ -0,0 +1,139 @@
1
+ ---
2
+ name: including-generated-files
3
+ description: 'Owns MSBuild generated-artifact integration: a target that creates source, Content, None, or another physical file that is missing from compilation or output, target timing, evaluation-time glob misses, IntermediateOutputPath placement, and FileWrites clean tracking. Use when a generated file is missing from the build even if the prompt does not name the producing task. Not for general Include/Remove/Update semantics, item metadata or batching, duplicate declarations, Roslyn source-generator internals, or non-MSBuild systems.'
4
+ license: MIT
5
+ ---
6
+
7
+ <!-- Modified by Cratis from dotnet's original (MIT): frontmatter, applicability, navigation and the changes listed in NOTICE. Upstream: https://github.com/dotnet/skills (plugins/dotnet-msbuild/skills/including-generated-files/SKILL.md; see NOTICE) -->
8
+
9
+ # Including Generated Files Into Your Build
10
+
11
+ Cratis rules in `.cratis/ai/rules/` (including `csharp.md`, `specs.csharp.md`, and `orleans.md`) and the `cratis-*` skills win where they differ.
12
+
13
+ ## Overview
14
+
15
+ Files generated during the build are generally ignored by the build process. This leads to confusing results such as:
16
+ - Generated files not being included in the output directory
17
+ - Generated source files not being compiled
18
+ - Globs not capturing files created during the build
19
+
20
+ This happens because of how MSBuild's build phases work.
21
+
22
+ ## Quick Takeaway
23
+
24
+ For code files generated during the build - we need to add those to `Compile` and `FileWrites` item groups within the target generating the file(s):
25
+
26
+ ```xml
27
+ <ItemGroup>
28
+ <Compile Include="$(GeneratedFilePath)" />
29
+ <FileWrites Include="$(GeneratedFilePath)" />
30
+ </ItemGroup>
31
+ ```
32
+
33
+ The target generating the file(s) should be hooked before CoreCompile and BeforeCompile targets - `BeforeTargets="CoreCompile;BeforeCompile"`
34
+
35
+ ## Why Generated Files Are Ignored
36
+
37
+ For detailed explanation, see [How MSBuild Builds Projects](https://docs.microsoft.com/visualstudio/msbuild/build-process-overview).
38
+
39
+ ### Evaluation Phase
40
+
41
+ MSBuild reads your project, imports everything, creates Properties, expands globs for Items **outside of Targets**, and sets up the build process.
42
+
43
+ ### Execution Phase
44
+
45
+ MSBuild runs Targets & Tasks with the provided Properties & Items to perform the build.
46
+
47
+ **Key Takeaway:** Files generated during execution don't exist during evaluation, therefore they aren't found. This particularly affects files that are globbed by default, such as source files (`.cs`).
48
+
49
+ ## Solution: Manually Add Generated Files
50
+
51
+ When files are generated during the build, manually add them into the build process. The approach depends on the type of file being generated.
52
+
53
+ ### Use `$(IntermediateOutputPath)` for Generated File Location
54
+
55
+ Always use `$(IntermediateOutputPath)` as the base directory for generated files. **Do not** hardcode `obj\` or construct the intermediary path manually (e.g., `obj\$(Configuration)\$(TargetFramework)\`). The intermediate output path can be redirected to a different location in some build configurations (e.g., shared output directories, CI environments). Using `$(IntermediateOutputPath)` ensures your target works correctly regardless of the actual path.
56
+
57
+ ### Always Add Generated Files to `FileWrites`
58
+
59
+ Every generated file should be added to the `FileWrites` item group. This ensures that MSBuild's `Clean` target properly removes your generated files. Without this, generated files will accumulate as stale artifacts across builds.
60
+
61
+ ```xml
62
+ <ItemGroup>
63
+ <FileWrites Include="$(IntermediateOutputPath)my-generated-file.xyz" />
64
+ </ItemGroup>
65
+ ```
66
+
67
+ ### Basic Pattern (Non-Code Files)
68
+
69
+ For generated files that need to be copied to output (config files, data files, etc.), add them to `Content` or `None` items before `BeforeBuild`:
70
+
71
+ ```xml
72
+ <Target Name="IncludeGeneratedFiles" BeforeTargets="BeforeBuild">
73
+
74
+ <!-- Your logic that generates files goes here -->
75
+
76
+ <ItemGroup>
77
+ <None Include="$(IntermediateOutputPath)my-generated-file.xyz" CopyToOutputDirectory="PreserveNewest"/>
78
+
79
+ <!-- Capture all files of a certain type with a glob -->
80
+ <None Include="$(IntermediateOutputPath)generated\*.xyz" CopyToOutputDirectory="PreserveNewest"/>
81
+
82
+ <!-- Register generated files for proper cleanup -->
83
+ <FileWrites Include="$(IntermediateOutputPath)my-generated-file.xyz" />
84
+ <FileWrites Include="$(IntermediateOutputPath)generated\*.xyz" />
85
+ </ItemGroup>
86
+ </Target>
87
+ ```
88
+
89
+ ### For Generated Source Files (Code That Needs Compilation)
90
+
91
+ If you're generating `.cs` files that need to be compiled, use **`BeforeTargets="CoreCompile;BeforeCompile"`**. This is the correct timing for adding `Compile` items — it runs late enough that the file generation has occurred, but before the compiler runs. Using `BeforeBuild` is too early for some scenarios and may not work reliably with all SDK features.
92
+
93
+ ```xml
94
+ <Target Name="IncludeGeneratedSourceFiles" BeforeTargets="CoreCompile;BeforeCompile">
95
+ <PropertyGroup>
96
+ <GeneratedCodeDir>$(IntermediateOutputPath)Generated\</GeneratedCodeDir>
97
+ <GeneratedFilePath>$(GeneratedCodeDir)MyGeneratedFile.cs</GeneratedFilePath>
98
+ </PropertyGroup>
99
+
100
+ <MakeDir Directories="$(GeneratedCodeDir)" />
101
+
102
+ <!-- Your logic that generates the .cs file goes here -->
103
+
104
+ <ItemGroup>
105
+ <Compile Include="$(GeneratedFilePath)" />
106
+ <FileWrites Include="$(GeneratedFilePath)" />
107
+ </ItemGroup>
108
+ </Target>
109
+ ```
110
+
111
+ Note: Specifying both `CoreCompile` and `BeforeCompile` ensures the target runs before whichever target comes first, providing robust ordering regardless of customizations in the build.
112
+
113
+ ## Target Timing
114
+
115
+ Choose the `BeforeTargets` value based on the type of file being generated:
116
+
117
+ - **`BeforeTargets="BeforeBuild"`** — For non-code files added to `None` or `Content`. Runs early enough for copy-to-output scenarios.
118
+ - **`BeforeTargets="CoreCompile;BeforeCompile"`** — For generated source files added to `Compile`. Ensures the file is included before the compiler runs.
119
+ - **`BeforeTargets="AssignTargetPaths"`** — The "final stop" before `None` and `Content` items (among others) are transformed into new items. Use as a fallback if `BeforeBuild` is too early.
120
+
121
+ ## Globbing Behavior
122
+
123
+ Globs behave according to **when** the glob took place:
124
+
125
+ | Glob Location | Files Captured |
126
+ |---------------|----------------|
127
+ | Outside of a target | Only files visible during Evaluation phase (before build starts) |
128
+ | Inside of a target | Files visible when the target runs (can capture generated files if timed correctly) |
129
+
130
+ This is why the solution places the `<ItemGroup>` inside a `<Target>` - the glob runs during execution when the generated files exist.
131
+
132
+ ## Relevant Links
133
+
134
+ - [How MSBuild Builds Projects](https://docs.microsoft.com/visualstudio/msbuild/build-process-overview)
135
+ - [Evaluation Phase](https://docs.microsoft.com/visualstudio/msbuild/build-process-overview#evaluation-phase)
136
+ - [Execution Phase](https://docs.microsoft.com/visualstudio/msbuild/build-process-overview#execution-phase)
137
+ - [Common Item Types](https://docs.microsoft.com/visualstudio/msbuild/common-msbuild-project-items)
138
+ - [How the SDK imports items by default](https://github.com/dotnet/sdk/blob/main/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.props)
139
+ - [Official docs: Handle generated files](https://learn.microsoft.com/visualstudio/msbuild/customize-your-build#handle-generated-files)