diff --git a/.editorconfig b/.editorconfig index f0d75d2..23c9b7c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -36,7 +36,7 @@ indent_size = 2 end_of_line = crlf indent_size = 2 -# Json files +# Json and JsonC files [*.{json,jsonc}] end_of_line = crlf @@ -54,6 +54,9 @@ end_of_line = crlf # C# files [*.cs] end_of_line = crlf +# Suppressions follow CODESTYLE.md "Analyzer Diagnostics and Suppressions": prefer a +# [SuppressMessage] attribute or the owning project's .editorconfig; relax a rule +# repo-wide here only when it applies to every project (never a brownfield batch). dotnet_diagnostic.IDE0055.severity = none dotnet_analyzer_diagnostic.severity = suggestion csharp_indent_block_contents = true diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 900529a..a228ea4 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,8 +1,12 @@ -# GitHub Copilot Instructions for LanguageTags +# Copilot Instructions + +Repository conventions for GitHub Copilot (and any other AI agent reading this file). The **canonical guide is [AGENTS.md](../AGENTS.md)** at the repo root - read it first, including the [PR Review Etiquette](../AGENTS.md#pr-review-etiquette) review-loop contract this file's runbook implements. This file is intentionally narrow: commit/PR-title conventions (summarized inline so VS Code's commit-message and PR-title generators have them) plus the GitHub Copilot Review Runbook. -For C# style rules, see [`CODESTYLE.md`](../CODESTYLE.md) at the repo root. Do not duplicate those rules here. **Project-specific conventions and API/behavioral contracts also belong in [AGENTS.md](../AGENTS.md), not here** - this file is intentionally limited to the inline commit/PR-title summary and the GitHub Copilot Review Runbook. Non-Copilot agents (Claude Code, Codex, Cursor, ...) are not directed to this file and don't read it by default, so any rule a reviewer must honor has to live in `AGENTS.md` to be provider-independent. +For code-style rules, see [`CODESTYLE.md`](../CODESTYLE.md) at the repo root - one guide with a General section plus the .NET language section. + +Do not duplicate language-specific rules here. **Project-specific conventions and API/behavioral contracts also belong in [AGENTS.md](../AGENTS.md), not here** - this file is intentionally limited to the inline commit/PR-title summary and the GitHub Copilot Review Runbook. Non-Copilot agents (Claude Code, Codex, Cursor, ...) are not directed to this file and don't read it by default, so any rule a reviewer must honor has to live in `AGENTS.md` to be provider-independent. ## Commit Messages and Pull Request Titles @@ -138,11 +142,13 @@ Issue-level Copilot comments (those in `issues//comments`) have no resolution Reply-body conventions: - Accepted bug/style fix: include fixing commit SHA and a one-line summary. -- Declined style comment: cite the rule (AGENTS.md or CODESTYLE.md) and the existing-tree precedent. +- Declined style comment: cite the rule (AGENTS.md or the CODESTYLE.md language section) and the existing-tree precedent. - Declined architecture proposal: one-sentence rationale. After the final push, sweep-resolve stale older threads for removed code paths. ## When in Doubt -Read [AGENTS.md](../AGENTS.md) for this repo's conventions; [`CODESTYLE.md`](../CODESTYLE.md) is authoritative for C# style. Don't restate any of these files' rules in commit bodies or PR descriptions - keep those focused on the change itself. If you find a discrepancy that should be fixed in the template itself (this file or AGENTS.md is out of date, a rule is missing, something bit this repo and would bite the next derived repo), open an issue upstream in [`ptr727/ProjectTemplate`](https://github.com/ptr727/ProjectTemplate) rather than only fixing it locally - see [AGENTS.md "Staying in Sync with the Template"](../AGENTS.md#staying-in-sync-with-the-template). +Read [AGENTS.md](../AGENTS.md) for this repo's conventions. For code-style rules, [`CODESTYLE.md`](../CODESTYLE.md) (its General section plus the relevant language section) is authoritative. Don't restate any of these files' rules in commit bodies or PR descriptions - keep those focused on the change itself. + +**In a derived repo:** if you find a discrepancy that should be fixed in the template itself (this file or AGENTS.md is out of date, a rule is missing, something bit this repo and would bite the next), open an issue upstream in [`ptr727/ProjectTemplate`](https://github.com/ptr727/ProjectTemplate) rather than only fixing it locally - see the template's [AGENTS.md "Staying in Sync and Reporting Drift Upstream"](https://github.com/ptr727/ProjectTemplate/blob/main/AGENTS.md#staying-in-sync-and-reporting-drift-upstream). diff --git a/.github/workflows/build-nugetlibrary-task.yml b/.github/workflows/build-nugetlibrary-task.yml index 5dd96c2..ee4879a 100644 --- a/.github/workflows/build-nugetlibrary-task.yml +++ b/.github/workflows/build-nugetlibrary-task.yml @@ -22,6 +22,12 @@ on: branch: required: true type: string + # Smoke mode: build for validation only and skip the artifact zip/upload. A PR smoke run has no consumer for + # the artifact (the github-release job is gated `!smoke`), so uploading it just burns artifact storage. + smoke: + required: false + type: boolean + default: false outputs: # Output of the uploaded artifact id artifact-id: @@ -78,13 +84,16 @@ jobs: --skip-duplicate - name: Zip output step + if: ${{ !inputs.smoke }} run: | set -euo pipefail 7z a -t7z ${{ runner.temp }}/${{ env.PROJECT_ARTIFACT }} ${{ runner.temp }}/publish/* # Branch-suffixed so the publisher's branch matrix can build both # branches in one run without colliding on the artifact name. + # Skipped on smoke: the github-release job is `!smoke`, so nothing would consume it. - name: Upload build artifacts step + if: ${{ !inputs.smoke }} id: artifact-upload-step uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: diff --git a/.github/workflows/build-release-task.yml b/.github/workflows/build-release-task.yml index 0c8b291..17acb5a 100644 --- a/.github/workflows/build-release-task.yml +++ b/.github/workflows/build-release-task.yml @@ -57,6 +57,8 @@ jobs: branch: ${{ inputs.branch }} # Push to NuGet.org, never on a smoke build. push: ${{ inputs.nuget && !inputs.smoke }} + # Skip the artifact zip/upload on smoke (nothing consumes it on a PR). + smoke: ${{ inputs.smoke }} github-release: name: Publish GitHub release job diff --git a/.husky/task-runner.json b/.husky/task-runner.json index 009e6b3..dbcd960 100644 --- a/.husky/task-runner.json +++ b/.husky/task-runner.json @@ -15,7 +15,7 @@ ] }, { - "name": ".Net Format", + "name": ".NET Format", "command": "dotnet", "args": [ "format", diff --git a/.vscode/launch.json b/.vscode/launch.json index 5dbeaba..0047099 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "name": "LanguageTagsCreate", "type": "coreclr", "request": "launch", - "preLaunchTask": ".Net Build", + "preLaunchTask": ".NET Build", "program": "${workspaceFolder}/.artifacts/bin/LanguageTagsCreate/debug/LanguageTagsCreate.dll", "args": [ "--codepath", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index f8ae84a..6c819ef 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,8 +1,11 @@ { "version": "2.0.0", "tasks": [ + // .NET language group. A non-.NET repo drops this group and adds its own + // language's tasks. The first three tasks are the .NET clean-compile set + // (CODESTYLE.md) carried verbatim; the rest are convenience/project-specific. { - "label": ".Net Build", + "label": ".NET Build", "type": "process", "command": "dotnet", "args": [ @@ -20,7 +23,7 @@ } }, { - "label": ".Net Format", + "label": ".NET Format", "type": "process", "command": "dotnet", "args": [ @@ -37,9 +40,10 @@ "showReuseMessage": false, "clear": false }, + "dependsOrder": "sequence", "dependsOn": [ "CSharpier Format", - ".Net Build" + ".NET Build" ] }, { @@ -60,8 +64,9 @@ "clear": false } }, + // Convenience / project-specific tasks (adapt or drop per repo). { - "label": ".Net Tool Update", + "label": ".NET Tool Update", "type": "process", "command": "dotnet", "args": [ @@ -94,7 +99,7 @@ } }, { - "label": ".Net Outdated Upgrade", + "label": ".NET Outdated Upgrade", "type": "process", "command": "dotnet", "args": [ diff --git a/AGENTS.md b/AGENTS.md index 8efe587..27716ca 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -138,7 +138,8 @@ Anti-pattern: don't keep flipping the code on the same style point. Flip the rul This repo is derived from [`ptr727/ProjectTemplate`](https://github.com/ptr727/ProjectTemplate) and re-syncs against it periodically, not just at creation. - **Verbatim carries.** Pull the current template version of each shared artifact and re-apply it, adapting only this repo's placeholders: [`.github/copilot-instructions.md`](./.github/copilot-instructions.md) (the Copilot review runbook - change only the ``/``/`` values in its API snippets), [`.markdownlint-cli2.jsonc`](./.markdownlint-cli2.jsonc), [`.editorconfig`](./.editorconfig), [`.gitattributes`](./.gitattributes), and this file's [PR Review Etiquette](#pr-review-etiquette) section. The `.editorconfig` EOL/per-extension block is always-verbatim; its `[*.cs]`/ReSharper block is .NET-only and is carried here. Keep `copilot-instructions.md` **narrow** (provider mechanics plus the commit/PR-title summary); project-specific conventions and API contracts live in this file (see [Library API Conventions](#library-api-conventions)), not there - non-Copilot agents are not directed to that file. -- **CODESTYLE.md.** Keep [`CODESTYLE.md`](./CODESTYLE.md) as the full aggregate the template ships and re-sync the whole file, rather than hand-trimming per-language snippets. +- **CODESTYLE.md.** Re-sync the whole file from the template, then keep the **General** section plus the **.NET** language section and drop the language sections this repo doesn't ship (the per-language sections are droppable, exactly like the `.editorconfig` `[*.cs]` block; this repo is .NET-only, so the Python section is dropped). Repo-root placement is load-bearing - `AGENTS.md` and `.github/copilot-instructions.md` link it by relative path. Adapt the in-section repo-specific bits: the .NET project-folder list, the `InternalsVisibleTo` project names, and the VS Code task labels. Replacing the file wholesale and dropping whole sections is simpler to keep current than hand-editing per-language snippets. +- **.vscode/tasks.json.** Carry the named **clean-compile** task definitions verbatim - `.NET Build`, `CSharpier Format`, and `.NET Format` (which chains the first two then `dotnet format style --verify-no-changes`). Their names are owned by the `CODESTYLE.md` ".NET" section and their command sequence + arguments are the canonical clean-compile spec; don't loosen them. Convenience tasks (`.NET Tool Update`, `.NET Outdated Upgrade`, `Husky.Net Run`) are the adapt zone. - **Release notes.** Keep a short release-notes summary in [`README.md`](./README.md) and the full history in [`HISTORY.md`](./HISTORY.md); update both when cutting a release. - **Report drift upstream.** When a re-sync surfaces a template gap, an outdated instruction, or something that bit this repo and would bite the next derived repo, open an issue in [`ptr727/ProjectTemplate`](https://github.com/ptr727/ProjectTemplate) rather than only patching locally - the template is the single source of truth, and this upstream-issue rule is this repo's only cross-repo obligation. Do not maintain or reference a "known downstream" registry, and do not name sibling repositories in docs, comments, or workflows - that registry and the maintainer fan-out duty live in the template hub only. diff --git a/CODESTYLE.md b/CODESTYLE.md index 462f801..1dd97b8 100644 --- a/CODESTYLE.md +++ b/CODESTYLE.md @@ -1,74 +1,99 @@ # Code Style and Formatting Rules -## Build Requirements +This is the single code-style guide for the repo. The **General** section applies to every language and is always carried. Each **language section** is self-contained and **droppable**: a repo with no .NET side drops the .NET section - the same per-language model as [`.editorconfig`](./.editorconfig), whose `[*.cs]` block a non-.NET repo drops. -### Zero Warnings Policy +Cross-cutting *process* rules (PR titles, branching, US English, markdown style, comments philosophy, workflow YAML, PR review etiquette) live in [AGENTS.md](./AGENTS.md) and are not repeated here. + +## General + +These rules apply to every language in the repo. + +### Tooling Names and Casing + +Use each tool's official casing in task labels, docs, and prose - `.NET` (not `.Net`), `CSharpier`, `Husky.Net`. Don't invent personal variants. + +### Clean-Compile Verification + +Each language defines a **clean-compile** verification - the combination of build, formatter, linter, and code-analysis tools that must report clean before a commit. It is exposed as one or more **named** VS Code tasks (or, where a language ships no tasks, documented commands), and those definitions are **carried verbatim** across derived repos. The concrete names live in each language section below. + +- **Run it after every code change.** The relevant language's clean-compile must pass before you commit; CI runs the same checks as a backstop. +- **The named task definition is the canonical spec** - its exact command sequence, arguments, and strictness. You may run it through the VS Code task **or** by invoking the equivalent native commands directly; either is fine **only if the sequence, arguments, and strictness match exactly**. No shortcuts and no more-lenient options (for example, never drop `--verify-no-changes` or loosen a `--severity`). + +### Analyzer Diagnostics and Suppressions + +- **A new port is not a license to silence diagnostics.** Brownfield / just-ported status never justifies relaxing analyzer or linter severities or muting newly surfaced warnings - fix them. (The only brownfield allowance in this template is the one-time git-signing / line-ending migration described in [AGENTS.md](./AGENTS.md) and [README.md](./README.md), which has nothing to do with code analysis.) +- **Suppress only genuine false-positives or deliberate, documented exceptions**, always at the **narrowest scope that fits**, in this order of preference: + 1. An **in-code annotation on the specific symbol**, with a justification - the language's attribute/comment form, never a blanket pragma spanning a region. + 2. The **owning project's local config** when the exception is project-wide for one project (e.g. a test project's own `.editorconfig`). + 3. The **root / shared config** only when the suppression is genuinely applicable to **every** project in the repo. +- **Never blanket-relax a batch of rules project-wide** to get a port to build. The per-language mechanics (which attribute, which config key) are in each language section. + +### Markdown and Spelling + +These apply repo-wide, in every directory: + +1. **Markdown linting**: All `.md` files must be lint-clean (error and warning free) via the VS Code `markdownlint` extension. [`.markdownlint-cli2.jsonc`](./.markdownlint-cli2.jsonc) at the repo root is the single source of truth - the davidanson `markdownlint` extension and a command-line `markdownlint-cli2` run both read it, so the IDE and CLI stay in lock-step. Rules it deliberately disables (e.g. `MD013` line-length, `MD033` inline HTML) are **intentional** - do not "fix" them. This file is carried verbatim by every derived repo (see [AGENTS.md "Staying in Sync with the Template"](./AGENTS.md#staying-in-sync-with-the-template)). Fix violations at the source rather than disabling rules. +2. **Spelling**: All spelling must be clean via the CSpell VS Code integration; words must be correctly spelled in **US English** (the repo-wide convention - see [AGENTS.md](./AGENTS.md)). Project-specific terms go in the workspace CSpell config. + +## .NET + +*This section applies only to the .NET side. A repo with no .NET projects drops the whole section.* + +This is the style guide for the **.NET projects** in this repo: [`LanguageTags/`](./LanguageTags/) (the published `ptr727.LanguageTags` library), [`LanguageTagsCreate/`](./LanguageTagsCreate/) (the codegen CLI), and [`LanguageTagsTests/`](./LanguageTagsTests/) (the xUnit suite). + +### Build Requirements + +#### Zero Warnings Policy **CRITICAL**: All builds must complete without warnings. The project enforces this through: -1. **VS Code tasks** - - `CSharpier Format` → `.Net Build` → `.Net Format` - - `.Net Format` must pass with `--verify-no-changes` before commit - - Command: `dotnet format style --verify-no-changes --severity=info --verbosity=detailed` +1. **The `.NET Format` clean-compile task** (see [Clean-Compile Verification](#clean-compile-verification)) + - The .NET clean-compile is the **`.NET Format`** VS Code task, which chains `CSharpier Format` -> `.NET Build` -> `dotnet format style --verify-no-changes`. These three task definitions are carried verbatim in [`.vscode/tasks.json`](./.vscode/tasks.json). + - After any code change it must pass before commit. Run the `.NET Format` task. To run it natively instead, reproduce that task chain from [`.vscode/tasks.json`](./.vscode/tasks.json) exactly - `CSharpier Format`, then `.NET Build`, then the `dotnet format style --verify-no-changes --severity=info ...` verify - without dropping or loosening any argument (tasks.json is the canonical command spec). Bare `dotnet format` alone, skipping CSharpier or the build, is not sufficient. 2. **Analyzer configuration** - `latest-all` - `true` - - Analyzer severity is `suggestion`, but all warnings must be addressed + - Analyzer severity is `suggestion`, but all warnings must be addressed - see [Analyzer Diagnostics and Suppressions](#analyzer-diagnostics-and-suppressions); do not relax rules to dodge them. -3. **Husky.Net pre-commit hooks** - - Automated checks run before commits +3. **CI lint backstop** + - [`test-pull-request.yml`](./.github/workflows/test-pull-request.yml) runs `dotnet husky run` on every PR - the same CSharpier + `dotnet format style --verify-no-changes` checks the pre-commit hooks run locally -### Build Tasks +#### Build Tasks -Available VS Code tasks (use via `run_task` tool): +Available VS Code tasks (run them from VS Code's task runner - **Terminal -> Run Task** - or an agent's task-running tool). The first three are the clean-compile set, carried verbatim; the rest are convenience tasks a derived repo adapts or drops: -- `.Net Build`: Build with diagnostic verbosity -- `.Net Format`: Verify formatting and style (must pass) -- `CSharpier Format`: Auto-format code with CSharpier -- `.Net Tool Update`: Update dotnet tools -- `Husky.Net Run`: Run pre-commit hooks manually +- `.NET Build`: Build with diagnostic verbosity *(clean-compile)* +- `CSharpier Format`: Auto-format code with CSharpier *(clean-compile)* +- `.NET Format`: Run CSharpier and build, then verify formatting and style with `--verify-no-changes` *(clean-compile; the task to run after edits)* +- `.NET Tool Update`: Update dotnet tools *(convenience)* +- `.NET Outdated Upgrade`: Upgrade outdated NuGet dependencies, interactive prompt *(convenience)* +- `Husky.Net Run`: Run the configured Husky.Net pre-commit hooks manually *(convenience)* -## Tooling and Editor +### Tooling and Editor -### Code Formatting and Tooling +#### Code Formatting and Tooling 1. **CSharpier**: Primary code formatter - - Run before committing: `dotnet csharpier format --log-level=debug .` - + - Invoked by the `CSharpier Format` task / `dotnet csharpier format --log-level=debug .` 2. **dotnet format**: Style verification - Verify no changes: `dotnet format style --verify-no-changes --severity=info --verbosity=detailed` - -3. **Husky.Net**: Git hooks for automated checks - - Installed as a local dotnet tool (via `dotnet tool restore`) - - Install Git hooks locally with `dotnet husky install` - - Pre-commit hooks run formatting and style checks - -4. **Other tools** +3. **Other tools** - `dotnet-outdated-tool`: Dependency update checks - Nerdbank.GitVersioning: Version management -### Editor Baseline +Husky.Net runs the clean-compile checks as pre-commit git hooks. It is installed as a local dotnet tool (`dotnet tool restore`); run `dotnet husky install` to register the hooks. CI runs the same checks as a backstop. + +#### Editor Baseline 1. **Required VS Code extensions**: CSharpier, markdownlint, CSpell 2. **VS Code settings**: Use the workspace settings without overrides -### Markdown Files - -1. **Linting**: All `.md` files must be linted with the VS Code `markdownlint` extension (local only; no CI) -2. **Zero warnings**: Markdown linting must be error and warning free - -### Spelling - -1. **CSpell**: All spelling checks must be error free using the CSpell VS Code integration -2. **Accepted spellings**: Words must be correctly spelled in US or UK English -3. **Allowed exceptions**: Project-specific terms must be added to the workspace CSpell config - -## Coding Standards and Conventions +### Coding Standards and Conventions Note: Code snippets are illustrative examples only. Replace namespaces/types to match your project. -### C# Language Features +#### C# Language Features 1. **File-scoped namespaces** @@ -104,7 +129,7 @@ Note: Code snippets are illustrative examples only. Replace namespaces/types to var name = "test"; ``` -### Naming Conventions +#### Naming Conventions 1. **Private fields**: underscore prefix with camelCase @@ -125,7 +150,7 @@ Note: Code snippets are illustrative examples only. Replace namespaces/types to private const int MaxRetries = 3; ``` -### Code Structure +#### Code Structure 1. **Global usings**: Use `GlobalUsings.cs` for common namespaces @@ -169,9 +194,9 @@ Note: Code snippets are illustrative examples only. Replace namespaces/types to - Linux scripts (`.sh`): LF 6. **`#region`**: Do not use regions. Prefer logical file/folder/namespace organization. -7. **Member ordering (StyleCop SA1201)**: const → static readonly → static fields → instance readonly fields → instance fields → constructors → public (events → properties → indexers → methods → operators) → non-public in same order → nested types +7. **Member ordering (StyleCop SA1201)**: const -> static readonly -> static fields -> instance readonly fields -> instance fields -> constructors -> public (events -> properties -> indexers -> methods -> operators) -> non-public in same order -> nested types -### Comments and Documentation +#### Comments and Documentation 1. **XML documentation** - `true` @@ -202,20 +227,25 @@ Note: Code snippets are illustrative examples only. Replace namespaces/types to public async Task GetQuoteOfTheDayAsync(string category, CancellationToken cancellationToken) {} ``` -2. **Code analysis suppressions** - - Do not use `#pragma` sections to disable analyzers - - For one-off cases, use suppression attributes with justifications - - For project-wide suppressions, add rules to `.editorconfig` +#### Analyzer Suppressions (.NET) - ```csharp - [System.Diagnostics.CodeAnalysis.SuppressMessage( - "Design", - "CA1034:Nested types should not be visible", - Justification = "https://github.com/dotnet/sdk/issues/51681" - )] - ``` +Follow the scope hierarchy in [Analyzer Diagnostics and Suppressions](#analyzer-diagnostics-and-suppressions). .NET mechanics, narrowest first: + +- **Never use `#pragma warning disable`** to silence an analyzer. +- **Symbol-scoped**: a `[System.Diagnostics.CodeAnalysis.SuppressMessage(...)]` attribute with a `Justification`, on the specific member or type: + + ```csharp + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "Design", + "CA1034:Nested types should not be visible", + Justification = "https://github.com/dotnet/sdk/issues/51681" + )] + ``` + +- **Project-scoped** (e.g. a test project): a `dotnet_diagnostic..severity` entry in *that project's own* `.editorconfig`, with a comment explaining why. +- **Repo-wide**: a `dotnet_diagnostic..severity` entry in the root `.editorconfig`, only when the rule is genuinely not applicable to any project. Relaxing a batch of `CA*` rules (or `dotnet_analyzer_diagnostic.severity`) to push a brownfield port through the build is exactly what this forbids. -### Error Handling and Logging +#### Error Handling and Logging 1. **Serilog logging**: Use structured logging @@ -247,7 +277,7 @@ Note: Code snippets are illustrative examples only. Replace namespaces/types to 5. **Exceptions**: Do not swallow exceptions; log and rethrow or translate to a domain-specific exception -### Code Patterns +#### Code Patterns 1. **Guard clauses**: Prefer early returns for validation and error handling 2. **Async all the way**: Avoid blocking calls (`.Result`, `.Wait()`); use `async`/`await` @@ -264,7 +294,7 @@ Note: Code snippets are illustrative examples only. Replace namespaces/types to 12. **Read-only data**: Use immutable or frozen collections for read-only data sets 13. **Lazy initialization**: Use `Lazy` for static, thread-safe instantiation (e.g., logger factory, HTTP factory) -### Testing Conventions +#### Testing Conventions 1. **Framework**: xUnit with AwesomeAssertions @@ -287,7 +317,7 @@ Note: Code snippets are illustrative examples only. Replace namespaces/types to 3. **Naming**: Descriptive names with underscores 4. **Theory tests**: Use `[Theory]` with `[InlineData]` -## Project Configuration +### Project Configuration 1. **Target framework**: .NET 10.0 (`net10.0`) @@ -300,15 +330,14 @@ Note: Code snippets are illustrative examples only. Replace namespaces/types to - Include SourceLink: `true` - Embed untracked sources: `true` -4. **Internal visibility**: Use `InternalsVisibleTo` for test and benchmark access +4. **Internal visibility**: Use `InternalsVisibleTo` for test access (adapt the project names to your repo's test projects) ```xml - - + ``` -## Best Practices +### Best Practices 1. **Code reviews**: All changes go through pull requests