ccppccpp home

Profiles

Backend C#

C# / ASP.NET Core / EF Core services, APIs and workers with preserved diagnostics, explicit DI lifetimes, observable async work, owned resources, safe queries and HTTP surfaces, and evidenced completion. Rule IDs BCS-01–BCS-84; NEED TO blocks on proven violations.

Set this profile

ccpp cpo profile set backend-csharp

Inside Claude Code, prefix the command with ! to run it in the session. Downloading a profile needs a Builder or Team plan; listing them does not.

Policies

80 policies, grouped by what they guard.

Secrets & private data 2

Credentials, keys and personal data stay out of files, logs, commands and the conversation.

  • bcs65-config-secrets

    BCS-65 · Tracked appsettings and config files reference secrets (user secrets, environment, vault) instead of literal passwords, keys or tokens

  • bcs72-sensitive-logging

    BCS-72 · Log calls never receive passwords, tokens, API keys, authorization headers or connection strings

Authentication & authorization 4

Who may do what, from roles, privileges and permissions to CSRF, CORS and verified tokens.

  • bcs56-authorization-removed

    BCS-56 · The user approves removing [Authorize]/RequireAuthorization or making an endpoint anonymous

  • bcs56-unprotected-endpoints

    BCS-56 · Controllers and endpoints in declared protected paths require authorization (off until protectedEndpointPaths is set)

  • bcs59-antiforgery-disabled

    BCS-59 · The user approves disabling antiforgery validation on state-changing endpoints

  • bcs60-credentialed-any-origin

    BCS-60 · A CORS policy allowing credentials never accepts arbitrary origins (wildcard or accept-all predicates)

Untrusted input 3

Requests, downloads and tool output are validated before they reach SQL, a shell, eval or a deserializer.

  • bcs12-entity-request-body

    BCS-12 · Write endpoints bind request contracts (DTOs), not persistence entities (definition from csharp-ls; review)

  • bcs45-raw-sql-interpolation

    BCS-45 · Raw SQL APIs (FromSqlRaw, ExecuteSqlRaw, SqlCommand, Dapper) never receive interpolated or concatenated text

  • bcs55-unvalidated-request-bodies

    BCS-55 · MVC actions binding a request body validate it before side effects ([ApiController] or a ModelState check) (review)

Weakened checks 7

Suppressions, disabled lint or CI steps and relaxed strictness need a reason or the user's approval.

  • bcs02-nullable-disabled

    BCS-02 · Project files keep nullable analysis enabled; new production projects enable it; sources do not add '#nullable disable'

  • bcs03-blanket-pragma

    BCS-03 · No '#pragma warning disable' without a diagnostic ID (it silences every warning that follows)

  • bcs03-unjustified-suppressions

    BCS-03 · A new '#pragma warning disable <ID>' or [SuppressMessage] says why (comment or Justification) and is restored

  • bcs03-weakened-diagnostics

    BCS-03 · The user approves project or EditorConfig changes that silence diagnostics, lower analyzer severity or stop treating warnings as errors

  • bcs05-build-warnings

    BCS-02/BCS-04/BCS-05/BCS-06 · New nullable, dead-code, readonly and repository-style diagnostics in dotnet build output are fixed (warn)

  • bcs28-build-analyzer-findings

    BCS-28/BCS-30/BCS-31/BCS-38 · A dotnet build reporting CA2016, CS4014, CA2012 or CA2200 on lines this turn added is fixed before going on

  • bcs80-weakened-test-runs

    BCS-80/BCS-03 · The user approves CI or project changes that drop dotnet build/test steps, filter tests out or stop treating warnings as errors in CI

Error handling 5

Failures are propagated or handled, never swallowed or turned into fake success.

  • bcs38-rethrow-loses-stack

    BCS-38 · A caught exception is rethrown with 'throw;' (or wrapped with its cause), never 'throw ex;' (CA2200)

  • bcs39-swallowed-exceptions

    BCS-39 · No empty catch block; a catch recovers, translates at a boundary or adds context, and says so

  • bcs40-cancellation-as-failure

    BCS-40 · A catch-all around cancellable async work lets cooperative cancellation through instead of turning it into a failure (review)

  • bcs41-exceptions-for-validation

    BCS-41 · Expected invalid input is reported as a validation result, not thrown and caught in the same method

  • bcs42-controller-catch-all

    BCS-42 · Controllers do not translate every exception into their own error response; unexpected errors go through central handling (ProblemDetails)

Async & concurrency 11

