refactor(rules): split C# guidance by topic
This commit is contained in:
1 parent
d4f45a3320
commit
27db155b85
10 files changed
+118
-117
No files matched your search
@@ -0,0 +1,14 @@
|
||||
# C# Rules
|
||||
|
||||
For C# or .NET work, open only the topic rules relevant to the task. Follow repository conventions and load applicable shared security rules as well.
|
||||
|
||||
| Topic | Codex rule | Claude skill |
|
||||
| --- | --- | --- |
|
||||
| Language style and code organization | `references/coding-style.md` | `rules-csharp-coding-style` |
|
||||
| Types, collections, and public contracts | `references/types-and-collections.md` | `rules-csharp-types-and-collections` |
|
||||
| Architecture and API boundaries | `references/architecture-and-apis.md` | `rules-csharp-architecture-and-apis` |
|
||||
| Async work and concurrency | `references/async-and-concurrency.md` | `rules-csharp-async-and-concurrency` |
|
||||
| Performance | `references/performance.md` | `rules-csharp-performance` |
|
||||
| Security | `references/security.md` | `rules-csharp-security` |
|
||||
| Validation, errors, and logging | `references/safety-and-errors.md` | `rules-csharp-safety-and-errors` |
|
||||
| Tests, dependencies, and analyzers | `references/testing-and-dependencies.md` | `rules-csharp-testing-and-dependencies` |
|
||||
@@ -0,0 +1,15 @@
|
||||
# C# Architecture and APIs
|
||||
|
||||
Apply these rules when designing public APIs, service boundaries, or application architecture.
|
||||
|
||||
* Give APIs explicit, strongly typed contracts. Validate external input at the boundary and keep trusted internal paths free of redundant checks.
|
||||
* Separate request models from persistence and domain models. Bind only fields the caller may set, and project only fields the caller may read.
|
||||
* Authenticate and authorize before accessing protected resources. Enforce resource ownership and tenant scope in the data access path, not only in the UI or route layer.
|
||||
* Bound page size, payload size, query complexity, and operation cost. Use explicit pagination for potentially large collections.
|
||||
* Keep application, domain, and infrastructure concerns separate. Avoid cross-layer coupling and service-locator patterns.
|
||||
* Use dependency injection when substitution or lifecycle management is needed. Keep dependencies explicit and avoid excessive constructor dependencies.
|
||||
* Prefer composition over inheritance; use inheritance only when the contract requires it. Seal types when extension is not intended.
|
||||
* Keep classes and methods focused. Avoid wrappers, abstractions, reflection, and global mutable state without a concrete need.
|
||||
* Preserve established project and public API conventions unless a concrete compatibility or correctness issue requires a change.
|
||||
* Keep authorization decisions close to the protected operation and fail closed when identity, ownership, or policy evaluation is unavailable.
|
||||
* Avoid returning persistence entities, internal exception details, or fields that are not part of the public contract.
|
||||
@@ -0,0 +1,13 @@
|
||||
# C# Async and Concurrency
|
||||
|
||||
Apply these rules when adding or changing asynchronous APIs, background work, or concurrent processing.
|
||||
|
||||
* Use asynchronous APIs for genuinely asynchronous I/O; do not wrap synchronous work in unnecessary tasks.
|
||||
* Keep asynchronous operations async through the call chain. Avoid `.Result`, `.Wait()`, and other synchronous waits that can block threads or deadlock.
|
||||
* Accept and propagate `CancellationToken` through work that can take meaningful time or be cancelled by its caller.
|
||||
* Bound concurrency for large or unbounded workloads. Avoid creating a task per item or using uncontrolled `Task.WhenAll`; use an appropriate queue or concurrency limiter when work must be throttled.
|
||||
* Use `ValueTask` only when profiling supports it and its usage contract is clear; otherwise prefer `Task`.
|
||||
* Keep shared state safe under concurrent access and preserve cancellation and exception behavior when coordinating tasks. Prefer immutable messages or synchronization primitives with clear ownership over unsynchronized shared mutation.
|
||||
* Avoid holding locks across `await`, blocking thread-pool threads, and starting background work whose lifetime is detached from its owner.
|
||||
* For producer/consumer work, apply backpressure and bound buffered items so a fast producer cannot exhaust memory.
|
||||
* Retry only transient failures, with bounded attempts and delay. Preserve idempotency and cancellation, and avoid multiplying retries across nested layers.
|
||||
@@ -0,0 +1,13 @@
|
||||
# C# Coding Style
|
||||
|
||||
Apply these rules when editing C# syntax, class structure, and everyday code organization.
|
||||
|
||||
* Follow current C# and .NET conventions and the style already used in the project.
|
||||
* Prefer direct, readable code over clever control flow, hidden magic, or outdated verbosity.
|
||||
* Keep classes, methods, and responsibilities focused. Use descriptive names and established domain terms; avoid unexplained abbreviations.
|
||||
* Prefer composition over inheritance. Use inheritance only for a real substitutable contract, and seal types when extension is not intended.
|
||||
* Avoid unnecessary wrappers, abstractions, reflection, runtime type checks, and global mutable state.
|
||||
* Prefer immutable or readonly state when it simplifies ownership and reduces accidental mutation.
|
||||
* Keep side effects visible. Make behavior deterministic and easy to test where practical.
|
||||
* Add comments or API documentation only for non-obvious decisions, public contracts, or documented project requirements.
|
||||
* Remove dead code instead of leaving commented-out implementations.
|
||||
@@ -0,0 +1,14 @@
|
||||
# C# Performance
|
||||
|
||||
Apply these rules when optimizing code or reviewing runtime and resource costs.
|
||||
|
||||
* Establish a representative baseline before changing code. Measure the affected workload, input size, concurrency, and environment; distinguish average latency from tail latency and throughput.
|
||||
* Find the dominant cost before optimizing: architecture, database access, network and I/O, algorithms, concurrency, allocations and GC, then CPU-level work.
|
||||
* Choose collections and algorithms for actual access patterns. Check asymptotic cost and data growth; avoid repeated scans, unnecessary sorting, copies, and unbounded result sets.
|
||||
* Keep data close to where it is processed. Filter and project in the database, avoid N+1 queries, bound page sizes, and avoid materializing rows or columns the caller does not use.
|
||||
* Stream large inputs and outputs when buffering the whole value would waste memory. Bound queues, batches, and parallel work to match downstream capacity.
|
||||
* Reduce allocations in measured hot paths: avoid repeated string construction, iterator/delegate capture, boxing, and collection resizing when profiling identifies them as material costs.
|
||||
* Consider pooling only for expensive reusable objects with clear ownership and reset rules. Pooling can retain memory or leak state between users; measure it and cap retained capacity.
|
||||
* Use `Span<T>`, `ValueTask`, preallocation, or specialized low-level APIs only when their benefit is demonstrated and they preserve readable, safe ownership.
|
||||
* Cache only when repeated work is measurable and the key, lifetime, size bound, invalidation, and sensitive-data handling are explicit.
|
||||
* After an optimization, run the same workload and compare correctness, allocations, GC, CPU, latency, and throughput against the baseline. Keep the simplest change that meets the target.
|
||||
@@ -0,0 +1,14 @@
|
||||
# C# Safety and Error Handling
|
||||
|
||||
Apply these rules when handling external input, failures, logs, or sensitive information.
|
||||
|
||||
* Treat external data as untrusted and validate it at system boundaries. Do not rely on static types to validate runtime input.
|
||||
* Validate size, range, format, and allowed values before expensive parsing or allocation. Keep validation consistent with downstream business and security constraints.
|
||||
* Fail fast for invalid arguments or impossible state. Do not use exceptions for routine control flow or swallow unexpected exceptions.
|
||||
* Preserve useful exception context without exposing secrets, personal data, or internal details in logs, APIs, or user-facing errors.
|
||||
* Use structured logging and avoid excessive logging, especially in hot paths. Never log credentials, tokens, or sensitive payloads.
|
||||
* Keep authorization, certificate validation, encryption, and other security controls intact. Follow the focused security rules for the affected boundary.
|
||||
* Keep side effects explicit and deterministic where practical; propagate cancellation and dispose owned resources correctly.
|
||||
* Use narrow exception handling around the operation that can fail. Do not catch broadly merely to retry, continue with partial state, or convert failures into success.
|
||||
* Avoid returning different error detail to unauthenticated callers when it would disclose whether protected accounts, records, or resources exist.
|
||||
* Treat resource limits as part of safe error handling: cap request bodies, decompressed data, collection sizes, parser depth, and other attacker-controlled work.
|
||||
@@ -0,0 +1,14 @@
|
||||
# C# Security
|
||||
|
||||
Apply these rules when implementing or reviewing security-sensitive .NET code. Load the matching shared security rule for the affected API, identity, data, file, network, cryptographic, or dependency boundary as well.
|
||||
|
||||
* Validate untrusted input at the boundary and enforce authorization for the specific resource and operation. Static types and client-side checks do not establish trust.
|
||||
* Use parameterized database APIs. If a query identifier or sort expression cannot be parameterized, select it from a fixed allowlist; never concatenate untrusted input into SQL.
|
||||
* For file access, canonicalize the resolved path and verify it remains inside the authorized root. Account for reparse points and symlinks when the attacker can affect directory contents.
|
||||
* For process execution, avoid a shell. Pass executable and arguments separately using APIs supported by the target framework, validate each argument, and restrict executable paths.
|
||||
* Deserialize into explicit DTOs or allowlisted types. Avoid unsafe polymorphic type activation and unbounded object graphs for untrusted data.
|
||||
* Bound request and parser work before allocating or processing large values. Apply timeouts to regular expressions that evaluate untrusted input and prefer patterns with predictable complexity.
|
||||
* Keep secrets in an approved secret store or protected configuration source. Never embed them in assemblies, client bundles, source, diagnostics, or exception messages.
|
||||
* Use platform TLS and established cryptographic APIs. Do not create custom cryptography or disable certificate validation; use cryptographically secure randomness for security tokens.
|
||||
* Use framework output encoding and safe APIs for HTML, XML, and other interpreters. Do not build executable markup or queries from untrusted strings.
|
||||
* Review security-sensitive changes with tests for rejected, malformed, oversized, unauthenticated, and cross-tenant inputs, as applicable.
|
||||
@@ -0,0 +1,10 @@
|
||||
# C# Testing and Dependencies
|
||||
|
||||
Apply these rules when changing tests, package references, analyzers, or build diagnostics.
|
||||
|
||||
* Write deterministic behavior-based tests. Avoid coupling assertions to private call order, implementation details, current time, or uncontrolled external services.
|
||||
* Make code testable through clear contracts and dependencies; do not add production hooks or abstractions solely for tests without a concrete need.
|
||||
* Prefer the .NET BCL and existing supported packages over new libraries when they solve the problem adequately.
|
||||
* Keep dependencies minimal, maintained, compatible, and updated through the repository's normal package-management process.
|
||||
* Treat compiler, analyzer, and nullable warnings seriously. Suppress a diagnostic only for a specific, documented reason and narrow the suppression to the affected code.
|
||||
* Run focused tests and analyzers for the changed path; broaden verification when shared behavior or compatibility could be affected.
|
||||
@@ -0,0 +1,11 @@
|
||||
# C# Types and Collections
|
||||
|
||||
Apply these rules when designing type contracts, choosing collection shapes, or exposing data through APIs.
|
||||
|
||||
* Prefer strongly typed models over `object`, `dynamic`, loosely typed dictionaries, or string-based contracts.
|
||||
* Prefer concrete collection types for internal parameters, properties, and local APIs when the contract does not need abstraction.
|
||||
* Expose collection interfaces such as `IReadOnlyList<T>`, `IEnumerable<T>`, `IDictionary<TKey, TValue>`, or `ICollection<T>` only when their capability is part of an intentional boundary or public contract.
|
||||
* Choose collection types based on lookup, ordering, mutation, and iteration needs. Pre-size collections only when expected capacity is known and material.
|
||||
* Avoid large mutable structs and direct exposure of mutable internal collections.
|
||||
* Prefer immutable data where practical, while preserving established API and serialization contracts.
|
||||
* Use `Span<T>` and related low-level types only when the performance rule's measurement justifies their lifetime and ownership constraints.
|
||||
Reference in new issue
Block a user