@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,95 @@
1
+ # Regex Patterns
2
+
3
+ ### Choose the Right Regex Engine Mode
4
+ 🟡 **DO** use `[GeneratedRegex]` for all static regex patterns, but never remove `NonBacktracking` if present | .NET 7+
5
+
6
+ ❌
7
+ ```csharp
8
+ var r = new Regex(dynamicPattern, RegexOptions.Compiled);
9
+ ```
10
+ ✅
11
+ ```csharp
12
+ [GeneratedRegex("pattern")]
13
+ private static partial Regex MyRegex();
14
+
15
+ var safe = new Regex(untrustedPattern, RegexOptions.NonBacktracking);
16
+
17
+ var oneOff = new Regex("pattern");
18
+ ```
19
+
20
+ **Impact: Source generator is always beneficial for static patterns. NonBacktracking prevents O(2^N) worst case — never remove it if present.**
21
+
22
+ ### Use IsMatch When You Only Need a Boolean Result
23
+ 🟡 **DO** use `IsMatch` instead of `Match(...).Success` | .NET 7+
24
+
25
+ ❌
26
+ ```csharp
27
+ bool found = Regex.Match(input, pattern).Success;
28
+ ```
29
+ ✅
30
+ ```csharp
31
+ bool found = Regex.IsMatch(input, pattern);
32
+ ```
33
+
34
+ **Impact: Avoids Match object allocation; with NonBacktracking, ~3x faster by skipping capture computation.**
35
+
36
+ ### Use Regex.Count/EnumerateMatches Instead of Matches
37
+ 🟡 **DO** use `Count()` and `EnumerateMatches()` for allocation-free match processing | .NET 7+
38
+
39
+ ❌
40
+ ```csharp
41
+ int count = 0;
42
+ Match m = regex.Match(text);
43
+ while (m.Success) { count++; m = m.NextMatch(); }
44
+ ```
45
+ ✅
46
+ ```csharp
47
+ int count = regex.Count(text);
48
+
49
+ foreach (ValueMatch m in Regex.EnumerateMatches(text, @"\b\w+\b"))
50
+ {
51
+ ReadOnlySpan<char> word = text.AsSpan(m.Index, m.Length);
52
+ }
53
+ ```
54
+
55
+ **Impact: ~3x faster than Match/NextMatch with NonBacktracking. Zero allocations for both Count and EnumerateMatches.**
56
+
57
+ ### Use Span-Based Regex APIs for Allocation-Free Matching
58
+ 🟡 **DO** use `ReadOnlySpan<char>` overloads for regex matching on spans | .NET 7+
59
+
60
+ ❌
61
+ ```csharp
62
+ string sub = largeBuffer.Substring(start, length);
63
+ bool found = Regex.IsMatch(sub, pattern);
64
+ ```
65
+ ✅
66
+ ```csharp
67
+ ReadOnlySpan<char> text = largeBuffer.AsSpan(start, length);
68
+ foreach (ValueMatch m in Regex.EnumerateMatches(text, @"\b\w+\b"))
69
+ {
70
+ ReadOnlySpan<char> word = text.Slice(m.Index, m.Length);
71
+ }
72
+ ```
73
+
74
+ **Impact: Eliminates string allocations when working with spans — particularly valuable in high-throughput parsing pipelines.**
75
+
76
+ ## Detection
77
+
78
+ Scan recipes for regex anti-patterns. Run these and report exact counts.
79
+
80
+ ```bash
81
+ # Compiled regex count (startup cost budget — compare ratio to GeneratedRegex)
82
+ grep -rn --include='*.cs' 'RegexOptions.Compiled' --exclude-dir=bin --exclude-dir=obj . | wc -l
83
+
84
+ # GeneratedRegex count (already optimized — verify the inverse)
85
+ grep -rn --include='*.cs' 'GeneratedRegex' --exclude-dir=bin --exclude-dir=obj . | wc -l
86
+
87
+ # Uncached new Regex() calls (construction cost per call)
88
+ grep -rn --include='*.cs' 'new Regex(' --exclude-dir=bin --exclude-dir=obj . | wc -l
89
+ ```
90
+
91
+ When `RegexOptions.Compiled` appears inside a class constructor or field initializer of an instantiated class (not a static singleton), count how many instances of that class are created at startup to determine total compiled regex budget. For example, if a `Rule` class compiles a regex in its constructor and 122 rules are registered, that is 122 compiled regexes at startup.
92
+
93
+ ### Patterns Requiring Manual Review
94
+
95
+ - **`new Regex(` uncached**: Field assignment may span multiple lines — grep on one line is unreliable. Verify that matched instances are stored in `static readonly` fields or `[GeneratedRegex]`.
@@ -0,0 +1,38 @@
1
+ # Structural Patterns
2
+
3
+ Patterns detected by the **absence** of a keyword or interface. These require codebase-wide counting scans, not single-file matching.
4
+
5
+ ### Seal Classes for Devirtualization
6
+ 🟡 **DO** seal all leaf classes (those not subclassed) | .NET Core 3.0+
7
+
8
+ Sealing lets the JIT devirtualize/inline virtual calls and use pointer comparison for type checks. Every non-abstract, non-static class that is not subclassed should be sealed. **Cratis qualification:** Never seal public types of a published framework/library package: doing so is a breaking change, and Cratis framework repositories treat public API changes as semver.
9
+
10
+ **Detection:** This is an absence pattern — scan for classes that are NOT sealed.
11
+
12
+ ```bash
13
+ # Count unsealed (non-abstract, non-static) classes
14
+ grep -rn --include='*.cs' -E '^\s*((public|internal|private|protected|file)\s+)?(partial\s+)?class ' --exclude-dir=bin --exclude-dir=obj . | grep -v 'sealed' | grep -v 'abstract' | grep -v 'static' | wc -l
15
+
16
+ # Count already-sealed classes (verify the inverse)
17
+ grep -rn --include='*.cs' 'sealed class' --exclude-dir=bin --exclude-dir=obj . | wc -l
18
+ ```
19
+
20
+ **Exclusions:** Do not seal classes that are subclassed elsewhere in the codebase. Identifying base classes requires manual review — grep for `: ClassName` patterns and cross-reference, but expect false positives from interface implementations and generic constraints.
21
+
22
+ ❌
23
+ ```csharp
24
+ internal class MyHandler : Base
25
+ { public override int Run() => 42; }
26
+ ```
27
+ ✅
28
+ ```csharp
29
+ internal sealed class MyHandler : Base
30
+ { public override int Run() => 42; }
31
+ ```
32
+
33
+ **Impact: Virtual calls up to 500x faster; type checks ~25x faster. Severity scales with count.**
34
+
35
+ **Scale-based severity:**
36
+ - 1-10 unsealed leaf classes → ℹ️ Info
37
+ - 11-50 unsealed leaf classes → 🟡 Moderate
38
+ - 50+ unsealed leaf classes → 🟡 Moderate (elevated priority)
@@ -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,22 @@
1
+ Generate Binary Logs
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/binlog-generation/SKILL.md
6
+
7
+ Changes made by Cratis:
8
+
9
+ LICENSE:
10
+ - Copy upstream MIT license and copyright verbatim.
11
+
12
+ SKILL.md:
13
+ - Remove the SDK version from the description; the 17.12 floor stays in the body.
14
+ - Normalize frontmatter serialization, add MIT license where absent; preserve name and description.
15
+ - Correct the binlog {} placeholder SDK/MSBuild minimum in description and body.
16
+ - Add marked modification/source comment and applicability/Cratis precedence line with the skill-specific safety, ownership or compatibility caveat.
17
+ - Render unimported binlog-failure-analysis routing reference as plain topic text.
18
+ - Render unimported build-perf-diagnostics routing reference as plain topic text.
19
+ - Correct the binlog {} placeholder SDK/MSBuild minimum.
20
+ - 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.
21
+
22
+ NOTICE: Add this attribution, change list, and any download/execution disclosure.
@@ -0,0 +1,129 @@
1
+ ---
2
+ name: binlog-generation
3
+ description: 'Generates MSBuild binary logs (binlogs) by adding /bl:{} to dotnet build, test, pack, publish, or restore commands, capturing a full build trace for later investigation. Use when a build error or build-performance problem needs a binlog and none exists. The {} placeholder needs a recent MSBuild; PowerShell must quote the switch as ''-bl:{}''. Not for analyzing an existing binlog or measuring build performance (use the msbuild skill) or for non-MSBuild build systems such as npm, Maven, or CMake.'
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/binlog-generation/SKILL.md; see NOTICE) -->
8
+
9
+ # Generate Binary Logs
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. Binlogs embed project and imported file contents: keep them local and task-scoped.
12
+
13
+ **Pass the `/bl` switch when running any MSBuild-based command.** This is a non-negotiable requirement for all .NET builds.
14
+
15
+ ## Commands That Require /bl
16
+
17
+ You MUST add the `/bl:{}` flag to:
18
+ - `dotnet build`
19
+ - `dotnet test`
20
+ - `dotnet pack`
21
+ - `dotnet publish`
22
+ - `dotnet restore`
23
+ - `msbuild` or `msbuild.exe`
24
+ - Any other command that invokes MSBuild
25
+
26
+ ## Preferred: Use `{}` for Automatic Unique Names
27
+
28
+ > **Note:** The `{}` placeholder requires MSBuild 17.12+ / .NET 9.0.100 SDK or later.
29
+
30
+ The `{}` placeholder in the binlog filename is replaced by MSBuild with a unique identifier, guaranteeing no two builds ever overwrite each other — without needing to track or check existing files.
31
+
32
+ ```bash
33
+ # Every invocation produces a distinct file automatically
34
+ dotnet build /bl:{}
35
+ dotnet test /bl:{}
36
+ dotnet build --configuration Release /bl:{}
37
+ ```
38
+
39
+ **PowerShell requires quoting the complete switch:**
40
+
41
+ ```powershell
42
+ # Keep the literal {} placeholder in one argument
43
+ dotnet build '-bl:{}'
44
+ dotnet test '-bl:{}'
45
+ ```
46
+
47
+ ## Why This Matters
48
+
49
+ 1. **Unique names prevent overwrites** - You can always go back and analyze previous builds
50
+ 2. **Failure analysis** - When a build fails, the binlog is already there for immediate analysis
51
+ 3. **Comparison** - You can compare builds before and after changes
52
+ 4. **No re-running builds** - You never need to re-run a failed build just to generate a binlog
53
+
54
+ ## Examples
55
+
56
+ ```bash
57
+ # ✅ CORRECT - {} generates a unique name automatically (bash/cmd)
58
+ dotnet build /bl:{}
59
+ dotnet test /bl:{}
60
+
61
+ # ✅ CORRECT - quote the complete PowerShell argument
62
+ dotnet build '-bl:{}'
63
+ dotnet test '-bl:{}'
64
+
65
+ # ❌ WRONG - Missing /bl flag entirely
66
+ dotnet build
67
+ dotnet test
68
+
69
+ # ❌ WRONG - No filename (overwrites the same msbuild.binlog every time)
70
+ dotnet build /bl
71
+ dotnet build /bl
72
+ ```
73
+
74
+ ## One build = one binlog
75
+
76
+ Add `/bl:{}` to **every** MSBuild invocation separately — never reuse a name and
77
+ never rely on bare `/bl`:
78
+
79
+ - Building several configurations, projects, or retrying a failed build? Each
80
+ command still gets its own `/bl:{}` so the logs never overwrite each other.
81
+
82
+ ```bash
83
+ dotnet build -c Debug /bl:{} # unique file
84
+ dotnet build -c Release /bl:{} # another unique file
85
+ ```
86
+
87
+ ## Verify the binlog exists
88
+
89
+ After the build, confirm a `.binlog` was actually produced before moving on to
90
+ analysis — a build that fails *before* MSBuild starts (e.g. a bad argument)
91
+ writes no binlog:
92
+
93
+ ```bash
94
+ ls -1 *.binlog # bash
95
+ dir /b *.binlog # Windows cmd
96
+ ```
97
+
98
+ ```powershell
99
+ Get-ChildItem *.binlog # PowerShell
100
+ ```
101
+
102
+ Note the resulting path so binlog failure analysis or build perf diagnostics
103
+ can consume it.
104
+
105
+ ## When a Specific Filename Is Required
106
+
107
+ If the binlog filename needs to be known upfront (e.g., for CI artifact upload), or if `{}` is not available in the installed MSBuild version, pick a name that won't collide with existing files:
108
+
109
+ 1. Check for existing `*.binlog` files in the directory
110
+ 2. Choose a name not already taken (e.g., by incrementing a counter from the highest existing number)
111
+
112
+ ```bash
113
+ # Example: directory contains 3.binlog — use 4.binlog
114
+ dotnet build /bl:4.binlog
115
+ ```
116
+
117
+ ## Cleaning the Repository
118
+
119
+ When cleaning the repository with `git clean`, **always exclude binlog files** to preserve your build history:
120
+
121
+ ```bash
122
+ # ✅ CORRECT - Exclude binlog files from cleaning
123
+ git clean -fdx -e "*.binlog"
124
+
125
+ # ❌ WRONG - This deletes binlog files (they're usually in .gitignore)
126
+ git clean -fdx
127
+ ```
128
+
129
+ This is especially important when iterating on build fixes - you need the binlogs to analyze what changed between builds.
@@ -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,27 @@
1
+ Detecting OutputPath and IntermediateOutputPath Clashes
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/check-bin-obj-clash/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
+ - Render unimported msbuild-antipatterns routing reference as plain topic text.
16
+ - Replace the blanket BuildProjectReferences=false exclusion with an evidence-based metadata-only query qualification.
17
+ - Qualify the structured workflow exclusion by actual targets and writes.
18
+ - Qualify the text-replay exclusion by actual targets and writes.
19
+ - Move the complete ## Common Causes and Fixes section verbatim into references/common-causes-and-fixes.md to fit the body limit; leave a direct pointer.
20
+ - 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.
21
+ - Point the antipatterns cross-references at the bundled msbuild skill reference.
22
+
23
+ references/common-causes-and-fixes.md:
24
+ - Contain the section moved verbatim from SKILL.md, with a reference H1 title.
25
+ - Add or normalize the top Contents list from existing headings; preserve section content.
26
+
27
+ NOTICE: Add this attribution, change list, and any download/execution disclosure.
@@ -0,0 +1,127 @@
1
+ ---
2
+ name: check-bin-obj-clash
3
+ description: 'Detects MSBuild projects with conflicting OutputPath or IntermediateOutputPath and fixes the clash. Use when builds fail with ''Cannot create a file when that file already exists'' or ''The process cannot access the file because it is being used by another process'', fail intermittently but pass on retry, or overwrite outputs in multi-project or multi-targeting builds where bin/obj or project.assets.json collide. Not for OS-level file locking, single-project single-TFM builds, or non-MSBuild build 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/check-bin-obj-clash/SKILL.md; see NOTICE) -->
8
+
9
+ # Detecting OutputPath and IntermediateOutputPath Clashes
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
+ This skill helps identify when multiple MSBuild project evaluations share the same `OutputPath` or `IntermediateOutputPath`. This is a common source of build failures including:
16
+
17
+ - File access conflicts during parallel builds
18
+ - Missing or overwritten output files
19
+ - Intermittent build failures
20
+ - "File in use" errors
21
+ - **NuGet restore errors like `Cannot create a file when that file already exists`** - this strongly indicates multiple projects share the same `IntermediateOutputPath` where `project.assets.json` is written
22
+
23
+ Clashes can occur between:
24
+ - **Different projects** sharing the same output directory
25
+ - **Multi-targeting builds** (e.g., `TargetFrameworks=net8.0;net9.0`) where the path doesn't include the target framework
26
+ - **Multiple solution builds** where the same project is built from different solutions in a single build
27
+
28
+ **Cratis qualification:** `BuildProjectReferences=false` only suppresses building referenced projects; it does not prove that this project instance is read-only. Exclude an instance only when its actual targets and writes show a metadata-only query (for example, `GetTargetPath`).
29
+
30
+ ## When to Use This Skill
31
+
32
+ **Invoke this skill immediately when you see:**
33
+ - `Cannot create a file when that file already exists` during NuGet restore
34
+ - `The process cannot access the file because it is being used by another process`
35
+ - Intermittent build failures that succeed on retry
36
+ - Missing output files or unexpected overwriting
37
+
38
+ ## Step 1: Generate a Binary Log
39
+
40
+ Use the `binlog-generation` skill to generate a binary log with the correct naming convention.
41
+
42
+ ## Primary workflow — binlog MCP
43
+
44
+ The MCP server exposes structured tools for inspecting a `.binlog` without
45
+ parsing text logs. Call them directly instead of replaying the binlog to a text
46
+ file. Call `tools/list` for the MCP first if you are unsure which tools are available.
47
+
48
+ **Important constraints:**
49
+ - The `.binlog` file is a **binary format** — do NOT try to `cat`, `head`, `strings`, or read it directly. Use only the MCP tools to query it.
50
+ - **Synthesize findings as you go.** Do not spend all available time investigating — once you have enough evidence, present your conclusions.
51
+
52
+ ### Step 2: Get an overview and list projects
53
+
54
+ Use the MCP overview and projects tools to understand the build and list all projects that participated.
55
+
56
+ ### Step 3: Check evaluations and global properties
57
+
58
+ Use the MCP `evaluations` and `evaluation_global_properties` tools to find all evaluations per project. Look for:
59
+ - Multiple evaluations for the same project (indicates multi-targeting or multiple build configurations)
60
+ - Differing global properties between evaluations (`TargetFramework`, `Configuration`, `RuntimeIdentifier`, `SolutionFileName`, `PublishReadyToRun`, etc.)
61
+
62
+ ### Step 4: Get output paths for each evaluation
63
+
64
+ Use the MCP properties tool to query `OutputPath`, `IntermediateOutputPath`, `BaseOutputPath`, and `BaseIntermediateOutputPath` for each project evaluation.
65
+
66
+ ### Step 5: Check for double writes
67
+
68
+ Use the MCP double_writes tool if available — it directly detects files written by multiple project instances.
69
+
70
+ ### Step 6: Identify clashes
71
+
72
+ Compare the `OutputPath` and `IntermediateOutputPath` values across all evaluations:
73
+ 1. **Normalize paths** - Convert to absolute paths and normalize separators
74
+ 2. **Group by path** - Find evaluations that share the same OutputPath or IntermediateOutputPath
75
+ 3. **Filter out non-build evaluations** - Exclude only instances proven by their targets and writes to be metadata-only queries; `BuildProjectReferences=false` alone is insufficient.
76
+ 4. **Report clashes** - Any group with more than one evaluation indicates a clash
77
+
78
+ ## Fallback workflow — text-log replay (when MCP is unavailable)
79
+
80
+ Use this only when the MCP server cannot be started.
81
+
82
+ Replay the binlog to a diagnostic text log, then grep for the same signals the MCP tools surface:
83
+
84
+ ```bash
85
+ dotnet msbuild build.binlog -noconlog -fl "-flp:v=diag;logfile=full.log"
86
+ ```
87
+
88
+ Then extract the clash signals:
89
+
90
+ - **Projects & evaluations** — list evaluation starts and count them per project: `grep 'Evaluation started' full.log | grep -oiE '"[^"]+\.[a-z]+proj"' | sort | uniq -c`. Matching the full **quoted path** keeps same-named projects in different directories distinct (and tolerates spaces in paths); a path with a count ≥ 2 was evaluated more than once (multi-targeting or extra global properties). (`grep -c` alone only totals evaluations across the whole log, so it can't reveal per-project duplication.)
91
+ - **Output paths** — `grep -iE 'OutputPath[[:space:]]*=|IntermediateOutputPath[[:space:]]*=|BaseOutputPath[[:space:]]*=|BaseIntermediateOutputPath[[:space:]]*=' full.log | sort -u`, or query a project directly: `dotnet msbuild MyProject.csproj -getProperty:OutputPath` (and `IntermediateOutputPath`, `BaseIntermediateOutputPath`).
92
+ - **Distinguishing global properties** — `grep -iE 'TargetFramework|Configuration|Platform|RuntimeIdentifier|SolutionFileName|PublishReadyToRun' full.log`. See the [Global Properties to Check](references/common-causes-and-fixes.md#global-properties-to-check-when-comparing-evaluations) table for which affect the path and which just fork a redundant instance.
93
+ - **Corroborating evidence (optional)** — `grep 'Target "CopyFilesToOutputDirectory"' full.log` plus `grep 'SkipUnchangedFiles' full.log` show a second instance writing (or skipping a masked write) to the same path; a long vs ~0 ms `CoreCompile` distinguishes the real build from a redundant instance.
94
+
95
+ **Then identify clashes:** normalize paths to absolute, group evaluations by `OutputPath` and by `IntermediateOutputPath`, and exclude only instances proven by their targets and writes to be metadata-only queries, not merely marked `BuildProjectReferences=false` — plus, for `OutputPath` only, `MSBuildRestoreSessionId` restore evaluations. Any group with more than one remaining evaluation is a clash.
96
+
97
+ Read references/common-causes-and-fixes.md when selecting the relevant diagnostic workflow.
98
+
99
+ ## Tips
100
+
101
+ - The SDK default paths include `$(TargetFramework)` — clashes often occur when projects override these defaults; normalize relative paths to absolute before comparing.
102
+ - **Cross-project `IntermediateOutputPath` clashes cannot be fixed with `AppendTargetFrameworkToOutputPath`** — files like `project.assets.json` are written directly to the intermediate path. For multi-targeting clashes *within the same project*, `AppendTargetFrameworkToOutputPath=true` is the correct fix.
103
+ - Error messages that indicate a path clash: `Cannot create a file when that file already exists` (NuGet restore), `The process cannot access the file because it is being used by another process`, or intermittent failures that succeed on retry.
104
+
105
+ ### Global Properties to Check When Comparing Evaluations
106
+
107
+ When multiple evaluations share an output path, compare these global properties to understand why:
108
+
109
+ | Property | Affects OutputPath? | Notes |
110
+ |----------|---------------------|-------|
111
+ | `TargetFramework` | Yes | Different TFMs should have different paths. **Exception:** re-injecting a *single-targeting* project's own TFM (e.g. via `SetTargetFramework` with the same value) is path-neutral — it forks a redundant instance sharing the output path (see "`SetTargetFramework` re-injecting...") |
112
+ | `RuntimeIdentifier` | Yes | Different RIDs should have different paths |
113
+ | `Configuration` | Yes | Debug vs Release |
114
+ | `Platform` | Yes | AnyCPU vs x64 etc. |
115
+ | `SolutionFileName` | No | Identifies which solution built the project — different values indicate multi-solution clash |
116
+ | `SolutionName` | No | Solution name without extension |
117
+ | `SolutionPath` | No | Full path to the solution file |
118
+ | `SolutionDir` | No | Directory containing the solution file |
119
+ | `CurrentSolutionConfigurationContents` | No | XML with project entries — count of entries reveals which solution |
120
+ | `BuildProjectReferences` | No | `false` = P2P query, not a real build - ignore these |
121
+ | `MSBuildRestoreSessionId` | No | Present = restore phase evaluation |
122
+ | `PublishReadyToRun` | No | Publish setting, doesn't change build output path but creates distinct project instances |
123
+ | `_IsPublishing` | No | Publish flag; an `<MSBuild>` Build/Publish call with this set (in this project or another that consumes it) forks a publish instance sharing the build output path (see "Explicit `<MSBuild>` Build/Publish with extra global properties") |
124
+
125
+ ## Testing Fixes
126
+
127
+ After making changes to fix path clashes, clean and rebuild to verify. See the `binlog-generation` skill's "Cleaning the Repository" section on how to clean the repository while preserving binlog files.