Repository navigation
chore(ai): put test categories on the test classes only - #32
Closed
xperiandri wants to merge 26 commits into
Closed
xperiandri wants to merge 26 commits into
xperiandri wants to merge 26 commits into
Conversation
* Significantly restructured `copilot-instructions.md` to provide detailed project info, solution structure, library usage, and comprehensive F# coding standards. * Added explicit guidance on language features, class instantiation, extension members, naming, and testing. * Emphasized maintainability, code quality, and directory layout.
Update `Microsoft.SourceLink.GitHub` to `10.0.402` together with the SDK it ships with. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nfig Batch files are checked out with CRLF and PowerShell scripts with LF on every platform, and `.editorconfig` states the same instead of asking for CRLF in PowerShell scripts. The inline comments of `.editorconfig` move onto their own lines: the specification does not support inline comments, so they were read as part of the value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`.editorconfig` follows the settings of Fantomas 8: - `fsharp_keep_indent_in_branch` became `fsharp_experimental_keep_indent_in_branch`; under its old name the setting was ignored. - `fsharp_semicolon_at_end_of_line` and `fsharp_max_dot_get_expression_width` no longer exist. - `end_of_line=lf` matches the line endings `.gitattributes` stores F# files with, so formatting on Windows no longer rewrites them as CRLF. The comments state the current defaults and link to the current documentation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fantomas 8 no longer puts a space between a type application and its argument list: `Create<'T> ()` becomes `Create<'T>()`. Whitespace only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
`ToolRestore` ran only in design-time builds, so a command-line build relied on the FAKE `DotnetToolRestore` target, and that target was a dependency of `BuildDocs` alone: on CI `CheckFormatCode` found no Fantomas and passed without checking anything. `ToolRestore` now runs before every restore, and the FAKE target is gone. `ToolUpdate` is removed: its `Outputs` used an undefined property, so MSBuild always skipped it. Formatting is delegated to one instance of a project without a target framework, so a project is formatted once per build however many target frameworks it has, and Fantomas runs twice because one pass is not always idempotent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FAKE `6.2.0` adds `DotNet.testMTP`, which runs `dotnet test` with the MSTest runner and takes the project, the configuration, the results directory and the code coverage as typed options. It also contains `6.1.5`: the last entry of the changelog keeps its date and description, and the message of a release commit keeps its quotes. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- `Microsoft.NET.Test.Sdk` `18.5.1` -> `18.11.0` - `Microsoft.Build.Framework` `18.6.3` -> `18.11.0` - `System.Collections.Immutable` `10.0.8` -> `10.0.13` - `System.Drawing.Common` and `System.Formats.Asn1` `10.0.8` -> `10.0.13` Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…tCover leftovers `DotnetTest` passed `/p:AltCover*` properties although no project references AltCover, and `GenerateCoverageReport` looked for `tests/**/coverage*.xml`, which nothing produced, so `ENABLE_COVERAGE` collected no coverage. `DotnetTest` now runs `DotNet.testMTP` for each test project and lets the MSTest runner collect coverage in the Cobertura format into `TestResults`, where `GenerateCoverageReport` reads it and writes HTML and Cobertura reports. Coverage is collected when `ENABLE_COVERAGE` is set or `GenerateCoverageReport` is among the targets. Also: - the release commit is named `release: bump version to ...`; - `quoted` is shared by the documentation target; - the workflows no longer explain `ENABLE_COVERAGE: false` with AltCover. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
`src/Directory.Build.props` holds what every library project shares, next to the `tests/Directory.Build.props` the test projects already have: it marks the project as packable, generates the documentation file, publishes the repository URL, embeds untracked sources and puts the PDB into the package next to the assembly. The solution groups the projects into `src` and `tests` folders. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y has no date `GenerateAssemblyInfo` read `latestEntry.Date.Value` and failed with a `NullReferenceException` for an entry without a date. The date is optional in a changelog entry, so the `ReleaseDate` metadata is now written only when the entry has one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ersion The package described itself as an F# API for Azure Cosmos DB and carried the `AzureCosmosDisableNewtonsoftJsonCheck` property, both left over from the project file this one was copied from. The description is `F# bindings for System.Collections.Immutable` again. `GenerateAssemblyInfo` is switched off for the SDK because the FAKE target of the same name writes `AssemblyInfo.fs`, but the project did not compile that file, so the assembly had version `0.0.0.0`. The generated file is now the first compiled file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FsLangMCP gives agents semantic F# tools: symbol lookup, diagnostics, usages and refactoring previews. It is a local tool pinned in the tool manifest, so `dotnet tool restore` installs it, and `.mcp.json` starts it with `dotnet tool run fslangmcp`. The servers in `.mcp.json` are sorted by name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- `CLAUDE.md` imports `.github/copilot-instructions.md`, so GitHub Copilot and Claude Code share one set of instructions; `AGENTS.md` points other agents at the same file. - `.mcp.json` lists the servers for Claude Code under `mcpServers` next to `servers`. - The GitHub MCP server does not support the OAuth dynamic client registration Claude Code needs, so `.claude/scripts/github-mcp-headers.ps1` passes it the token Git Credential Manager already stores. - `ClaudeSkillsLink` links `.claude/skills` to `.github/skills` when that folder exists; the link is local and git-ignored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The generic sections are replaced with the current shared ones: - `MCP Servers` – when to prefer the F#, GitHub and Microsoft Docs servers; - `F# Coding Guidelines` – tooling, asynchrony and cancellation, values and collections (`voption`, struct tuples, `ToLookup`, pipelines kept in one module, comparing `System.Type` values), functions, lambdas and strings (explicit `StringComparison`, spans), nullable reference types, XML documentation comments and the order of `open` statements; - `Naming Conventions` – test names with spaces; - `Testing` – `StringAssert`, `Assert.Contains`, `Assert.HasCount` and running tests with `--no-build`. The project details, the solution structure, the libraries in use and the test category rules are specific to this repository and stay as they are. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GitHub Copilot applies `.github/instructions/test-categories.instructions.md` to `tests/**/*.fs`, and `.claude/rules/test-categories.md` imports it for Claude Code under the same path. The instructions say: - No category is written as a string in `[<TestCategory "...">]`. - Each attribute gives one category. - Each attribute name has the `TestCategoryAttribute` suffix. - The category is the name without the suffix, written as separate words; a product name or a type name keeps its spelling. - Each test class has the attribute of the operation or component that it examines. - The attributes of each `TestCategories.fs` file are sorted alphabetically by type name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- `actions/configure-pages` `v5` -> `v6` - `actions/upload-pages-artifact` `v4` -> `v5` - `actions/deploy-pages` `v4` -> `v5` Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The dev container installs the starship feature and enables it in zsh when the container is created. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e its sibling keys `target` was indented by five spaces while the other safe outputs indent their keys by four. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
README: - the required SDK is the `10.0.401` pinned in `global.json`, not `8.0 or higher`; - `CONFIGURATION` defaults to `Debug`, and to `Release` only when `PublishToNuGet` runs; - `ENABLE_COVERAGE` and `DotnetTest` describe the MSTest runner instead of AltCover and the solution file; - `PublishToNuGet` pushes with `dotnet nuget push`, not `paket push`; - the release commit is named ``release: bump version to `x.y.z` ``; - the badge of the `.NET Core` workflow, which does not exist, is removed, and the NuGet badge is loaded over HTTPS. The pull request template names this project instead of the one it was copied from. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the assembly info Since FAKE `6.1.5` the changelog parser keeps the date and the description of the last entry of the file, which `6.1.4` dropped. `1.0.0` is the only entry here, so the regenerated `AssemblyInfo.fs` carries its `ReleaseDate` metadata again, and the comment on the date check no longer refers to the defect. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A solution restores its projects in parallel, so `ToolRestore` ran `dotnet tool restore` in every project at the same time and all of them touched the same marker file. The `Restore dependencies` step of the Copilot setup, which restores the solution, failed on Linux after `ToolRestore` started to run on every restore. Every project now delegates to one instance of `Directory.Build.targets`, which MSBuild builds once per build, so the tools are restored once and the other projects wait for that run. The Copilot setup no longer restores the tools on its own before restoring the solution. `Format` says why it runs Fantomas twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Testing section asked for an operation category on every test method through `TestCategory (nameof …)`. That contradicts the path-scoped rules of `.github/instructions/test-categories.instructions.md`, which forbid a category written as a string in `[<TestCategory "...">]` and put the attribute of the examined operation or component on the test class. The Testing section no longer repeats category rules, and the path-scoped rules now also say that each category is declared as a `TestCategoryBaseAttribute` descendant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
xperiandri
added a commit
that referenced
this pull request
Oct 18, 2026
D8 put an operation category on every test method through `TestCategory (nameof …)`. The test category rules forbid categories written as strings and put the attribute of the examined component on the class (#32), so the categories of the contract and collection tests are the `TestCategories.fs` attributes on the test classes, and test methods carry none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟢 Approval recommended
The documentation-only changes consistently clarify the category rules and have no unresolved findings.
No open issues 🎉
What changed in this PR
Resolves conflicting test-category guidance by making the path-scoped instructions the single source for class-level categories.
Changes:
- Removes method-level category requirements from the general instructions.
- Explicitly requires custom categories derived from
TestCategoryBaseAttribute.
| File | Description |
|---|---|
.github/instructions/test-categories.instructions.md |
Clarifies the required category base type. |
.github/copilot-instructions.md |
Removes conflicting category guidance. |
Review effort: Balanced
Collaborator
Author
|
Folded into
The tree of |
xperiandri
added a commit
that referenced
this pull request
Oct 18, 2026
D8 put an operation category on every test method through `TestCategory (nameof …)`. The test category rules forbid categories written as strings and put the attribute of the examined component on the class (#32), so the categories of the contract and collection tests are the `TestCategories.fs` attributes on the test classes, and test methods carry none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Proposed Changes
The agent instructions contradicted each other on test categories:
.github/copilot-instructions.md, Testing section: asked for an operation category on every test method through[<TestMethod; TestCategory(nameof Queue.enqueue)>], with specialized attributes added next to it on the method..github/instructions/test-categories.instructions.md, path-scoped: forbids a category written as a string in[<TestCategory "...">].nameofproduces such a string. These rules put the attribute of the operation or component that a class examines on the class.Changes:
TestCategoryBaseAttributedescendant.The rule after this change: a test class carries
TestCategoryBaseAttributedescendants for the collection and for the component or area that it examines, such as[<TestClass; FlatListTestCategory; BuilderTestCategory>]. Test methods carry no categories.Types of changes
What types of changes does your code introduce to FSharp.Collections.Immutable?
Put an
xin the boxes that applyAgent instructions only; no code changes.
Checklist
Put an
xin the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.Further comments
The tests on
maincarry no categories yet. The ADR 0001 pull requests (#25 onwards) still putTestCategory (nameof …)on their test methods and check it inTestCategoriesTests. They will follow this rule: categories on the classes only, and the convention test checks the classes.🤖 Generated with Claude Code