@cratis/pi 7.101.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 (168) hide show
  1. package/package/corpus/harnesses/copilot/instructions/github-actions.instructions.md +17 -0
  2. package/package/corpus/harnesses/copilot/instructions/profiles.instructions.md +10 -1
  3. package/package/corpus/harnesses/copilot/instructions/pull-requests.instructions.md +2 -0
  4. package/package/corpus/harnesses/copilot/instructions/secrets.instructions.md +4 -0
  5. package/package/corpus/hooks/README.md +11 -1
  6. package/package/corpus/hooks/scripts/cratis-check-pr.mjs +12 -1
  7. package/package/corpus/hooks/scripts/cratis-guard-secrets.sh +79 -23
  8. package/package/corpus/hooks/scripts/cratis-guard-writes.sh +145 -40
  9. package/package/corpus/rules/github-actions.md +17 -0
  10. package/package/corpus/rules/profiles.md +10 -1
  11. package/package/corpus/rules/pull-requests.md +2 -0
  12. package/package/corpus/rules/secrets.md +4 -0
  13. package/package/corpus/skills/analyzing-dotnet-performance/LICENSE +23 -0
  14. package/package/corpus/skills/analyzing-dotnet-performance/NOTICE +36 -0
  15. package/package/corpus/skills/analyzing-dotnet-performance/SKILL.md +214 -0
  16. package/package/corpus/skills/analyzing-dotnet-performance/references/async-patterns.md +122 -0
  17. package/package/corpus/skills/analyzing-dotnet-performance/references/collections-and-linq.md +220 -0
  18. package/package/corpus/skills/analyzing-dotnet-performance/references/critical-patterns.md +291 -0
  19. package/package/corpus/skills/analyzing-dotnet-performance/references/io-and-serialization.md +135 -0
  20. package/package/corpus/skills/analyzing-dotnet-performance/references/memory-and-strings.md +219 -0
  21. package/package/corpus/skills/analyzing-dotnet-performance/references/regex-patterns.md +95 -0
  22. package/package/corpus/skills/analyzing-dotnet-performance/references/structural-patterns.md +38 -0
  23. package/package/corpus/skills/binlog-generation/LICENSE +23 -0
  24. package/package/corpus/skills/binlog-generation/NOTICE +22 -0
  25. package/package/corpus/skills/binlog-generation/SKILL.md +129 -0
  26. package/package/corpus/skills/check-bin-obj-clash/LICENSE +23 -0
  27. package/package/corpus/skills/check-bin-obj-clash/NOTICE +27 -0
  28. package/package/corpus/skills/check-bin-obj-clash/SKILL.md +127 -0
  29. package/package/corpus/skills/check-bin-obj-clash/references/common-causes-and-fixes.md +206 -0
  30. package/package/corpus/skills/coverage-analysis/LICENSE +23 -0
  31. package/package/corpus/skills/coverage-analysis/NOTICE +32 -0
  32. package/package/corpus/skills/coverage-analysis/SKILL.md +198 -0
  33. package/package/corpus/skills/coverage-analysis/references/guidelines.md +68 -0
  34. package/package/corpus/skills/coverage-analysis/references/output-format.md +91 -0
  35. package/package/corpus/skills/coverage-analysis/references/report-generation.md +58 -0
  36. package/package/corpus/skills/coverage-analysis/references/setup-discovery.md +307 -0
  37. package/package/corpus/skills/coverage-analysis/scripts/Compute-CrapScores.ps1 +80 -0
  38. package/package/corpus/skills/coverage-analysis/scripts/CoverageData.ps1 +272 -0
  39. package/package/corpus/skills/coverage-analysis/scripts/Extract-MethodCoverage.ps1 +65 -0
  40. package/package/corpus/skills/cratis-ci-pipeline-performance/LICENSE +2 -0
  41. package/package/corpus/skills/cratis-ci-pipeline-performance/SKILL.md +201 -0
  42. package/package/corpus/skills/cratis-ci-pipeline-performance/references/build-once-and-shard.md +158 -0
  43. package/package/corpus/skills/cratis-ci-pipeline-performance/references/caching.md +86 -0
  44. package/package/corpus/skills/cratis-ci-pipeline-performance/references/flaky-and-hung-jobs.md +70 -0
  45. package/package/corpus/skills/cratis-ci-pipeline-performance/references/publish-pipelines.md +67 -0
  46. package/package/corpus/skills/cratis-ci-pipeline-performance/references/required-checks-and-path-filters.md +117 -0
  47. package/package/corpus/skills/cratis-ci-pipeline-performance/references/runner-sizing-and-images.md +65 -0
  48. package/package/corpus/skills/cratis-ci-pipeline-performance/references/security-and-pinning.md +73 -0
  49. package/package/corpus/skills/cratis-ci-pipeline-performance/references/sources.md +33 -0
  50. package/package/corpus/skills/cratis-ci-pipeline-performance/references/test-setup-cost.md +82 -0
  51. package/package/corpus/skills/cratis-ci-pipeline-performance/scripts/ci-timings.sh +356 -0
  52. package/package/corpus/skills/cratis-ci-pipeline-performance/scripts/fixtures/jobs/1003.json +79 -0
  53. package/package/corpus/skills/cratis-ci-pipeline-performance/scripts/fixtures/jobs/1007.json +79 -0
  54. package/package/corpus/skills/cratis-ci-pipeline-performance/scripts/fixtures/jobs/1010.json +79 -0
  55. package/package/corpus/skills/cratis-ci-pipeline-performance/scripts/fixtures/runs.json +102 -0
  56. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/LICENSE +2 -0
  57. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/SKILL.md +244 -0
  58. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/docker-images.md +86 -0
  59. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/dotnet-nuget.md +87 -0
  60. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/go-jvm-python-elixir.md +83 -0
  61. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/npm-yarn.md +78 -0
  62. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/other-environments.md +60 -0
  63. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/worked-examples.md +97 -0
  64. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/scripts/cratis-local-packages.sh +778 -0
  65. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/scripts/npm-restore-check.cjs +109 -0
  66. package/package/corpus/skills/csharp-refactoring/LICENSE +23 -0
  67. package/package/corpus/skills/csharp-refactoring/NOTICE +22 -0
  68. package/package/corpus/skills/csharp-refactoring/SKILL.md +175 -0
  69. package/package/corpus/skills/csharp-refactoring/references/operation-catalog.md +37 -0
  70. package/package/corpus/skills/directory-build-organization/LICENSE +23 -0
  71. package/package/corpus/skills/directory-build-organization/NOTICE +21 -0
  72. package/package/corpus/skills/directory-build-organization/SKILL.md +205 -0
  73. package/package/corpus/skills/directory-build-organization/references/common-patterns.md +56 -0
  74. package/package/corpus/skills/directory-build-organization/references/multi-level-examples.md +167 -0
  75. package/package/corpus/skills/directory-build-organization/references/targetframework-props-pitfall.md +54 -0
  76. package/package/corpus/skills/dotnet-aot-compat/LICENSE +23 -0
  77. package/package/corpus/skills/dotnet-aot-compat/NOTICE +18 -0
  78. package/package/corpus/skills/dotnet-aot-compat/SKILL.md +265 -0
  79. package/package/corpus/skills/dotnet-aot-compat/references/polyfills.md +43 -0
  80. package/package/corpus/skills/dotnet-trace-collect/LICENSE +23 -0
  81. package/package/corpus/skills/dotnet-trace-collect/NOTICE +65 -0
  82. package/package/corpus/skills/dotnet-trace-collect/SKILL.md +116 -0
  83. package/package/corpus/skills/dotnet-trace-collect/references/dotnet-monitor.md +97 -0
  84. package/package/corpus/skills/dotnet-trace-collect/references/dotnet-trace-collect-linux.md +84 -0
  85. package/package/corpus/skills/dotnet-trace-collect/references/dotnet-trace-collect.md +91 -0
  86. package/package/corpus/skills/dotnet-trace-collect/references/perfcollect.md +200 -0
  87. package/package/corpus/skills/dotnet-trace-collect/references/perfview.md +141 -0
  88. package/package/corpus/skills/dotnet-trace-collect/references/tool-selection.md +160 -0
  89. package/package/corpus/skills/dump-collect/LICENSE +23 -0
  90. package/package/corpus/skills/dump-collect/NOTICE +40 -0
  91. package/package/corpus/skills/dump-collect/SKILL.md +97 -0
  92. package/package/corpus/skills/dump-collect/references/container-dumps.md +412 -0
  93. package/package/corpus/skills/dump-collect/references/coreclr-dumps.md +108 -0
  94. package/package/corpus/skills/dump-collect/references/nativeaot-dumps.md +280 -0
  95. package/package/corpus/skills/eliminate-redundant-restores/LICENSE +23 -0
  96. package/package/corpus/skills/eliminate-redundant-restores/NOTICE +19 -0
  97. package/package/corpus/skills/eliminate-redundant-restores/SKILL.md +112 -0
  98. package/package/corpus/skills/extension-points/LICENSE +23 -0
  99. package/package/corpus/skills/extension-points/NOTICE +18 -0
  100. package/package/corpus/skills/extension-points/SKILL.md +248 -0
  101. package/package/corpus/skills/filter-syntax/LICENSE +23 -0
  102. package/package/corpus/skills/filter-syntax/NOTICE +17 -0
  103. package/package/corpus/skills/filter-syntax/SKILL.md +179 -0
  104. package/package/corpus/skills/including-generated-files/LICENSE +23 -0
  105. package/package/corpus/skills/including-generated-files/NOTICE +17 -0
  106. package/package/corpus/skills/including-generated-files/SKILL.md +139 -0
  107. package/package/corpus/skills/microbenchmarking/LICENSE +23 -0
  108. package/package/corpus/skills/microbenchmarking/NOTICE +36 -0
  109. package/package/corpus/skills/microbenchmarking/SKILL.md +131 -0
  110. package/package/corpus/skills/microbenchmarking/references/bdn-internals-and-tuning.md +143 -0
  111. package/package/corpus/skills/microbenchmarking/references/comparison-strategies.md +200 -0
  112. package/package/corpus/skills/microbenchmarking/references/diagnosers-and-exporters.md +150 -0
  113. package/package/corpus/skills/microbenchmarking/references/project-setup-and-running.md +189 -0
  114. package/package/corpus/skills/microbenchmarking/references/writing-benchmarks.md +310 -0
  115. package/package/corpus/skills/msbuild/LICENSE +23 -0
  116. package/package/corpus/skills/msbuild/NOTICE +55 -0
  117. package/package/corpus/skills/msbuild/SKILL.md +117 -0
  118. package/package/corpus/skills/msbuild/references/antipatterns/additional-antipatterns.md +291 -0
  119. package/package/corpus/skills/msbuild/references/antipatterns/incremental-build-inputs-outputs.md +57 -0
  120. package/package/corpus/skills/msbuild/references/antipatterns/private-assets.md +29 -0
  121. package/package/corpus/skills/msbuild/references/binlog-failure-analysis.md +85 -0
  122. package/package/corpus/skills/msbuild/references/binlog-generation.md +69 -0
  123. package/package/corpus/skills/msbuild/references/build-perf-baseline.md +493 -0
  124. package/package/corpus/skills/msbuild/references/build-perf-diagnostics.md +268 -0
  125. package/package/corpus/skills/msbuild/references/copy-to-output-directory.md +183 -0
  126. package/package/corpus/skills/msbuild/references/eval-performance.md +190 -0
  127. package/package/corpus/skills/msbuild/references/extension-points.md +281 -0
  128. package/package/corpus/skills/msbuild/references/incremental-build.md +365 -0
  129. package/package/corpus/skills/msbuild/references/msbuild-antipatterns.md +401 -0
  130. package/package/corpus/skills/orleans/LICENSE +21 -0
  131. package/package/corpus/skills/orleans/NOTICE +64 -0
  132. package/package/corpus/skills/orleans/SKILL.md +140 -0
  133. package/package/corpus/skills/orleans/references/anti-patterns.md +660 -0
  134. package/package/corpus/skills/orleans/references/configuration-api.md +933 -0
  135. package/package/corpus/skills/orleans/references/examples.md +66 -0
  136. package/package/corpus/skills/orleans/references/grain-api.md +784 -0
  137. package/package/corpus/skills/orleans/references/grains.md +75 -0
  138. package/package/corpus/skills/orleans/references/hosting.md +71 -0
  139. package/package/corpus/skills/orleans/references/implementation.md +591 -0
  140. package/package/corpus/skills/orleans/references/official-docs-index.md +250 -0
  141. package/package/corpus/skills/orleans/references/patterns.md +811 -0
  142. package/package/corpus/skills/orleans/references/persistence-api.md +495 -0
  143. package/package/corpus/skills/orleans/references/primitive-selection.md +35 -0
  144. package/package/corpus/skills/orleans/references/scheduling-and-services.md +295 -0
  145. package/package/corpus/skills/orleans/references/serialization-api.md +299 -0
  146. package/package/corpus/skills/orleans/references/streaming-api.md +396 -0
  147. package/package/corpus/skills/orleans/references/testing-patterns.md +210 -0
  148. package/package/corpus/skills/platform-detection/LICENSE +23 -0
  149. package/package/corpus/skills/platform-detection/NOTICE +17 -0
  150. package/package/corpus/skills/platform-detection/SKILL.md +230 -0
  151. package/package/corpus/skills/platform-detection/references/command-mode.md +27 -0
  152. package/package/corpus/skills/profiling/LICENSE +21 -0
  153. package/package/corpus/skills/profiling/NOTICE +50 -0
  154. package/package/corpus/skills/profiling/SKILL.md +144 -0
  155. package/package/corpus/skills/profiling/references/commands.md +439 -0
  156. package/package/corpus/skills/profiling/references/patterns.md +586 -0
  157. package/package/corpus/skills/profiling/references/profiling.md +190 -0
  158. package/package/corpus/skills/run-tests/LICENSE +23 -0
  159. package/package/corpus/skills/run-tests/NOTICE +19 -0
  160. package/package/corpus/skills/run-tests/SKILL.md +305 -0
  161. package/package/corpus/skills/target-authoring/LICENSE +23 -0
  162. package/package/corpus/skills/target-authoring/NOTICE +17 -0
  163. package/package/corpus/skills/target-authoring/SKILL.md +165 -0
  164. package/package/corpus/skills/vectorization/LICENSE +23 -0
  165. package/package/corpus/skills/vectorization/NOTICE +17 -0
  166. package/package/corpus/skills/vectorization/SKILL.md +189 -0
  167. package/package/profile-catalog.json +87 -1
  168. package/package.json +3 -2