Owned tasks, awaited promises, preserved cancellation and no blocking on event loops.

  • bcs24-blocking-waits

    BCS-24 · No blocking wait on a task (.Result, .Wait(), GetAwaiter().GetResult(), Task.WaitAll) outside startup code (typed by csharp-ls)

  • bcs25-sync-io-in-async

    BCS-25 · Async methods call the asynchronous database, file, stream and HTTP APIs, not their blocking overloads (typed by csharp-ls)

  • bcs26-async-void

    BCS-26 · Asynchronous methods return Task or ValueTask; async void only for event-handler signatures

  • bcs27-task-run-on-request-path

    BCS-27 · Request handlers do not wrap work in Task.Run just to await it (it only moves the work to another pool thread)

  • bcs28-dropped-cancellation

    BCS-28 · A method holding a CancellationToken passes it to every call that accepts one (overloads resolved by csharp-ls; CA2016)

  • bcs29-uncancellable-entry-points

    BCS-29 · Public async I/O entry points of controllers, repositories, clients and services accept a CancellationToken

  • bcs30-discarded-tasks

    BCS-30 · A call returning Task or ValueTask is awaited, returned or explicitly supervised, never dropped (typed by csharp-ls)

  • bcs31-valuetask-reuse

    BCS-31 · A ValueTask is consumed once (awaited, .Result, .AsTask()), never twice (typed by csharp-ls; CA2012)

  • bcs32-await-under-lock

    BCS-32 · No await while holding a monitor (lock statement or Monitor.Enter/Exit); use SemaphoreSlim for async exclusion

  • bcs33-request-objects-in-detached-work

    BCS-33 · Work that is not awaited (Task.Run, StartNew, thread pool, timers) does not capture HttpContext or request objects

  • bcs34-concurrent-httpcontext

    BCS-34 · Parallel work (Parallel.ForEach, Task.WhenAll over lambdas) does not touch the same HttpContext concurrently

Performance & resource bounds 10

Timeouts, bounded retries and fan-out, reused clients, closed resources, no N+1 queries.

  • bcs36-undisposed-resources

    BCS-36 · Streams, connections, commands, scopes, contexts and transactions created by an operation are disposed on every exit path

  • bcs37-unreleased-rentals

    BCS-37 · Rented buffers, semaphore slots and monitors are returned or released in a finally block

  • bcs46-materialize-before-filter

    BCS-46 · A provider-backed query is filtered, projected and limited before ToList/AsEnumerable, not after (typed by csharp-ls)

  • bcs47-unbounded-list-endpoints

    BCS-47 · HTTP endpoints do not materialize a whole table; list reads are paginated or explicitly limited (typed by csharp-ls; review)

  • bcs50-queries-in-loops

    BCS-50 · EF Core queries and navigation loads are not issued once per item of a loop (N+1; typed by csharp-ls; review)

  • bcs51-tracked-read-only-queries

    BCS-51 · Read-only entity queries use AsNoTracking when the method never saves (typed by csharp-ls)

  • bcs62-unbounded-request-bodies

    BCS-62 · Request-body limits are not removed or raised to unbounded, and request bodies are not read to the end without a limit (review)

  • bcs68-httpclient-per-operation

    BCS-68 · HttpClient instances come from IHttpClientFactory or a long-lived instance, never 'new HttpClient()' per operation

  • bcs69-unbounded-outbound-calls

    BCS-69 · Outbound HTTP clients keep a finite timeout and calls are not detached from cancellation (review)

  • bcs70-retrying-unsafe-methods

    BCS-70 · HTTP retry policies are limited to idempotent requests unless the side effect is deduplicated (review)

Architecture & boundaries 13

Declared layers and dependency directions, no import cycles, small modules, explicit dependencies.

  • bcs08-namespace-boundaries

    BCS-08 · Using directives respect the project's declared code boundaries (off until namespaceRules is set)

  • bcs08-project-boundaries

    BCS-08 · Project and package references respect the declared project boundaries (off until projectReferenceRules is set)

  • bcs09-project-reference-cycles

    BCS-09 · A new ProjectReference does not close a cycle in the project graph (followed three references deep)

  • bcs10-transport-in-domain

    BCS-10 · Declared pure-domain code does not import ASP.NET Core, HTTP or persistence namespaces (off until domainPaths is set)

  • bcs13-public-iqueryable

    BCS-13 · Public application contracts do not return IQueryable outside an approved query abstraction

  • bcs17-service-locator

    BCS-17 · Business code receives dependencies through its constructor, not GetService/GetRequiredService at run time

  • bcs18-scoped-in-singleton

    BCS-18 · A hosted service (a singleton) does not take a DbContext in its constructor; it creates a scope or a context per operation (type from csharp-ls)

  • bcs19-build-service-provider

    BCS-19 · Registration code does not build a second service provider (BuildServiceProvider) while configuring services

  • bcs20-disposing-injected-services

    BCS-20 · Classes do not dispose services the container injected into them (the container owns their lifetime)

  • bcs21-root-provider-in-hosted-services

    BCS-21 · A hosted service resolves services from a per-operation scope, not from the root provider

  • bcs22-shared-mutable-collections

    BCS-22 · Static (process-wide) collections are not mutated outside a lock; concurrent requests share them (review)

  • bcs23-scoped-in-middleware

    BCS-23 · Conventional middleware takes scoped services (a DbContext) in InvokeAsync, not its constructor (type from csharp-ls)

  • bcs74-wall-clock

    BCS-74 · Business logic takes time from an injected TimeProvider, not DateTime.Now/UtcNow, so expiry and scheduling are testable

