diff --git a/AGENTS.md b/AGENTS.md index 24ae4423..a1ffc6ed 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -199,6 +199,11 @@ Bring the user in when: Anti-pattern: don't keep flipping the code on the same style point. Flip the rule once and stick to the rule. +## Communicating with the User + +- **Reference every pull request as a clickable link.** When you mention a PR - in chat, a summary, or a report - render it as a markdown link to the PR (`[#123](https://github.com///pull/123)`), never a bare `#123`. The same applies to issues and commits. +- **Ask for input as a numbered list.** When you need the user to decide or answer, present the questions - and any options - as a numbered list so they can reply per number. A single inline question is fine; two or more are always numbered. + ## Workflow YAML Conventions These conventions describe the target state. New and modified workflows must respect them; the rest of the repo is expected to be brought up to the same standard. Sweep PRs that apply a rule everywhere are welcome when a rule changes. @@ -240,6 +245,12 @@ The CI lint job runs these tools (workflow YAML and Markdown), but run them loca When pulling a public image fails on a Docker-Desktop/WSL credential-helper error (`docker-credential-desktop.exe: exec format error`), retry with an empty Docker config: `DOCKER_CONFIG=$(mktemp -d) docker run ...` after writing `{}` to `$DOCKER_CONFIG/config.json`. +## Supported Development Platforms + +- **Cross-platform by default - Windows + macOS + Linux.** Linux runs natively (a Linux desktop, or SSH/remote into a Linux host), through a devcontainer on Windows or macOS, or through WSL2 on Windows - the devcontainer and WSL routes carry their own nuances (mounts, path translation, SSH-agent forwarding) but deliver the same toolchain. Editing is cross-platform through the GUI regardless of where code runs. Assume this default. +- **A repo's platform ceiling is set by its dependencies, not tooling effort; decide it per repo before writing dev tooling.** Narrow below the default only for a hard runtime ceiling - the code can only execute or test on one platform (e.g. a Home Assistant integration is Linux-only: HA Core has POSIX-only dependencies and will not run natively on Windows, so even maximal tooling yields only lint-only there). The narrowing axis is where code *executes* for dev and testing - native, SSH-remote, container, or CI - never where editing happens. +- **Record a narrowed platform and its reason in the repo** (README/AGENTS) so the restriction reads as a deliberate dependency ceiling, not an omission. + ## Devcontainer Contributors commit to this repo with signed commits; the SSH-signing setup lives in [docs/ssh-signing.md](./docs/ssh-signing.md), host prerequisites in [docs/host-setup.md](./docs/host-setup.md), and devcontainer SSH-agent forwarding in [docs/devcontainer.md](./docs/devcontainer.md). This repo ships no application toolchain; the per-language devcontainer definitions it once used are kept as reference under [`catalog/snippets/devcontainer/`](./catalog/snippets/devcontainer/). diff --git a/CODESTYLE.md b/CODESTYLE.md index f3633687..2a374d50 100644 --- a/CODESTYLE.md +++ b/CODESTYLE.md @@ -156,7 +156,7 @@ Note: Code snippets are illustrative examples only. Replace namespaces/types to global using System; global using System.Net.Http; global using System.Threading.Tasks; - global using Serilog; + global using Microsoft.Extensions.Logging; ``` 2. **Usings placement**: Outside namespace, sorted with `System` directives first @@ -245,15 +245,13 @@ Follow the scope hierarchy in [Analyzer Diagnostics and Suppressions][analyzer-d #### Error Handling and Logging -1. **Serilog logging**: Use structured logging +1. **Structured logging**: Use structured message templates - Serilog is the **application's** concrete backend; a library never references it (see item 2) ```csharp - logger.Error(exception, "{Function}", function); + logger.LogError(exception, "{Function}", function); ``` -2. **Library log configuration**: Libraries must expose logging configuration - - Provide options or settings to supply an `ILoggerFactory` and/or `ILogger` - - Offer a global fallback logger for static usage when needed +2. **Libraries log through abstractions, never a concrete backend.** A NuGet **library** depends only on `Microsoft.Extensions.Logging.Abstractions` and exposes an `ILoggerFactory` seam - a settable global factory defaulting to `NullLoggerFactory` (fallback `NullLogger.Instance`) with `SetFactory`/`TrySetFactory`, and/or an `ILoggerFactory`/`ILogger` parameter in its API. It must **not** reference Serilog or any sink - that forces a logging framework on every consumer and drags in AOT-incompatible dependencies. The consuming **application** owns the concrete logger (Serilog is fine there), bridges it to `ILoggerFactory` (e.g. `SerilogLoggerFactory` from `Serilog.Extensions.Logging`), and injects it. Reference: `LanguageTags` - `LogOptions` in the library; the CLI's `LoggerFactory` builds the Serilog-backed factory and injects it via `LogOptions.SetFactory`. 3. **CallerMemberName**: Use for automatic function name tracking @@ -294,7 +292,7 @@ Follow the scope hierarchy in [Analyzer Diagnostics and Suppressions][analyzer-d #### Testing Conventions -1. **Framework**: xUnit with AwesomeAssertions +1. **Framework**: **xUnit v3 or later** (the `xunit.v3` package, never the legacy v2 `xunit` package) with **AwesomeAssertions** for every assertion; native xUnit asserts (`Assert.Equal`, `Assert.True`, ...) are not allowed - use the fluent `.Should()` API ```csharp [Fact]