@@ -0,0 +1,135 @@
1
+ # I/O, Serialization & General Patterns
2
+
3
+ ## Contents
4
+
5
+ - Use HttpCompletionOption.ResponseHeadersRead for Streaming
6
+ - Use Async FileStream Operations
7
+ - Use Memory\<byte\> Overloads for Stream.ReadAsync/WriteAsync
8
+ - Use Span-Based TryFormat for Number Formatting
9
+ - Use static readonly for Runtime Devirtualization
10
+ - Avoid Explicit Static Constructors — Use Field Initializers
11
+ - Detection
12
+ - Patterns Requiring Manual Review
13
+
14
+ ### Use HttpCompletionOption.ResponseHeadersRead for Streaming
15
+ 🟡 **DO** use `ResponseHeadersRead` when downloading large responses | .NET Core 3.0+
16
+
17
+ ❌
18
+ ```csharp
19
+ var response = await client.GetAsync(uri);
20
+ ```
21
+ ✅
22
+ ```csharp
23
+ using var response = await client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead);
24
+ using var stream = await response.Content.ReadAsStreamAsync();
25
+ await stream.CopyToAsync(destinationStream);
26
+ ```
27
+
28
+ **Impact: ~2x faster for large downloads (10MB+), dramatically reduced memory usage.**
29
+
30
+ ### Use Async FileStream Operations
31
+ 🟡 **DO** use `FileStream` with `useAsync: true` for scalable file I/O | .NET 6+
32
+
33
+ ❌
34
+ ```csharp
35
+ using var fs = new FileStream(path, FileMode.Open);
36
+ ```
37
+ ✅
38
+ ```csharp
39
+ await using var fs = new FileStream(path, FileMode.Open, FileAccess.Read,
40
+ FileShare.Read, bufferSize: 4096, useAsync: true);
41
+
42
+ byte[] buffer = new byte[1024];
43
+ while (await fs.ReadAsync(buffer) != 0) { /* process */ }
44
+ ```
45
+
46
+ **Impact: Up to 3x faster async reads; allocation reduced from megabytes to hundreds of bytes.**
47
+
48
+ ### Use Memory\<byte\> Overloads for Stream.ReadAsync/WriteAsync
49
+ 🟡 **DO** use `Memory<byte>`-based stream overloads instead of `byte[]` overloads | .NET 5+
50
+
51
+ ❌
52
+ ```csharp
53
+ await stream.ReadAsync(buffer, 0, buffer.Length);
54
+ await stream.WriteAsync(buffer, 0, buffer.Length);
55
+ ```
56
+ ✅
57
+ ```csharp
58
+ await stream.ReadAsync(buffer.AsMemory());
59
+ await stream.WriteAsync(buffer.AsMemory());
60
+ ```
61
+
62
+ **Impact: Eliminates ~72 KB allocation per 1,000 read/write pairs on NetworkStream.**
63
+
64
+ ### Use Span-Based TryFormat for Number Formatting
65
+ 🟡 **DO** use `TryFormat` to format numbers into `Span<char>` buffers | .NET Core 2.1+
66
+
67
+ ❌
68
+ ```csharp
69
+ string formatted = value.ToString();
70
+ destination.Write(formatted);
71
+ ```
72
+ ✅
73
+ ```csharp
74
+ Span<char> buffer = stackalloc char[20];
75
+ if (value.TryFormat(buffer, out int charsWritten))
76
+ destination.Write(buffer[..charsWritten]);
77
+ ```
78
+
79
+ **Impact: Int32.ToString() ~2x faster in .NET Core 2.1, Int32 parsing ~5x faster in .NET Core 3.0.**
80
+
81
+ ### Use static readonly for Runtime Devirtualization
82
+ 🟡 **DO** store implementations in `static readonly` fields for JIT devirtualization | .NET Core 3.0+
83
+
84
+ ❌
85
+ ```csharp
86
+ private static Base s_impl = new DerivedImpl();
87
+ s_impl.Process();
88
+ ```
89
+ ✅
90
+ ```csharp
91
+ private static readonly Base s_impl = new DerivedImpl();
92
+ s_impl.Process();
93
+
94
+ private static readonly bool s_feature =
95
+ Environment.GetEnvironmentVariable("Feature") == "1";
96
+ ```
97
+
98
+ **Impact: Virtual call eliminated entirely — can be inlined to zero overhead. Dead code elimination in tier 1.**
99
+
100
+ ### Avoid Explicit Static Constructors — Use Field Initializers
101
+ 🟡 **AVOID** explicit `static` constructors when field initializers suffice | .NET Core 3.0+
102
+
103
+ ❌
104
+ ```csharp
105
+ class Foo
106
+ {
107
+ static readonly int s_value;
108
+ static Foo() { s_value = ComputeValue(); }
109
+ }
110
+ ```
111
+ ✅
112
+ ```csharp
113
+ class Foo
114
+ {
115
+ static readonly int s_value = ComputeValue();
116
+ }
117
+ ```
118
+
119
+ **Impact: Enables better JIT optimization and reduces potential lock overhead on static method access.**
120
+
121
+ ## Detection
122
+
123
+ Scan recipes for I/O and serialization anti-patterns. Run these and report exact counts.
124
+
125
+ ```bash
126
+ # new HttpClient() (socket exhaustion risk)
127
+ grep -rn --include='*.cs' 'new HttpClient(' --exclude-dir=bin --exclude-dir=obj . | wc -l
128
+
129
+ # new JsonSerializerOptions() not cached (592x slower in .NET 6)
130
+ grep -rn --include='*.cs' 'new JsonSerializerOptions' --exclude-dir=bin --exclude-dir=obj . | grep -v 'static\|readonly' | wc -l
131
+ ```
132
+
133
+ ### Patterns Requiring Manual Review
134
+
135
+ - **`JsonSerializer.Serialize/Deserialize` without source-gen context**: Can't determine from grep if a context parameter is passed
@@ -0,0 +1,219 @@
1
+ # Memory & String Patterns
2
+
3
+ ## Contents
4
+
5
+ - Use ReadOnlySpan\<byte\> for Constant Byte Data
6
+ - Use stackalloc for Small Temporary Buffers
7
+ - Use Span.TryWrite for Allocation-Free Interpolation
8
+ - Use Span.Split() for Zero-Allocation Splitting
9
+ - Use UTF8 String Literals (u8 suffix)
10
+ - Use ReadOnlySpan\<char\> Pattern Matching with switch
11
+ - Use params ReadOnlySpan\<T\> to Eliminate Array Allocations
12
+ - Avoid Chained String-Returning Operations
13
+ - Cache char.ToString() for Known Character Sets
14
+ - Detection
15
+ - Patterns Requiring Manual Review
16
+
17
+ ### Use ReadOnlySpan\<byte\> for Constant Byte Data
18
+ 🟡 **DO** assign constant byte arrays to `ReadOnlySpan<byte>` | .NET 5+
19
+
20
+ ❌
21
+ ```csharp
22
+ byte[] data = new byte[] { 0x48, 0x65, 0x6C, 0x6C, 0x6F };
23
+ ```
24
+ ✅
25
+ ```csharp
26
+ ReadOnlySpan<byte> data = [0x48, 0x65, 0x6C, 0x6C, 0x6F];
27
+ ReadOnlySpan<int> primes = [2, 3, 5, 7, 11, 13];
28
+ ```
29
+
30
+ **Impact: ~100x faster access than static byte[] field, zero allocation.**
31
+
32
+ ### Use stackalloc for Small Temporary Buffers
33
+ 🟡 **DO** use `stackalloc` for small, fixed-size temporary buffers | .NET Core+
34
+
35
+ ❌
36
+ ```csharp
37
+ char[] buffer = new char[64];
38
+ guid.TryFormat(buffer, out int written);
39
+ ```
40
+ ✅
41
+ ```csharp
42
+ Span<char> buffer = stackalloc char[64];
43
+ guid.TryFormat(buffer, out int written);
44
+ ```
45
+
46
+ **Impact: Zero heap allocation, no GC pressure, instant alloc/dealloc.**
47
+
48
+ ### Use Span.TryWrite for Allocation-Free Interpolation
49
+ 🟡 **DO** use `MemoryExtensions.TryWrite` to format into `Span<char>` buffers | .NET 6+
50
+
51
+ ❌
52
+ ```csharp
53
+ string formatted = $"Date: {dt:R}";
54
+ destination.Write(formatted);
55
+ ```
56
+ ✅
57
+ ```csharp
58
+ Span<char> buffer = stackalloc char[64];
59
+ buffer.TryWrite($"Date: {dt:R}", out int charsWritten);
60
+ ```
61
+
62
+ **Impact: Zero heap allocation for formatting operations.**
63
+
64
+ ### Use Span.Split() for Zero-Allocation Splitting
65
+ 🟡 **DO** use `MemoryExtensions.Split` for allocation-free string splitting | .NET 9+
66
+
67
+ ❌
68
+ ```csharp
69
+ string[] parts = input.Split(',');
70
+ ```
71
+ ✅
72
+ ```csharp
73
+ foreach (Range range in input.AsSpan().Split(','))
74
+ {
75
+ ReadOnlySpan<char> segment = input.AsSpan(range);
76
+ }
77
+ ```
78
+
79
+ **Impact: 208 bytes → 0 bytes per split, 2x faster.**
80
+
81
+ ### Use UTF8 String Literals (u8 suffix)
82
+ 🟡 **DO** use the `u8` suffix for compile-time UTF8 `ReadOnlySpan<byte>` | .NET 7+
83
+
84
+ ❌
85
+ ```csharp
86
+ byte[] header = Encoding.UTF8.GetBytes("Content-Type");
87
+ ```
88
+ ✅
89
+ ```csharp
90
+ ReadOnlySpan<byte> header = "Content-Type"u8;
91
+ ```
92
+
93
+ **Impact: 17ns → 0.006ns — eliminates runtime transcoding entirely.**
94
+
95
+ ### Use ReadOnlySpan\<char\> Pattern Matching with switch
96
+ 🟡 **DO** use `switch` on `ReadOnlySpan<char>` for allocation-free string matching | C# 11+
97
+
98
+ ❌
99
+ ```csharp
100
+ switch (attr.Value.Trim()) { case "preserve": /* ... */ break; }
101
+ ```
102
+ ✅
103
+ ```csharp
104
+ switch (attr.Value.AsSpan().Trim())
105
+ {
106
+ case "preserve": return Preserve;
107
+ case "default": return Default;
108
+ }
109
+ ```
110
+
111
+ **Impact: Eliminates string allocation from Trim() in switch-based dispatch.**
112
+
113
+ ### Use params ReadOnlySpan\<T\> to Eliminate Array Allocations
114
+ 🟡 **DO** add `params ReadOnlySpan<T>` overloads to library methods | C# 13 / .NET 9+
115
+
116
+ ❌
117
+ ```csharp
118
+ public static void Log(params string[] messages) { /* ... */ }
119
+ Log("Starting", "Processing", "Done");
120
+ ```
121
+ ✅
122
+ ```csharp
123
+ public static void Log(params ReadOnlySpan<string> messages) { /* ... */ }
124
+ Log("Starting", "Processing", "Done");
125
+ ```
126
+
127
+ **Impact: Eliminates params array allocation. E.g., Path.Join with 5+ segments saves 64 bytes per call.**
128
+
129
+ ### Avoid Chained String-Returning Operations
130
+ 🟡 **AVOID** chains of 3+ string-returning method calls that each allocate intermediates | .NET Core+
131
+
132
+ **Pattern 1: Chained .Replace() calls**
133
+
134
+ ❌
135
+ ```csharp
136
+ string result = input.Replace("a", "b").Replace("c", "d").Replace("e", "f");
137
+ ```
138
+ ✅
139
+ ```csharp
140
+ var sb = new StringBuilder(input.Length);
141
+ // single pass replacing all patterns
142
+ ```
143
+
144
+ **Pattern 2: Chained Regex.Replace() calls**
145
+
146
+ ❌
147
+ ```csharp
148
+ public static string Underscore(this string input) =>
149
+ Regex3.Replace(Regex2.Replace(Regex1.Replace(input, "$1_$2"), "$1_$2"), "_").ToLower();
150
+ ```
151
+ ✅
152
+ ```csharp
153
+ return string.Create(totalLength, state, (span, s) => { /* write directly */ });
154
+ ```
155
+
156
+ **Pattern 3: += string concatenation in loops**
157
+
158
+ ❌
159
+ ```csharp
160
+ string result = "";
161
+ foreach (var part in parts)
162
+ result += separator + part;
163
+ ```
164
+ ✅
165
+ ```csharp
166
+ var sb = new StringBuilder();
167
+ foreach (var part in parts)
168
+ sb.Append(separator).Append(part);
169
+ return sb.ToString();
170
+ ```
171
+
172
+ **Impact: Eliminates N-1 intermediate string allocations per chain. For `+=` in loops, eliminates O(n²) total allocation.**
173
+
174
+ ### Cache char.ToString() for Known Character Sets
175
+ 🟡 **DO** cache `char.ToString()` results when the set of characters is small and known | .NET Core+
176
+
177
+ ❌
178
+ ```csharp
179
+ return symbol.ToString();
180
+
181
+ foreach (var prefix in UnitPrefixes)
182
+ input = input.Replace(prefix.Value.Name, prefix.Key.ToString());
183
+ ```
184
+ ✅
185
+ ```csharp
186
+ private static readonly FrozenDictionary<char, string> s_charStrings =
187
+ new Dictionary<char, string>
188
+ {
189
+ ['k'] = "k", ['M'] = "M", ['G'] = "G",
190
+ }.ToFrozenDictionary();
191
+
192
+ return s_charStrings[symbol];
193
+ ```
194
+
195
+ **Impact: Eliminates one string allocation per char.ToString() call. Significant when called in loops or on hot paths.**
196
+
197
+ ## Detection
198
+
199
+ Scan recipes for memory and string anti-patterns. Run these and report exact counts.
200
+
201
+ ```bash
202
+ # .ToLower()/.ToUpper() without culture parameter (allocates + culture-sensitive)
203
+ grep -rn --include='*.cs' -E '\.(ToLower|ToUpper)\(\)' --exclude-dir=bin --exclude-dir=obj . | wc -l
204
+
205
+ # Chained .Replace( calls (3+ on one line — intermediate string allocations)
206
+ grep -rn --include='*.cs' '\.Replace(.*\.Replace(.*\.Replace(' --exclude-dir=bin --exclude-dir=obj . | wc -l
207
+
208
+ # params in method signatures (array allocation per call)
209
+ grep -rn --include='*.cs' 'params ' --exclude-dir=bin --exclude-dir=obj . | wc -l
210
+
211
+ # LINQ on strings — .All/.Any on IEnumerable<char> (replace with foreach loop)
212
+ grep -rn --include='*.cs' -E '\.(All|Any)\(char\.' --exclude-dir=bin --exclude-dir=obj . | wc -l
213
+ ```
214
+
215
+ ### Patterns Requiring Manual Review
216
+
217
+ - **Boxing via string.Format**: Can't determine argument types from grep — needs type analysis
218
+ - **`+=` string concatenation in loops**: `+=` matches all types (int, list, event, string) — needs type context to confirm string
219
+ - **`char.ToString()`**: Requires knowing the variable type is `char` — not reliably greppable
@@ -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.