HTTP & APIs 4

Request and response contracts, schemas, status codes, error bodies and published API surfaces.

  • bcs58-middleware-order

    BCS-58 · The pipeline keeps UseRouting, UseCors, UseAuthentication, UseAuthorization and endpoint mapping in the required order

  • bcs61-exception-details-exposed

    BCS-61 · Production error responses carry no stack traces or raw exceptions; the developer exception page is Development-only

  • bcs63-headers-after-response-start

    BCS-63 · Status code and headers are not set after the response body started (WriteAsync, CopyToAsync, SendFileAsync)

  • bcs64-sync-request-body

    BCS-64 · Request.Form and the request body are read asynchronously (ReadFormAsync), not synchronously; AllowSynchronousIO stays off

Databases & queries 4

Schemas, queries, transactions and the ORM used as intended.

  • bcs43-dbcontext-lifetime

    BCS-43 · A DbContext is never static or registered as a singleton; each unit of work gets its own (type from csharp-ls)

  • bcs44-overlapping-dbcontext-operations

    BCS-44 · Task.WhenAll does not run two EF Core operations on the same DbContext concurrently (typed by csharp-ls)

  • bcs48-unstable-pagination

    BCS-48 · Offset pagination (Skip) on a database query orders by a declared unique key (typed by csharp-ls)

  • bcs52-multiple-savechanges

    BCS-52 · A method calling SaveChanges more than once runs the writes in one transaction (or one SaveChanges) (review)

Configuration 2

Settings read once at a boundary, validated, with units and without unsafe defaults.

  • bcs66-configuration-in-business-code

    BCS-66 · Business code takes typed options (IOptions<T>), not IConfiguration with ad-hoc keys; composition roots and options classes may

  • bcs67-unvalidated-options

    BCS-67 · Options bound from configuration are validated at startup (ValidateOnStart), not on first use

Logging & observability 1

Structured logs, bounded metric labels, no debug prints left in production code.

  • bcs71-interpolated-log-templates

    BCS-71 · Log messages use constant templates with named placeholders, not interpolated or concatenated strings (CA2254)

Dependencies & toolchain 1

Packages change through the package manager, lockfiles stay consistent and the project's tools are used.

  • bcs07-package-additions

    BCS-07 · A new NuGet package names the changed feature or build tooling that uses it (review)

Tests 8

Tests assert behavior, stay deterministic and are not removed or skipped silently.

  • bcs54-inmemory-provider-tests

    BCS-54 · Tests of provider-specific queries and constraints run against the production database engine, not EF Core InMemory

  • bcs75-untested-changes

    BCS-75/BCS-76 · A turn that changes production C# code changes tests too, or says why none applies (review, once per stop)

  • bcs76-assertion-free-tests

    BCS-76 · Tests assert an observable outcome; no test without assertion and no tautological assertion (Assert.True(true))

  • bcs77-direct-controller-tests

    BCS-77 · HTTP contracts (routing, binding, authorization, errors) are tested through the application host, not by calling controllers directly

  • bcs78-static-test-state

    BCS-78 · Test classes do not share mutable static state between tests (order and parallelism dependence) (review)

  • bcs79-sleep-in-tests

    BCS-79 · Asynchronous tests wait for events or bounded conditions, not fixed sleeps (Thread.Sleep, Task.Delay)

  • bcs80-removed-tests

    BCS-80 · The user approves edits that remove test methods or assertions from a test file

  • bcs80-skipped-tests

    BCS-80 · The user approves newly skipped or ignored tests

Completion evidence 5

A turn ends with its checks run and passing; claims of success need proof after the last edit.

  • bcs-turn-baseline

    Records the work tree when a prompt starts, the baseline of the end-of-turn and build-output checks (BCS-01, BCS-05, BCS-28, BCS-75)

  • bcs01-new-compile-errors

    BCS-01 · Claude does not end a turn with compiler errors it introduced in C# sources or the files that use them (csharp-ls)

  • bcs81-placeholders

    BCS-81 · Production code ships implemented behavior, not NotImplementedException, TODO-only bodies or TODO stub returns

  • bcs83-completion-claims

    BCS-83 · A final message claiming a passing build or tests needs a successful dotnet run after Claude's last edit

  • bcs83-evidence-ledger

    BCS-83 · Records, per session, Claude's edits and the dotnet build, test or format runs that succeeded after them