Skip to content

Promote Develop to Main - #464

Closed
ptr727 wants to merge 884 commits into
mainfrom
promote/develop-to-main
Closed

Promote Develop to Main#464
ptr727 wants to merge 884 commits into
mainfrom
promote/develop-to-main

Conversation

@ptr727

@ptr727 ptr727 commented Sep 6, 2026

Copy link
Copy Markdown
Owner

Summary

Promotes develop to main: #463 bumped the
ptr727/ProjectTemplate hub-hosted reusable workflow pins from 2.0.539 to 2.0.560 across
test-pull-request.yml, publish-release.yml, and merge-bot-pull-request.yml. NuGet
packages, dotnet local tools, and third-party Actions were already at their latest versions on
both branches, so no other change is carried.

main had not yet picked up this hub-pin bump on its own (its independent dependabot bumps
since the last promotion, #460/#462,
covered nuget-deps/actions-deps groups only), so this promotion could not fast-forward and used a
promote/develop-to-main branch to resolve the resulting three-file merge conflict.

Verification

  • git diff origin/main origin/develop (whole tree) is exactly the same 6 lines the conflict
    resolution produced; the resulting merge commit's tree (7b43593e) equals
    origin/develop^{tree} exactly, so no content was lost or introduced by the merge.
  • .NET Format clean-compile chain: 0 warnings, 0 pending formatting changes.
  • dotnet test: 212/212 passed.
  • actionlint: clean.
  • Confirmed every changed reusable-workflow callee (validate-task.yml, build-release-task.yml,
    merge-bot-task.yml) keeps its interface compatible with what this repo's callers pass at
    2.0.560; publish-plan-task.yml is byte-identical between the two pins.

🤖 Generated with Claude Code

github-actions Bot and others added 30 commits April 7, 2025 14:59
…ps-985d8ac106

Bump xunit.analyzers from 1.20.0 to 1.21.0 in the nuget-deps group
Bumps the nuget-deps group with 1 update: [xunit.analyzers](https://github.com/xunit/xunit.analyzers).


Updates `xunit.analyzers` from 1.20.0 to 1.21.0
- [Commits](xunit/xunit.analyzers@1.20.0...1.21.0)

---
updated-dependencies:
- dependency-name: xunit.analyzers
  dependency-version: 1.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: nuget-deps
...

Signed-off-by: dependabot[bot] <support@github.com>
…985d8ac106

Bump xunit.analyzers from 1.20.0 to 1.21.0 in the nuget-deps group
Native eol and csharpier
CSharpier after file build
Bumps the nuget-deps group with 1 update: [xunit.runner.visualstudio](https://github.com/xunit/visualstudio.xunit).


Updates `xunit.runner.visualstudio` from 3.0.2 to 3.1.0
- [Release notes](https://github.com/xunit/visualstudio.xunit/releases)
- [Commits](xunit/visualstudio.xunit@3.0.2...3.1.0)

---
updated-dependencies:
- dependency-name: xunit.runner.visualstudio
  dependency-version: 3.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: nuget-deps
...

Signed-off-by: dependabot[bot] <support@github.com>
…ps-cc577801b4

Bump xunit.runner.visualstudio from 3.0.2 to 3.1.0 in the nuget-deps group
Bumps the nuget-deps group with 1 update: [xunit.runner.visualstudio](https://github.com/xunit/visualstudio.xunit).


Updates `xunit.runner.visualstudio` from 3.0.2 to 3.1.0
- [Release notes](https://github.com/xunit/visualstudio.xunit/releases)
- [Commits](xunit/visualstudio.xunit@3.0.2...3.1.0)

---
updated-dependencies:
- dependency-name: xunit.runner.visualstudio
  dependency-version: 3.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: nuget-deps
...

Signed-off-by: dependabot[bot] <support@github.com>
…cc577801b4

Bump xunit.runner.visualstudio from 3.0.2 to 3.1.0 in the nuget-deps group
---
updated-dependencies:
- dependency-name: Serilog
  dependency-version: 4.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: Serilog
  dependency-version: 4.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: Serilog
  dependency-version: 4.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-version: 17.14.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
…ain/Microsoft.NET.Test.Sdk-17.14.0

Update Microsoft.NET.Test.Sdk to 17.14.0
---
updated-dependencies:
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-version: 17.14.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
ptr727 and others added 20 commits August 29, 2026 10:41
## Why

The .NET 10 SDK dropped the VSTest bridge `dotnet test` relied on, so
`dotnet test` failed outright on every PR: `Testing with VSTest target
is no longer supported by Microsoft.Testing.Platform on .NET 10 SDK and
later.` This is what was blocking #443, #444, #445, and #446 (all four
currently fail on the `Run unit tests job`).

## What

- Opt `UtilitiesTests` into native Microsoft.Testing.Platform (MTP):
`global.json`'s `test.runner` setting, plus
`UseMicrosoftTestingPlatformRunner`/`OutputType=Exe` on the test
project, per the [official migration
guide](https://learn.microsoft.com/en-us/dotnet/core/testing/migrating-vstest-microsoft-testing-platform).
- Swap `coverlet.collector` (VSTest-only) for
`Microsoft.Testing.Extensions.CodeCoverage`, the native MTP coverage
provider.
- Bump `Microsoft.NET.Test.Sdk` and the `xunit.v3` family to the
versions that ship a compatible MTP runtime; the prior `xunit.v3` 3.2.2
pairing threw a `TypeLoadException` against the newer platform assembly.
- Update the validate workflow's `dotnet test` invocation (`--coverage`
instead of `--collect`), naming the output file explicitly
(`--coverage-output coverage.cobertura.xml`): the extension's default
GUID basename is not matched by codecov-action's file finder, so the
upload step would otherwise silently find nothing under
`fail_ci_if_error: false`.
- Fix three `ExtensionsTests.cs` null-argument tests that were missing
the null-forgiving operator a sibling test already used;
`TreatWarningsAsErrors` never reached these under the old VSTest error,
which aborted the build before the test project ever compiled.
- Add `global.json` to the Solution Items folder and fix
`Directory.Packages.props`'s alphabetical ordering.

## Verification

Ran locally against .NET 10.0.400: `dotnet build` (0 warnings/errors),
`dotnet test --coverage --coverage-output-format cobertura
--coverage-output coverage.cobertura.xml --results-directory ./coverage`
(183/183 passed, `coverage/coverage.cobertura.xml` produced), `dotnet
csharpier check .`, and `dotnet format style --verify-no-changes` all
clean. Reviewed with a local adversarial pass before pushing (fleet
`local-strict-review`).

## Known trade-off

`Microsoft.Testing.Extensions.CodeCoverage` ships native instrumentation
for `win-x64/x86/arm64`, `linux-x64`, `linux-musl-x64`, and `osx-x64`
only, no `osx-arm64` or `linux-arm64`. CI runs on `ubuntu-latest` (x64)
and is unaffected, but coverage collection won't work locally on Apple
Silicon or Linux arm64 dev machines, where `coverlet.collector` had none
of that restriction. Flagging for awareness rather than blocking on it,
since this is the officially recommended MTP coverage path.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Tests**
* Updated the test runner and testing tools for improved compatibility
and execution.
  * Added consistent Cobertura code coverage reporting.
* Preserved validation of expected compression and decompression errors.

* **Chores**
  * Standardized .NET SDK and test environment configuration.
  * Updated test tooling and coverage integration packages.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Why

Same regression as #447, on `main` this time (per
`.github/dependabot.yml`, `main` and `develop` are kept current
independently). The .NET 10 SDK dropped the VSTest bridge `dotnet test`
relied on, so `dotnet test` failed outright: `Testing with VSTest target
is no longer supported by Microsoft.Testing.Platform on .NET 10 SDK and
later.` This is what was blocking #443 and #444 (both currently fail on
the `Run unit tests job`).

## What

Identical fix to #447, cherry-picked (the relevant files were
byte-identical between `main` and `develop` before this PR):

- Opt `UtilitiesTests` into native Microsoft.Testing.Platform (MTP) via
`global.json`'s `test.runner` setting plus
`UseMicrosoftTestingPlatformRunner`/`OutputType=Exe`.
- Swap `coverlet.collector` (VSTest-only) for
`Microsoft.Testing.Extensions.CodeCoverage` (native MTP coverage),
marked test-only via `PrivateAssets`.
- Bump
`Microsoft.NET.Test.Sdk`/`xunit.v3`/`xunit.analyzers`/`xunit.runner.visualstudio`
to versions with a compatible MTP runtime.
- Update the validate workflow's `dotnet test` invocation (`--coverage`
instead of `--collect`, with an explicit `--coverage-output` filename
codecov-action can discover).
- Fix three `ExtensionsTests.cs` null-argument tests missing a
null-forgiving operator.
- `global.json` in CRLF (this repo's `.editorconfig` convention) and
added to Solution Items.

## Verification

Already went through #447's full review loop (local adversarial review,
Copilot, CodeRabbit, all findings fixed) on identical content.
Re-verified independently on this branch: `dotnet build` (0
warnings/errors), `dotnet test --coverage --coverage-output-format
cobertura --coverage-output coverage.cobertura.xml --results-directory
./coverage` (183/183 passed), `dotnet csharpier check .`, `dotnet format
style --verify-no-changes`, and `editorconfig-checker` on `global.json`
all clean.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Tests**
* Updated automated test execution with a modern test runner for more
reliable validation.
* Added improved code coverage collection and Cobertura report
generation for clearer quality metrics.
  * Updated testing tools and frameworks to newer versions.
* Preserved existing compression test behavior while improving
nullable-value handling during test execution.

* **Chores**
* Added centralized configuration for consistent test tooling across the
solution.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Bumps AwesomeAssertions from 9.5.0 to 9.6.0
Bumps Microsoft.Extensions.Http.Resilience from 10.8.0 to 10.9.0
Bumps Microsoft.Extensions.Logging.Abstractions from 10.0.10 to 10.0.11
Bumps Microsoft.SourceLink.GitHub from 10.0.301 to 10.0.400

---
updated-dependencies:
- dependency-name: AwesomeAssertions
  dependency-version: 9.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: nuget-deps
- dependency-name: Microsoft.Extensions.Http.Resilience
  dependency-version: 10.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: nuget-deps
- dependency-name: Microsoft.Extensions.Logging.Abstractions
  dependency-version: 10.0.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: nuget-deps
- dependency-name: Microsoft.SourceLink.GitHub
  dependency-version: 10.0.400
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: nuget-deps
...

Signed-off-by: dependabot[bot] <support@github.com>
Updated
[AwesomeAssertions](https://github.com/AwesomeAssertions/AwesomeAssertions)
from 9.5.0 to 9.6.0.

<details>
<summary>Release notes</summary>

_Sourced from [AwesomeAssertions's
releases](https://github.com/AwesomeAssertions/AwesomeAssertions/releases)._

## 9.6.0

## What's Changed

### New features
* Enable adding reportables to AssertionScope by @​cbersch in
AwesomeAssertions/AwesomeAssertions#551
* Add option ExcludingObsoleteMembers for structural comparison by
@​lg2de in
AwesomeAssertions/AwesomeAssertions#558

### Fixes
* Fix duplicate matching rules by @​lg2de in
AwesomeAssertions/AwesomeAssertions#566
* Remove obsolete information from FailReason description by @​cbersch
in AwesomeAssertions/AwesomeAssertions#589
* fix: upper and lower case issue by @​aco-mreble in
AwesomeAssertions/AwesomeAssertions#591

### Documentation
* Extend design guidelines for API changes by @​lg2de in
AwesomeAssertions/AwesomeAssertions#547
* Add documentation to all public API by @​lg2de in
AwesomeAssertions/AwesomeAssertions#556

### Others
* Fix build due to vulnerabilities in System.Security.Cryptography.Xml
by @​lg2de in
AwesomeAssertions/AwesomeAssertions#548
* Enable renovate updates for the Build project (Fallout) by @​lg2de in
AwesomeAssertions/AwesomeAssertions#549
* Use ignored temp directory for npm by @​cbersch in
AwesomeAssertions/AwesomeAssertions#554
* Fix navigation link to new assertion scopes doc by @​cbersch in
AwesomeAssertions/AwesomeAssertions#555
* Fixes visibility of some members by @​lg2de in
AwesomeAssertions/AwesomeAssertions#557
* Cleanup Build and Renovate by @​lg2de in
AwesomeAssertions/AwesomeAssertions#564
* Remove obsolete warning suppressions by @​lg2de in
AwesomeAssertions/AwesomeAssertions#608
* Code cleanup on CollectionAssertionSpecs by @​lg2de in
AwesomeAssertions/AwesomeAssertions#609
* Calculate NuGet version only when packaging is enabled by @​lg2de in
AwesomeAssertions/AwesomeAssertions#611

### Dependencies
* Enable automatic upgrade for all build project packages by @​cbersch
in AwesomeAssertions/AwesomeAssertions#550
* Fix verify settings while updating Verify.DiffPlex to 3.3.1 by @​lg2de
in AwesomeAssertions/AwesomeAssertions#586
* Fix test adapter updates by @​cbersch in
AwesomeAssertions/AwesomeAssertions#588
* Fix package updates of MTP by @​lg2de in
AwesomeAssertions/AwesomeAssertions#606
* Upgrade NUnit 4.x and NUnit3TestAdapter 6.x by @​cbersch in
AwesomeAssertions/AwesomeAssertions#587
* Remove obsolete reference to System.Reflection.Metadata by @​lg2de in
AwesomeAssertions/AwesomeAssertions#607
* Update to Fallout 10.4.0 by @​lg2de in
AwesomeAssertions/AwesomeAssertions#594
* Update actions/setup-dotnet action to v6 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#569
* Update dependency LibGit2Sharp to 0.32.0 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#563
* Update dependency Meziantou.Analyzer to 3.0.163 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#612
* Update dependency Microsoft.NET.Test.Sdk to 18.9.0 by @​renovate[bot]
in AwesomeAssertions/AwesomeAssertions#614
* Update dependency Microsoft.Testing.Extensions.CodeCoverage to 18.9.0
by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#583
* Update dependency Microsoft.Testing.Extensions.TrxReport to 2.3.3 by
@​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#577
* Update mstest monorepo to 4.3.3 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#601
* Update dependency Nuget.Packaging to 7.6.0 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#578
* Update dependency Reflectify to 1.10.0 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#615
* Update dependency Roslynator.Analyzers to 4.16.1 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#613
* Update dependency SharpCompress to 0.50.4 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#596
* Update dependency TUnit to 1.63.0 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#579
* Update dependency Verify.XunitV3 to 31.28.0 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#580

## New Contributors
* @​aco-mreble made their first contribution in
AwesomeAssertions/AwesomeAssertions#591
 ... (truncated)

Commits viewable in [compare
view](AwesomeAssertions/AwesomeAssertions@9.5.0...9.6.0).
</details>

Pinned
[Microsoft.Extensions.Http.Resilience](https://github.com/dotnet/extensions)
at 10.9.0.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Extensions.Http.Resilience's
releases](https://github.com/dotnet/extensions/releases)._

## 10.9.0

Version 10.9.0 is headlined by changes in these areas:

* **AI:** New experimental routing APIs center on the abstract
`RoutingChatClient` base class, with `SemanticRoutingChatClient` as a
concrete semantic-routing implementation. Separately, the abstract
`FailoverChatClient` specialization and its concrete
`OrderedFailoverChatClient` implementation add failover routing.
* **AI Evaluation:** The generated report gains redesigned Overview,
Cases, History, and Comparison views.
* **ASP.NET Core and HTTP diagnostics:** The release adds HTTP request
latency log enrichment and fixes configuration binding, response-body
logging, request-path redaction, and resilience package version
handling.
* **Source-generated logging and service discovery:** Fixes cover
classification type qualification, thread-local state cleanup, and DNS
query suffix handling.

## Experimental API Changes

### New Experimental APIs

* New experimental API: HTTP request latency log enrichment
(`EXTEXP0013`) #​7602
* New experimental API: Chat client routing and failover (`MEAI001`)
#​7662

## What's Changed

### AI (`Microsoft.Extensions.AI`,
`Microsoft.Extensions.AI.Abstractions`, and
`Microsoft.Extensions.AI.OpenAI`)

* Add extensible chat client routing #​7662 by @​joshuajyue (co-authored
by @​Copilot)
* Pass the request's options to the selected client #​7685 by
@​joshuajyue (co-authored by @​jozkee @​Copilot)
* AI.Abstractions: fix ExcludeFromSchema dropped under concurrent
AIFunction creation #​7677 by @​jozkee (co-authored by @​Copilot)
* Cap OpenAI dependency version
([b10f9c0](dotnet/extensions@b10f9c0))
by @​jeffhandley (co-authored by @​Copilot)

**Note: Microsoft.Extensions.AI.OpenAI constrains its dependency for
OpenAI to 2.12.x, preventing OpenAI updates to 2.13.0+ due to an
incompatibility. We expect to release Microsoft.Extensions.AI.OpenAI
version 10.9.1 during the week of August 17 to address this issue.**

### HTTP Resilience and Diagnostics
(`Microsoft.Extensions.Http.Resilience` and
`Microsoft.Extensions.Http.Diagnostics`)

* Fix Grpc.Net.ClientFactory version range check - Fixes #​7565 #​7566
by @​Ghost93
* Fix response body logging under debugger #​7678 by @​Rimobul
* Redact outgoing path when route is unknown #​7687 by @​Rimobul
* Fix HTTP client logging config binding #​7691 by @​Rimobul

### ASP.NET Core Extensions
(`Microsoft.AspNetCore.Diagnostics.Middleware`)

* Rename HttpLatencyTelemetry extensions class and drop redundant TFM
guard #​7645 by @​EasyL0ver (co-authored by @​Copilot)
* Add HTTP request latency log enricher (experimental) #​7602 by
@​EasyL0ver (co-authored by @​Copilot)

### Logging Source Generator (`Microsoft.Gen.Logging`)

* [Microsoft.Gen.Logging] Clear thread-local state when logging throws
#​7682 by @​Rimobul
* [Microsoft.Gen.Logging] Fully qualify classification types #​7689 by
@​Rimobul

### AI Evaluation (`Microsoft.Extensions.AI.Evaluation.Reporting`)

* [Microsoft.Extensions.AI.Evaluation.Reporting] Evaluation report
redesign #​7609 by @​grafanaKibana

### Project Templates (`Microsoft.McpServer.ProjectTemplates`)

* Remove MCP server project template #​7680 by @​jeffhandley
(co-authored by @​Copilot)

 ... (truncated)

## 10.8.4

This servicing update refreshes the .NET AI project templates ahead of
the July 30, 2026 retirement of GitHub Models — removing the GitHub
Models provider option and updating template dependencies.

As a result, both the AI Chat Web (`aichatweb`) and AI Agent Web API
(`aiagent-webapi`) templates now **require** the AI service provider to
be chosen explicitly via `--provider`; there is no longer a default. One
of the following must be selected:

- `--provider azureopenai` — Azure OpenAI
- `--provider ollama` — Ollama (for local development)
- `--provider openai` — OpenAI Platform

## Packages in this release

| Package | Version |
|---|---|
| Microsoft.Extensions.AI.Templates | 10.8.4-preview.3.26379.3 |
| Microsoft.Agents.AI.ProjectTemplates | 1.13.0-preview.1.26379.3 |

## What's Changed

### Project templates

- **Removed the GitHub Models provider** from the AI Chat Web and AI
Agent Web API templates, ahead of [GitHub Models being fully retired on
July 30,
2026](https://github.blog/changelog/2026-07-01-github-models-is-being-fully-retired-on-july-30-2026/).
The `--provider` option is now required with no default
([#​7667](dotnet/extensions#7667)).
- Updated AI template dependencies — bumped `Aspire.Hosting.AppHost` to
`13.4.6` and `CommunityToolkit.VectorData.SqliteVec` to
`1.0.0-preview.4` (aligned `System.Linq.AsyncEnumerable` to `10.0.9`),
replacing earlier workaround package pins
([#​7639](dotnet/extensions#7639)).

## Full Changelog

- dotnet/extensions@v10.8.3...v10.8.4


## 10.8.3

## Packages in this release

| Package | Version |
|---|---|
| Microsoft.Extensions.AI | 10.8.3 |
| Microsoft.Extensions.AI.Abstractions | 10.8.3 |
| Microsoft.Extensions.AI.OpenAI | 10.8.3 |

## Experimental API Changes

### Experimental API behavior updates

- Updated serialization behavior for experimental
`ToolApprovalRequestContent.RequiresConfirmation` so it no longer leaks
into consumer source-generated `AIContent` JSON metadata unless approval
APIs are intentionally used
([#​7659](dotnet/extensions#7659)).

## What's Changed

### AI abstractions and serialization

- Fixed MEAI001 leakage from `RequiresConfirmation` in source-generated
`AIContent` contexts by using an internal JSON-included backing member
while keeping the public experimental member ignored for
source-generation metadata
([#​7659](dotnet/extensions#7659)).

## Test Improvements

- Added stabilization regression coverage to verify consumer
source-generated `List<AIContent>` contexts compile and round-trip
without requiring MEAI001 suppression
([#​7659](dotnet/extensions#7659)).

## Full Changelog

- dotnet/extensions@v10.8.2...v10.8.3


## 10.8.2

This servicing release updates
Microsoft.Extensions.VectorData.ConformanceTests to 10.8.2 and includes
targeted test framework migration fixes.

## Packages in this release

| Package | Version | Note |
|---------|---------|---------|
| Microsoft.Extensions.VectorData.Abstractions | 10.8.2 | Published
August 7, 2026 |
| Microsoft.Extensions.VectorData.ConformanceTests | 10.8.2 | |

**Update: August 7, 2026**
The Microsoft.Extensions.VectorData.Abstractions package was initially
excluded from this release by mistake. Because
Microsoft.Extensions.VectorData.ConformanceTests has a dependency on
Microsoft.Extensions.VectorData.Abstractions, that led to failures when
updating to Microsoft.Extensions.VectorData.ConformanceTests 10.8.2.

Microsoft.Extensions.VectorData.Abstractions was published August 7,
2026 to resolve that issue.

## What's Changed

### AI

* Move Microsoft.Extensions.VectorData.ConformanceTests to xUnit 3
#​7636 by @​adamsitnik (co-authored by @​Copilot)

## Acknowledgements

* @​roji reviewed pull requests

**Full Changelog**:
dotnet/extensions@v10.8.1...v10.8.2

## 10.8.1

This servicing release updates the Microsoft.Extensions.AI,
Microsoft.Extensions.AI.Abstractions, and Microsoft.Extensions.AI.OpenAI
packages to 10.8.1 with two targeted fixes: correct
tool-call/tool-result ordering when resuming approval-gated functions
with service-managed chat history, and preservation of the OpenAI
Responses reasoning item id for stateless (store=false) encrypted
reasoning.

## Packages in this release

| Package | Version |
|---------|---------|
| Microsoft.Extensions.AI | 10.8.1 |
| Microsoft.Extensions.AI.Abstractions | 10.8.1 |
| Microsoft.Extensions.AI.OpenAI | 10.8.1 |

## What's Changed

### AI

* Fix FICC tool_calls/tool ordering with approvals and service-managed
chat history #​7617 by @​westey-m
* Roundtrip OpenAI Responses reasoning item id for stateless
(store=false) encrypted reasoning #​7629 by @​rogerbarreto (co-authored
by @​tarekgh)

## Acknowledgements

* @​jozkee reviewed pull requests

**Full Changelog**:
dotnet/extensions@v10.8.0...v10.8.1


Commits viewable in [compare
view](dotnet/extensions@v10.8.0...v10.9.0).
</details>

Pinned
[Microsoft.Extensions.Logging.Abstractions](https://github.com/dotnet/dotnet)
at 10.0.11.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Extensions.Logging.Abstractions's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated [Microsoft.SourceLink.GitHub](https://github.com/dotnet/dotnet)
from 10.0.301 to 10.0.400.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.SourceLink.GitHub's
releases](https://github.com/dotnet/dotnet/releases)._

## 10.0.400

You can build .NET 10.0 from the repository by cloning the release tag
`v10.0.400` and following the build instructions in the [main
README.md](https://github.com/dotnet/dotnet/blob/v10.0.400/README.md#building).

Alternatively, you can build from the sources attached to this release
directly.
More information on this process can be found in the [dotnet/dotnet
repository](https://github.com/dotnet/dotnet/blob/v10.0.400/README.md#building-from-released-sources).

Attached are PGP signatures for the GitHub generated tarball and
zipball. You can find the public key at https://dot.net/release-key-2023

## 10.0.303

You can build .NET 10.0 from the repository by cloning the release tag
`v10.0.303` and following the build instructions in the [main
README.md](https://github.com/dotnet/dotnet/blob/v10.0.303/README.md#building).

Alternatively, you can build from the sources attached to this release
directly.
More information on this process can be found in the [dotnet/dotnet
repository](https://github.com/dotnet/dotnet/blob/v10.0.303/README.md#building-from-released-sources).

Attached are PGP signatures for the GitHub generated tarball and
zipball. You can find the public key at https://dot.net/release-key-2023

## 10.0.302

You can build .NET 10.0 from the repository by cloning the release tag
`v10.0.302` and following the build instructions in the [main
README.md](https://github.com/dotnet/dotnet/blob/v10.0.302/README.md#building).

Alternatively, you can build from the sources attached to this release
directly.
More information on this process can be found in the [dotnet/dotnet
repository](https://github.com/dotnet/dotnet/blob/v10.0.302/README.md#building-from-released-sources).

Attached are PGP signatures for the GitHub generated tarball and
zipball. You can find the public key at https://dot.net/release-key-2023

Commits viewable in [compare
view](dotnet/dotnet@v10.0.301...v10.0.400).
</details>

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Updated
[AwesomeAssertions](https://github.com/AwesomeAssertions/AwesomeAssertions)
from 9.5.0 to 9.6.0.

<details>
<summary>Release notes</summary>

_Sourced from [AwesomeAssertions's
releases](https://github.com/AwesomeAssertions/AwesomeAssertions/releases)._

## 9.6.0

## What's Changed

### New features
* Enable adding reportables to AssertionScope by @​cbersch in
AwesomeAssertions/AwesomeAssertions#551
* Add option ExcludingObsoleteMembers for structural comparison by
@​lg2de in
AwesomeAssertions/AwesomeAssertions#558

### Fixes
* Fix duplicate matching rules by @​lg2de in
AwesomeAssertions/AwesomeAssertions#566
* Remove obsolete information from FailReason description by @​cbersch
in AwesomeAssertions/AwesomeAssertions#589
* fix: upper and lower case issue by @​aco-mreble in
AwesomeAssertions/AwesomeAssertions#591

### Documentation
* Extend design guidelines for API changes by @​lg2de in
AwesomeAssertions/AwesomeAssertions#547
* Add documentation to all public API by @​lg2de in
AwesomeAssertions/AwesomeAssertions#556

### Others
* Fix build due to vulnerabilities in System.Security.Cryptography.Xml
by @​lg2de in
AwesomeAssertions/AwesomeAssertions#548
* Enable renovate updates for the Build project (Fallout) by @​lg2de in
AwesomeAssertions/AwesomeAssertions#549
* Use ignored temp directory for npm by @​cbersch in
AwesomeAssertions/AwesomeAssertions#554
* Fix navigation link to new assertion scopes doc by @​cbersch in
AwesomeAssertions/AwesomeAssertions#555
* Fixes visibility of some members by @​lg2de in
AwesomeAssertions/AwesomeAssertions#557
* Cleanup Build and Renovate by @​lg2de in
AwesomeAssertions/AwesomeAssertions#564
* Remove obsolete warning suppressions by @​lg2de in
AwesomeAssertions/AwesomeAssertions#608
* Code cleanup on CollectionAssertionSpecs by @​lg2de in
AwesomeAssertions/AwesomeAssertions#609
* Calculate NuGet version only when packaging is enabled by @​lg2de in
AwesomeAssertions/AwesomeAssertions#611

### Dependencies
* Enable automatic upgrade for all build project packages by @​cbersch
in AwesomeAssertions/AwesomeAssertions#550
* Fix verify settings while updating Verify.DiffPlex to 3.3.1 by @​lg2de
in AwesomeAssertions/AwesomeAssertions#586
* Fix test adapter updates by @​cbersch in
AwesomeAssertions/AwesomeAssertions#588
* Fix package updates of MTP by @​lg2de in
AwesomeAssertions/AwesomeAssertions#606
* Upgrade NUnit 4.x and NUnit3TestAdapter 6.x by @​cbersch in
AwesomeAssertions/AwesomeAssertions#587
* Remove obsolete reference to System.Reflection.Metadata by @​lg2de in
AwesomeAssertions/AwesomeAssertions#607
* Update to Fallout 10.4.0 by @​lg2de in
AwesomeAssertions/AwesomeAssertions#594
* Update actions/setup-dotnet action to v6 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#569
* Update dependency LibGit2Sharp to 0.32.0 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#563
* Update dependency Meziantou.Analyzer to 3.0.163 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#612
* Update dependency Microsoft.NET.Test.Sdk to 18.9.0 by @​renovate[bot]
in AwesomeAssertions/AwesomeAssertions#614
* Update dependency Microsoft.Testing.Extensions.CodeCoverage to 18.9.0
by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#583
* Update dependency Microsoft.Testing.Extensions.TrxReport to 2.3.3 by
@​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#577
* Update mstest monorepo to 4.3.3 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#601
* Update dependency Nuget.Packaging to 7.6.0 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#578
* Update dependency Reflectify to 1.10.0 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#615
* Update dependency Roslynator.Analyzers to 4.16.1 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#613
* Update dependency SharpCompress to 0.50.4 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#596
* Update dependency TUnit to 1.63.0 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#579
* Update dependency Verify.XunitV3 to 31.28.0 by @​renovate[bot] in
AwesomeAssertions/AwesomeAssertions#580

## New Contributors
* @​aco-mreble made their first contribution in
AwesomeAssertions/AwesomeAssertions#591
 ... (truncated)

Commits viewable in [compare
view](AwesomeAssertions/AwesomeAssertions@9.5.0...9.6.0).
</details>

Pinned
[Microsoft.Extensions.Http.Resilience](https://github.com/dotnet/extensions)
at 10.9.0.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Extensions.Http.Resilience's
releases](https://github.com/dotnet/extensions/releases)._

## 10.9.0

Version 10.9.0 is headlined by changes in these areas:

* **AI:** New experimental routing APIs center on the abstract
`RoutingChatClient` base class, with `SemanticRoutingChatClient` as a
concrete semantic-routing implementation. Separately, the abstract
`FailoverChatClient` specialization and its concrete
`OrderedFailoverChatClient` implementation add failover routing.
* **AI Evaluation:** The generated report gains redesigned Overview,
Cases, History, and Comparison views.
* **ASP.NET Core and HTTP diagnostics:** The release adds HTTP request
latency log enrichment and fixes configuration binding, response-body
logging, request-path redaction, and resilience package version
handling.
* **Source-generated logging and service discovery:** Fixes cover
classification type qualification, thread-local state cleanup, and DNS
query suffix handling.

## Experimental API Changes

### New Experimental APIs

* New experimental API: HTTP request latency log enrichment
(`EXTEXP0013`) #​7602
* New experimental API: Chat client routing and failover (`MEAI001`)
#​7662

## What's Changed

### AI (`Microsoft.Extensions.AI`,
`Microsoft.Extensions.AI.Abstractions`, and
`Microsoft.Extensions.AI.OpenAI`)

* Add extensible chat client routing #​7662 by @​joshuajyue (co-authored
by @​Copilot)
* Pass the request's options to the selected client #​7685 by
@​joshuajyue (co-authored by @​jozkee @​Copilot)
* AI.Abstractions: fix ExcludeFromSchema dropped under concurrent
AIFunction creation #​7677 by @​jozkee (co-authored by @​Copilot)
* Cap OpenAI dependency version
([b10f9c0](dotnet/extensions@b10f9c0))
by @​jeffhandley (co-authored by @​Copilot)

**Note: Microsoft.Extensions.AI.OpenAI constrains its dependency for
OpenAI to 2.12.x, preventing OpenAI updates to 2.13.0+ due to an
incompatibility. We expect to release Microsoft.Extensions.AI.OpenAI
version 10.9.1 during the week of August 17 to address this issue.**

### HTTP Resilience and Diagnostics
(`Microsoft.Extensions.Http.Resilience` and
`Microsoft.Extensions.Http.Diagnostics`)

* Fix Grpc.Net.ClientFactory version range check - Fixes #​7565 #​7566
by @​Ghost93
* Fix response body logging under debugger #​7678 by @​Rimobul
* Redact outgoing path when route is unknown #​7687 by @​Rimobul
* Fix HTTP client logging config binding #​7691 by @​Rimobul

### ASP.NET Core Extensions
(`Microsoft.AspNetCore.Diagnostics.Middleware`)

* Rename HttpLatencyTelemetry extensions class and drop redundant TFM
guard #​7645 by @​EasyL0ver (co-authored by @​Copilot)
* Add HTTP request latency log enricher (experimental) #​7602 by
@​EasyL0ver (co-authored by @​Copilot)

### Logging Source Generator (`Microsoft.Gen.Logging`)

* [Microsoft.Gen.Logging] Clear thread-local state when logging throws
#​7682 by @​Rimobul
* [Microsoft.Gen.Logging] Fully qualify classification types #​7689 by
@​Rimobul

### AI Evaluation (`Microsoft.Extensions.AI.Evaluation.Reporting`)

* [Microsoft.Extensions.AI.Evaluation.Reporting] Evaluation report
redesign #​7609 by @​grafanaKibana

### Project Templates (`Microsoft.McpServer.ProjectTemplates`)

* Remove MCP server project template #​7680 by @​jeffhandley
(co-authored by @​Copilot)

 ... (truncated)

## 10.8.4

This servicing update refreshes the .NET AI project templates ahead of
the July 30, 2026 retirement of GitHub Models — removing the GitHub
Models provider option and updating template dependencies.

As a result, both the AI Chat Web (`aichatweb`) and AI Agent Web API
(`aiagent-webapi`) templates now **require** the AI service provider to
be chosen explicitly via `--provider`; there is no longer a default. One
of the following must be selected:

- `--provider azureopenai` — Azure OpenAI
- `--provider ollama` — Ollama (for local development)
- `--provider openai` — OpenAI Platform

## Packages in this release

| Package | Version |
|---|---|
| Microsoft.Extensions.AI.Templates | 10.8.4-preview.3.26379.3 |
| Microsoft.Agents.AI.ProjectTemplates | 1.13.0-preview.1.26379.3 |

## What's Changed

### Project templates

- **Removed the GitHub Models provider** from the AI Chat Web and AI
Agent Web API templates, ahead of [GitHub Models being fully retired on
July 30,
2026](https://github.blog/changelog/2026-07-01-github-models-is-being-fully-retired-on-july-30-2026/).
The `--provider` option is now required with no default
([#​7667](dotnet/extensions#7667)).
- Updated AI template dependencies — bumped `Aspire.Hosting.AppHost` to
`13.4.6` and `CommunityToolkit.VectorData.SqliteVec` to
`1.0.0-preview.4` (aligned `System.Linq.AsyncEnumerable` to `10.0.9`),
replacing earlier workaround package pins
([#​7639](dotnet/extensions#7639)).

## Full Changelog

- dotnet/extensions@v10.8.3...v10.8.4


## 10.8.3

## Packages in this release

| Package | Version |
|---|---|
| Microsoft.Extensions.AI | 10.8.3 |
| Microsoft.Extensions.AI.Abstractions | 10.8.3 |
| Microsoft.Extensions.AI.OpenAI | 10.8.3 |

## Experimental API Changes

### Experimental API behavior updates

- Updated serialization behavior for experimental
`ToolApprovalRequestContent.RequiresConfirmation` so it no longer leaks
into consumer source-generated `AIContent` JSON metadata unless approval
APIs are intentionally used
([#​7659](dotnet/extensions#7659)).

## What's Changed

### AI abstractions and serialization

- Fixed MEAI001 leakage from `RequiresConfirmation` in source-generated
`AIContent` contexts by using an internal JSON-included backing member
while keeping the public experimental member ignored for
source-generation metadata
([#​7659](dotnet/extensions#7659)).

## Test Improvements

- Added stabilization regression coverage to verify consumer
source-generated `List<AIContent>` contexts compile and round-trip
without requiring MEAI001 suppression
([#​7659](dotnet/extensions#7659)).

## Full Changelog

- dotnet/extensions@v10.8.2...v10.8.3


## 10.8.2

This servicing release updates
Microsoft.Extensions.VectorData.ConformanceTests to 10.8.2 and includes
targeted test framework migration fixes.

## Packages in this release

| Package | Version | Note |
|---------|---------|---------|
| Microsoft.Extensions.VectorData.Abstractions | 10.8.2 | Published
August 7, 2026 |
| Microsoft.Extensions.VectorData.ConformanceTests | 10.8.2 | |

**Update: August 7, 2026**
The Microsoft.Extensions.VectorData.Abstractions package was initially
excluded from this release by mistake. Because
Microsoft.Extensions.VectorData.ConformanceTests has a dependency on
Microsoft.Extensions.VectorData.Abstractions, that led to failures when
updating to Microsoft.Extensions.VectorData.ConformanceTests 10.8.2.

Microsoft.Extensions.VectorData.Abstractions was published August 7,
2026 to resolve that issue.

## What's Changed

### AI

* Move Microsoft.Extensions.VectorData.ConformanceTests to xUnit 3
#​7636 by @​adamsitnik (co-authored by @​Copilot)

## Acknowledgements

* @​roji reviewed pull requests

**Full Changelog**:
dotnet/extensions@v10.8.1...v10.8.2

## 10.8.1

This servicing release updates the Microsoft.Extensions.AI,
Microsoft.Extensions.AI.Abstractions, and Microsoft.Extensions.AI.OpenAI
packages to 10.8.1 with two targeted fixes: correct
tool-call/tool-result ordering when resuming approval-gated functions
with service-managed chat history, and preservation of the OpenAI
Responses reasoning item id for stateless (store=false) encrypted
reasoning.

## Packages in this release

| Package | Version |
|---------|---------|
| Microsoft.Extensions.AI | 10.8.1 |
| Microsoft.Extensions.AI.Abstractions | 10.8.1 |
| Microsoft.Extensions.AI.OpenAI | 10.8.1 |

## What's Changed

### AI

* Fix FICC tool_calls/tool ordering with approvals and service-managed
chat history #​7617 by @​westey-m
* Roundtrip OpenAI Responses reasoning item id for stateless
(store=false) encrypted reasoning #​7629 by @​rogerbarreto (co-authored
by @​tarekgh)

## Acknowledgements

* @​jozkee reviewed pull requests

**Full Changelog**:
dotnet/extensions@v10.8.0...v10.8.1


Commits viewable in [compare
view](dotnet/extensions@v10.8.0...v10.9.0).
</details>

Pinned
[Microsoft.Extensions.Logging.Abstractions](https://github.com/dotnet/dotnet)
at 10.0.11.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Extensions.Logging.Abstractions's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated [Microsoft.SourceLink.GitHub](https://github.com/dotnet/dotnet)
from 10.0.301 to 10.0.400.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.SourceLink.GitHub's
releases](https://github.com/dotnet/dotnet/releases)._

## 10.0.400

You can build .NET 10.0 from the repository by cloning the release tag
`v10.0.400` and following the build instructions in the [main
README.md](https://github.com/dotnet/dotnet/blob/v10.0.400/README.md#building).

Alternatively, you can build from the sources attached to this release
directly.
More information on this process can be found in the [dotnet/dotnet
repository](https://github.com/dotnet/dotnet/blob/v10.0.400/README.md#building-from-released-sources).

Attached are PGP signatures for the GitHub generated tarball and
zipball. You can find the public key at https://dot.net/release-key-2023

## 10.0.303

You can build .NET 10.0 from the repository by cloning the release tag
`v10.0.303` and following the build instructions in the [main
README.md](https://github.com/dotnet/dotnet/blob/v10.0.303/README.md#building).

Alternatively, you can build from the sources attached to this release
directly.
More information on this process can be found in the [dotnet/dotnet
repository](https://github.com/dotnet/dotnet/blob/v10.0.303/README.md#building-from-released-sources).

Attached are PGP signatures for the GitHub generated tarball and
zipball. You can find the public key at https://dot.net/release-key-2023

## 10.0.302

You can build .NET 10.0 from the repository by cloning the release tag
`v10.0.302` and following the build instructions in the [main
README.md](https://github.com/dotnet/dotnet/blob/v10.0.302/README.md#building).

Alternatively, you can build from the sources attached to this release
directly.
More information on this process can be found in the [dotnet/dotnet
repository](https://github.com/dotnet/dotnet/blob/v10.0.302/README.md#building-from-released-sources).

Attached are PGP signatures for the GitHub generated tarball and
zipball. You can find the public key at https://dot.net/release-key-2023

Commits viewable in [compare
view](dotnet/dotnet@v10.0.301...v10.0.400).
</details>

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>
…451)

Brings this repository back into line with the hub, driven from
`RESYNC.md` against a fresh hub checkout. The audit that produced the
findings ran at `audit run 2026-08-30T03:27:29Z | hub a378121` and
reported 45 findings against `main@eb80a36`. Every hub task is pinned at
`f3b4cc9`, release `2.0.526`.

## Line endings are now LF

This is the headline change and the reason nearly every file appears in
the diff. The fleet standard moved to LF, so `.gitattributes` is now `*
text=auto eol=lf` with CRLF kept only for `*.bat` and `*.cmd`, and
`.editorconfig` declares `end_of_line = lf` on `[*]` with the same
single CRLF exception. The two now agree, and git enforces on checkout
what the editor writes, where the old `* -text` default left git out of
it entirely.

The tree was renormalized with `git add --renormalize`, so every tracked
file is LF in both the index and the working tree. Verified against the
hub's own gate:

```text
[ok  ] eol          0 issue(s)
[ok  ] eol-coverage 0 issue(s)  (9 representative paths + 1 tracked shebang path resolved through git check-attr)
```

**Reviewing this diff:** 52 of the 124 changed files carry line-ending
churn and nothing else, and are provably byte-identical with the
carriage returns stripped. `git diff origin/develop --ignore-cr-at-eol`
is the view that drops them.

## Instruction set

`AGENTS.md` is now the hub's three byte-locked sections plus a
repository preamble, with the fleet rule text moved to a new
`GOVERNANCE.md` (the 20 declared sections) and a new `CLAUDE.md`
importing `AGENTS.md`. `CODESTYLE.md`, `WORKFLOW.md` and `AUDIT.md` are
re-vendored, and the `.github/skills/` tree is carried whole with its
digest verified against the hub source.

The `carried-instruction-file-guard` probe found twelve local additions
in the old `AGENTS.md` and `CODESTYLE.md`. None were dropped. Each went
to its declared destination:

| Local content | Destination |
| --- | --- |
| Library public-API and behavioral contracts, project layout | new
`ARCHITECTURE.md` |
| Tooling, linter invocations, release and hook runbooks | new
`OPERATIONS.md` |
| Packable-project, test-runner and analyzer-relaxation rules |
`CODESTYLE.md` "Utilities .NET Conventions" |

## Workflows

All four reusable tasks are now the hub's, reached by pin:
`validate-task`, `publish-plan-task`, `build-release-task` and
`merge-bot-task`. What stays here is the trigger policy, the paths
filter, the per-target wiring, and the ruleset-bound aggregator.
`build-release-task.yml`, `publish-plan-task.yml`, `validate-task.yml`,
`repo-config/` and `spec/secrets.json` are deleted, per their `retire`
dispositions in the hub's `spec/divergences.json`.

Adopting the shared validator was originally deferred, because its
unit-test step ran the VSTest coverage invocation that this repository's
native Microsoft.Testing.Platform suite exits `5` on. Hub #1107 fixed
that in `2.0.526`, and the task's exact command was verified against
this tree before adopting: 183 of 183 pass, and the report lands where
the Codecov finder matches it once prefixed. Both Codecov checks are
green on this pull request, which is the end-to-end proof.

The pull request workflow also gained the `changes` paths filter that
`WORKFLOW.md` D1.1, D1.4 and D1.5 require. Its entries are the
publisher's own shipped-input list, so the smoke gate and the publish
gate agree on what affects the package by construction, and a
documentation-only pull request now skips the smoke build.

## Dependabot

PRs #443 through #446 are stale against this branch: they still carry
`coverlet.collector`, which the Microsoft.Testing.Platform migration
removed, and they conflict. Their content is either already on `develop`
or included here (the cspell action at `v9.0.1`). Dependabot should
reopen cleanly once `develop` and `main` move. Also bumps
`Microsoft.Testing.Extensions.CodeCoverage` to 18.10.0, the one package
with an update available. The dotnet tool manifest is already at the
current CSharpier and Husky.Net.

## Verification

Every gate run locally before each push, plus three
`local-strict-review` passes whose findings are all fixed:

```text
dotnet build                             0 warnings, 0 errors
dotnet csharpier check .                 43 files, clean
dotnet format style --verify-no-changes  clean
dotnet test (MTP + coverage)             183/183 passed
markdownlint-cli2 '**/*.md'              48 files, 0 issues
cspell README.md HISTORY.md              0 issues
actionlint                               clean
editorconfig-checker                     clean
shellcheck + shfmt (.husky/pre-commit)   clean
repo_gate.py                             eol, eol-coverage, sha-pin all clean
prose_lint.py --diff origin/develop      clean
```

## Filed rather than fixed here

- #452, the download tests reaching real network hosts.
Correct, and out of scope for a change that only renormalizes those
files' line endings.
- Three hub-side items, since no hub file is touched by this change: the
carried-content defects this review surfaced, the `WORKFLOW.md` D1.6
wording on how `CODECOV_TOKEN` reaches the validator, and the stale
registry entry for this repository.

Repository settings and rulesets were not applied, since
`repo-config/configure.sh check|apply` is an outward-facing write.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Documentation**
* Added architecture, governance, operations, coding standards, audit,
workflow, and maintenance guidance.
* Improved README navigation, installation, release, contribution, and
support information.
  * Added comprehensive review, testing, and workflow references.

* **Workflow Updates**
* Streamlined pull-request validation, release planning, publishing, and
merge automation.
  * Removed obsolete validation and release workflow components.

* **Consistency**
* Standardized line endings, formatting, linting exclusions, and editor
configuration.
  * Improved project and workspace organization.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Promotes the hub resync. Every conflict resolved to develop's side, which
brings main to develop's tree exactly:

  merged tree  5035943
  develop tree 5035943

Three conflicts were line endings alone, since main added global.json,
UtilitiesTests.csproj and ExtensionsTests.cs as CRLF while develop
renormalized the tree to LF. Each was confirmed content-identical with the
carriage returns stripped before develop's side was taken.

The other two carried nothing main-only. Directory.Packages.props differed
only in the coverage extension, where develop is the newer 18.10.0, and
Utilities.slnx listed a duplicate dependabot entry, a Data folder holding
three files this repository does not have, and the two workflow tasks
develop deleted because the hub now hosts them.
Promotes the hub resync (#451) to `main`.

## Why this is a `promote/` branch rather than `develop` itself

`main` carried its own copies of work `develop` had done independently:
the Microsoft.Testing.Platform migration (#448 against #447) and an
AwesomeAssertions bump (#450 against #449). Combined with the CRLF-to-LF
renormalization, `develop -> main` conflicts on seven paths, and
`develop`'s `required_linear_history` plus its PR ruleset forbid
resolving them on `develop`. This is the documented remedy: resolve on a
throwaway branch off `main`, then open that into `main`.

## The resolution is provably exactly `develop`

Every conflict was resolved to `develop`'s side, and the result is
byte-identical to `develop`'s tree:

```text
merged tree   5035943
develop tree  5035943
```

Each was confirmed lossless before `develop` was taken, per the
documented check:

| Path | Why taking `develop` drops nothing |
| --- | --- |
| `global.json` | Content-identical modulo EOL. `main` added it CRLF,
`develop` renormalized it. |
| `UtilitiesTests/UtilitiesTests.csproj` | Content-identical modulo EOL.
|
| `UtilitiesTests/ExtensionsTests.cs` | Content-identical modulo EOL. |
| `Directory.Packages.props` | Differs in one line, the coverage
extension, where `develop` is the newer 18.10.0 against `main`'s 18.9.0.
|
| `Utilities.slnx` | `main`'s extra entries are a duplicate
`dependabot.yml`, a `Data/` folder naming three files this repository
does not contain, and the two workflow tasks `develop` deleted because
the hub now hosts them. Verified each path is absent on `develop`, and
that `dependabot.yml` is still listed there under GitHub Actions. |
| `.github/workflows/build-release-task.yml` | Deleted on `develop` per
its `retire` disposition. |
| `.github/workflows/validate-task.yml` | Deleted on `develop`, which
now calls the hub-hosted validator by pin. |

## Verification

Run against this branch's tree, not inferred from #451:

```text
dotnet build                             0 warnings, 0 errors
dotnet csharpier check .                 43 files, clean
dotnet format style --verify-no-changes  clean
dotnet test (MTP + coverage)             183/183 passed
markdownlint-cli2 '**/*.md'              48 files, 0 issues
actionlint                               clean
editorconfig-checker                     clean
repo_gate.py                             eol, eol-coverage, sha-pin all clean
prose_lint.py --diff origin/main         clean
```

## Merging

The head is `promote/develop-to-main`, not `develop`, so the
delete-`develop` trap does not apply here. Merge with a merge commit
rather than a squash, per the `main` ruleset.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Added a `StringHistory` utility for retaining and rendering
configurable first and last lines.
- Added comprehensive repository architecture, operations, governance,
and contribution guidance.

- **CI/CD**
- Updated validation, testing, and publishing workflows with clearer
triggers, scoped permissions, and external workflow integration.
  - Removed obsolete release and validation workflow definitions.

- **Documentation**
  - Added coding, testing, review, release, and workflow guidance.

- **Style**
  - Standardized text line endings and formatting across the repository.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Closes #427. Closes #452. Closes #454.

## #454, the `StringHistory` limit properties

`MaxFirstLines` and `MaxLastLines` were each documented `Set to 0 for no
limit`, which holds only when both are zero, the one branch `AppendLine`
treats as unrestricted. Set individually, zero retains none on that
side. The maintainer chose the smaller of the two directions the issue
offered, so the documentation now says what the code does rather than
the code changing to match the documentation.

Three behavioral changes on top of that:

- The constructor and both setters reject a negative value with
`ArgumentOutOfRangeException`, rather than letting it reach `RemoveAt`
and throw after entries have already been taken. The constructor
validates its own parameters, so the exception names `maxFirstLines` or
`maxLastLines` rather than `value`.
- Each setter re-partitions the lines already stored, so a limit
assigned after appending is honored instead of ignored.
- Re-partitioning only ever discards. Once a line has been dropped the
head is closed: it can be trimmed but never refilled, by a later append
or by a later, larger `MaxFirstLines`. What is retained is therefore
always a prefix of the stream followed by a suffix of it, which is
exactly the head-and-tail contract
[`ARCHITECTURE.md`](./ARCHITECTURE.md) states.

That third point is the one worth reviewing closely, and it is the one
two local review passes and a fuzz each found a different defect in
before it settled. A 300000-history fuzz over random append and limit
sequences holds the prefix-plus-suffix contract, the count bound, and
no-duplicates across four and a half million intermediate states.

## #452, the download tests

`DownloadTests` and `DownloadAsyncTests` reached `www.google.com` and
`httpstat.us`, so the unit-test gate depended on outbound DNS and on two
third parties it does not control, and paid a five-second sleep on every
run to exercise the timeout path.

They now drive a loopback HTTP server bound to an ephemeral port.
`Download`'s public surface is unchanged, so the `Lazy<HttpClient>`
contract in `ARCHITECTURE.md` still holds and the seam the issue offered
as the larger alternative was not needed.

- The server writes HTTP/1.1 onto a `TcpListener` socket rather than
using `HttpListener`, which on Windows resolves an explicit-address
prefix through http.sys and needs a URL reservation an unelevated
developer does not have. CI is Linux-only, so nothing here would have
caught that.
- Binding port 0 and reading the port back removes the probe-then-bind
race a first draft had.
- The negative case is a 404 from that server rather than a hostname
expected never to resolve, which a wildcard registration or a
captive-portal resolver would have silently inverted.
- The cancellation test waits for the server to signal that it holds the
request, cancels only then, and asserts the call returned well inside
the route's own delay. Asserting only that the call returned false would
have passed just as well if the server had never started.
- Both not-found tests assert the server actually routed the request,
for the same reason.
- The test assembly disables the ambient proxy. `HttpClientFactory`
leaves `SocketsHttpHandler.UseProxy` at its default, so a client
resolves `HttpClient.DefaultProxy`, which on Unix is read from
`http_proxy` and bypasses loopback only where `no_proxy` says to. A
machine configured that way would send every loopback request to a
proxy, which is the environment dependence this issue exists to remove.

The suite is 200 tests and runs in about one second, against 193 tests
and roughly six seconds before. Twenty consecutive runs were clean.

## #427, the coordination reference

`HISTORY.md` named the template repository in its v3.5 entry. It now
states what changed without naming where it came from.
`.github/copilot-instructions.md`, the other file the issue named, was
already clear, and the hub's own audit reports this repository clean.

A reviewer may read the `HISTORY.md` hunk as an out-of-scope edit to a
shipped release record. It is #427's deliverable rather than incidental
churn.

## Verification

`.NET Format` (CSharpier, build, `dotnet format style
--verify-no-changes`) clean, zero warnings under `AnalysisMode=All` and
`TreatWarningsAsErrors`. markdownlint, CSpell, actionlint,
`editorconfig-checker`, shellcheck and shfmt clean. The hub's prose gate
and repository gate both clean.

## One thing beyond the three issues

`Download.DownloadFile()` and `DownloadFileAsync()` opened the
destination with `File.OpenWrite()`, which is `FileMode.OpenOrCreate`
and does not truncate, so a download over a longer existing file left
that file's trailing bytes after the downloaded content and returned
`true`. A local review pass raised it, and the maintainer asked for it
here rather than as a separate issue.

**The fix changed shape twice before settling, so read the current
behavior here rather than in the commit history.** Both methods now open
the destination with `FileMode.OpenOrCreate` and truncate it with
`SetLength(0)`, rewriting it in place. Its permissions, ownership, and
any hard links or symlinks to it survive, which a probe confirms on
Linux: mode 0600 stays 0600 with the file truncated to the body's
length, a hard link sees the new content, a symlink is written through
rather than replaced, and a read-only destination is refused with the
file intact.

The cost, which the release notes now state rather than leave implicit:
truncation happens once the response headers are accepted, so a download
that fails partway leaves a short file, where `File.OpenWrite()` left
the original bytes behind the newly written ones.

Two approaches were tried and rejected on the way, both by local review
passes:

- `FileMode.Create`, which empties the destination before a single body
byte exists, and which Windows refuses outright against a hidden file
where `OpenOrCreate` succeeds.
- Writing beside the destination and moving the result into place. That
gives the strongest failure guarantee, an untouched destination, but it
replaces the file's identity rather than its contents. Probed on Linux:
a 0600 destination came back 0664, a symlink was replaced by a regular
file leaving its target stale, a hard link kept the old content, and a
read-only destination was silently overwritten, since `rename(2)`
consults the directory's permission and not the file's, while Windows
refuses that same move. The maintainer chose in-place rewriting over
that trade.

Six tests cover it: two for the overwrite, two for a request that fails
before the response is accepted, and two for a destination that cannot
be opened.

## Not in this change

- The failing `Publish project release` run is the NuGet OIDC
`job_workflow_ref` claim,
[ProjectTemplate#1126](ptr727/ProjectTemplate#1126).
The fix moves the token exchange and the push into the calling
repository, so this repository's `publish-release.yml` needs new content
plus a re-pin. That cannot merge usefully until the hub fix reaches its
`main`, so it is a follow-up rather than part of this change.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* `StringHistory` now repartitions retained lines when limits change and
preserves consistent first- and last-line behavior.
* Zero limits support unrestricted retention; negative limits are
rejected.

* **Bug Fixes**
* Downloads correctly replace oversized existing files without leaving
stale content.
* Failed downloads preserve existing files and handle unusable
destinations gracefully.

* **Documentation**
  * Updated architecture, README, and release history documentation.

* **Tests**
* Expanded coverage for history limits, downloads, concurrency,
cancellation, and failure scenarios.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Answers the two findings from the review of the `develop -> main`
promotion, #456. Neither could be pushed there, since that pull
request's head is `develop`, so both land here first and #456 picks them
up.

## `StringHistory.SetLimits()`

Assigning `MaxFirstLines` and `MaxLastLines` one after the other
re-partitions twice, so the first assignment measures against the other
limit's previous value and discards lines the final pair would have
retained. On a default history holding ten lines:

```text
MaxFirstLines = 2; MaxLastLines = 3;   -> 2 lines retained
MaxLastLines = 3; MaxFirstLines = 2;   -> 3 lines retained
SetLimits(2, 3)                        -> 5 lines retained
```

The two-argument constructor was the only way to apply a pair
atomically, and it does not reach an instance that already holds lines.
`SetLimits()` validates both values, assigns both fields, and
re-partitions once.

Worth stating precisely, because the first draft of this change
over-claimed it and a local pass caught it: it is not that no ordering
ever avoids the loss. For a given target pair one order is often
lossless, and an exhaustive sweep of the reachable states found 264
where exactly one is. What holds is that **which** order works depends
on the values and on what is stored, so no fixed ordering is safe.

Six tests: the atomic case, the divergence from separate assignment,
both negative arguments, clearing to the unrestricted mode, and
`Repartition()`'s discarded branch reached through `SetLimits()`, which
caps each side against its own counter rather than against the whole
list.

The 300000-history fuzz now drives `SetLimits()` alongside the two
setters, holding the prefix-plus-suffix contract, the count bound, no
duplicates, and that an assignment never adds a line, across four and a
half million states.

## The grammar finding, and what it turned up

`AOT safe` becomes `AOT-safe` where it modifies a noun. The same
compound sits in `HttpClientFactory` and `AssemblyInfo` doc comments, so
those are corrected rather than left disagreeing with the release note.

Editing those two files brought them under the whole-file rule, which
surfaced three defects none of them on a changed line:

- `ARCHITECTURE.md` said `StringCompression` "passes `leaveOpen` so the
caller keeps ownership of the stream it supplied". Every public member
takes and returns a `string`; the only stream is one the method creates
and disposes itself, so a consumer would look for an overload that does
not exist.
- `AssemblyInfo`'s type summary read "AOT and trim safe", the last
unhyphenated instance in the repository and the copy that ships in the
XML docs.
- `HttpClientFactory`'s retry comment said a 4xx is not retried, three
lines below a bullet that retries 408 and 429.

## Verification

212 tests green. `.NET Format` clean-compile with zero warnings under
`AnalysisMode=All` and `TreatWarningsAsErrors`. markdownlint, CSpell,
`editorconfig-checker`, and both hub gates clean, the prose gate run
over whole files rather than changed lines.

## Not in this change

The `Publish project release` failure is the NuGet OIDC
`job_workflow_ref` claim,
[ProjectTemplate#1126](ptr727/ProjectTemplate#1126),
which needs a caller-side stub change here plus a re-pin once the hub
fix reaches its `main`.
…458)

Restores NuGet publishing, which has been broken since this repository
adopted the hub release chain. This is this repository's half of the hub
fix,
[ProjectTemplate#1126](ptr727/ProjectTemplate#1126),
landed in the hub as `2.0.536`.

## What broke and why

The first real release after adopting the chain, [run
33336000403](https://github.com/ptr727/Utilities/actions/runs/33336000403),
failed at the NuGet.org token exchange:

```text
Token exchange failed (HTTP 401). Claim 'job_workflow_ref' has value
'<owner>/ProjectTemplate/.github/workflows/build-release-task.yml@f3b4cc9'
which does not start with <owner>/Utilities/.github/workflows/.
```

Trusted publishing validates that claim against the repository owning
the package, and the claim names the workflow the job actually ran from.
A push made from a hub-hosted task can never satisfy it, and a caller
hook does not help either, since a composite action runs inside the
hub's job. The hub therefore builds the package and uploads it, and the
calling repository pushes it.

## The change

**The pin and the stub edit are one change, not two.** The hub removed
the `nuget:` input and the `NUGET_USERNAME` secret from the task, so a
pin bump on its own startup-fails against names the task no longer
declares. All six references across three workflows move from `2.0.526`
to `2.0.536`.

I verified that mechanically rather than by reading: every input and
every secret each of the four callers passes is declared on the
corresponding task at `1fe2537`, and no newly-required input is
unpassed.

- `publish` drops the `NUGET_USERNAME` mapping, the `id-token: write`
grant and the `nuget:` input, keeping `enable_nuget` so the task still
builds and uploads the package.
- A new `publish-nuget` job downloads `nuget-build-${{ github.ref_name
}}`, trades the GitHub OIDC token for a short-lived NuGet key, and
pushes. `id-token: write` sits on that one job, which is what D7.2 asks
for.
- The smoke path drops `nuget: false` with them.
- Your nuget.org trusted-publishing policy needs no change: it already
names `ptr727/Utilities` and `publish-release.yml`, so this restores the
match rather than requiring a new policy.

## Carried content, and one local line that survived

`WORKFLOW.md` described the superseded model, that NuGet pushes from the
leaf, on three of the lines this change contradicts. It is carried at
`intent` fidelity, so it is carried forward from the hub rather than
hand-edited.

It is **not** a clean carry, and a blind re-vendor would have destroyed
something. The guard's exact-phrase probe found one line present here
and in **neither** hub revision: D1.6's statement that `CODECOV_TOKEN`
is mapped explicitly under the calling job's own `secrets:` block. Both
hub revisions instead say it reaches the validator via `secrets:
inherit`. The local line is the accurate one here, since both workflows
map the token explicitly, and it is preserved. The file now differs from
the hub by exactly that one line.

A local review pass then caught that carrying `WORKFLOW.md` had left the
carried Skills behind, which is what an agent actually loads at the
moment this matters. `release-publish-mechanics.md` still said "NuGet
pushes from inside the build-nuget hook", and `workflow-ci-contract`
still listed `nuget` as an orchestrator input. An agent bumping the pin
later would have read the pre-fix model and put the push back inside the
leaf, reproducing the exact failure this change fixes. Seven Skill files
carried from `2.0.536`, verified byte-identical afterward, and verified
a byte-clean carry of `2.0.526` beforehand so nothing local was at risk.

## One behavior change worth knowing

Moving the push out of the leaf reorders it after the GitHub release.
`D4.5` still holds for a failed **build**, which skips this job with the
rest. It does not cover a failed **push**: the release is cut inside
`publish` and `publish-nuget` runs after it, so a token-exchange failure
or a nuget.org outage leaves a release and tag for a version that never
reached NuGet.org. Re-running the publisher is the remedy, since the
release-exists gate and `--skip-duplicate` are both idempotent. That
shape comes from the hub's documented stub rather than from anything
chosen here, and the job comment records it.

## Verification, and its limit

actionlint, markdownlint, CSpell, `editorconfig-checker`, and both hub
gates clean. 212 tests green.

**A green pull request proves nothing about this path.** A smoke build
never reaches either push, which is exactly why this class of failure
survived to the first real release. The evidence will be the first
dispatched release after merge, and that run is what should be read
rather than this pull request.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Release Workflow**
* NuGet packages and symbols are now published through a dedicated,
secure release step with trusted authentication.
* Duplicate uploads are handled gracefully, and consumed build artifacts
are cleaned up.
* Release validation now includes clearer safeguards for package,
Docker, and library targets.

* **Documentation**
* Expanded workflow and release guidance covering artifact lifecycles,
publishing, validation, and troubleshooting.
* Clarified `StringHistory` behavior, including limit validation and
unrestricted mode.

* **Maintenance**
* Updated shared automation components to the latest supported release.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Closes #427. Closes #452. Closes #454.

Promotes `develop` at `a16f4b3` to `main`. One squashed pull request,
#455, which closed the three open issues and fixed one defect found
while doing so.

The issue-closing keywords sit here rather than on #455, since GitHub
only closes an issue when the pull request merges into the default
branch, and #455 merged into `develop`.

## What is being promoted

- **#454, the `StringHistory` limit properties.** `MaxFirstLines` and
`MaxLastLines` were each documented `Set to 0 for no limit`, which holds
only when both are zero. Zero on one side is now documented as retaining
no lines on that side, both the constructor and the setters reject a
negative value, and assigning a limit re-partitions the lines already
stored instead of being ignored. Re-partitioning only ever discards, so
what is retained is always a prefix of the appended lines followed by a
suffix of them, and once a line has been dropped the head is trimmed but
never refilled.
- **#452, the download tests.** They reached `www.google.com` and
`httpstat.us`, so the unit-test gate depended on outbound DNS and on two
third parties, and paid a five-second sleep on every run. They now drive
a loopback HTTP server on an ephemeral port, and the test assembly
disables the ambient proxy so a machine with `http_proxy` set does not
send loopback requests through it. `Download`'s public surface is
unchanged.
- **#427, the coordination reference.** `HISTORY.md` named the template
repository in its v3.5 entry and no longer does.
- **A `Download` defect found during the above.** `DownloadFile()` and
`DownloadFileAsync()` opened the destination with `File.OpenWrite()`,
which does not truncate, so a download over a longer existing file left
that file's trailing bytes after the downloaded content and returned
`true`. Both now open with `FileMode.OpenOrCreate` and truncate with
`SetLength(0)`, rewriting in place so the destination's permissions,
ownership, and any links to it survive.
- **The version floor**, raised to 4.1, with the two shipped fixes
recorded in `HISTORY.md` and `README.md`.

## Verification

The merge is clean and `git write-tree` on it equals `git rev-parse
origin/develop^{tree}` exactly (`0cfd271c`), so `main` ends up with
`develop`'s tree and nothing else.

`develop` carried 206 tests green, the `.NET Format` clean-compile chain
with zero warnings under `AnalysisMode=All` and `TreatWarningsAsErrors`,
markdownlint, CSpell, actionlint, `editorconfig-checker`, shellcheck and
shfmt clean, and the hub's prose and repository gates clean. #455 went
through eight review rounds; every thread was resolved and every
suppressed finding answered, with `suppressed on_head=0` at the merge.

## Releases stay blocked, and this does not unblock them

`publish-release.yml` still fails at the NuGet OIDC token exchange,
because the hub-hosted release chain makes the `job_workflow_ref` claim
name the hub rather than this repository
([ProjectTemplate#1126](ptr727/ProjectTemplate#1126)).
The fix moves the token exchange and the push back into the calling
repository, which needs new content in this repository's
`publish-release.yml` plus a re-pin, and cannot land until that hub
change reaches its `main`. That is a follow-up pull request, so merging
this one leaves the latest release at 4.0.38.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Downloads now fully replace existing files, preventing stale or
corrupted trailing content.
* Failed downloads preserve existing destination files and handle
unavailable destinations safely.
* `StringHistory` now validates limits, preserves discarded-content
rules, repartitions stored lines correctly, and supports atomic limit
updates.

* **Documentation**
* Clarified download buffering, truncation, partial-download outcomes,
file options, and `StringHistory` behavior.
  * Updated terminology and retry-behavior documentation.

* **Release**
  * Updated the project version to 4.1.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Bumps Microsoft.Testing.Extensions.CodeCoverage from 18.10.0 to 18.11.0

---
updated-dependencies:
- dependency-name: Microsoft.Testing.Extensions.CodeCoverage
  dependency-version: 18.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: nuget-deps
...

Signed-off-by: dependabot[bot] <support@github.com>
Updated
[Microsoft.Testing.Extensions.CodeCoverage](https://github.com/microsoft/codecoverage)
from 18.10.0 to 18.11.0.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Testing.Extensions.CodeCoverage's
releases](https://github.com/microsoft/codecoverage/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/microsoft/codecoverage/commits).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=Microsoft.Testing.Extensions.CodeCoverage&package-manager=nuget&previous-version=18.10.0&new-version=18.11.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Updated
[Microsoft.Testing.Extensions.CodeCoverage](https://github.com/microsoft/codecoverage)
from 18.10.0 to 18.11.0.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Testing.Extensions.CodeCoverage's
releases](https://github.com/microsoft/codecoverage/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/microsoft/codecoverage/commits).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=Microsoft.Testing.Extensions.CodeCoverage&package-manager=nuget&previous-version=18.10.0&new-version=18.11.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>
Bumps the actions-deps group with 4 updates: [ptr727/ProjectTemplate/.github/workflows/merge-bot-task.yml](https://github.com/ptr727/projecttemplate), [ptr727/ProjectTemplate/.github/workflows/publish-plan-task.yml](https://github.com/ptr727/projecttemplate), [ptr727/ProjectTemplate/.github/workflows/validate-task.yml](https://github.com/ptr727/projecttemplate) and [ptr727/ProjectTemplate/.github/workflows/build-release-task.yml](https://github.com/ptr727/projecttemplate).


Updates `ptr727/ProjectTemplate/.github/workflows/merge-bot-task.yml` from 2.0.536 to 2.0.539
- [Release notes](https://github.com/ptr727/projecttemplate/releases)
- [Changelog](https://github.com/ptr727/ProjectTemplate/blob/main/HISTORY.md)
- [Commits](ptr727/ProjectTemplate@1fe2537...a9afa1d)

Updates `ptr727/ProjectTemplate/.github/workflows/publish-plan-task.yml` from 2.0.536 to 2.0.539
- [Release notes](https://github.com/ptr727/projecttemplate/releases)
- [Changelog](https://github.com/ptr727/ProjectTemplate/blob/main/HISTORY.md)
- [Commits](ptr727/ProjectTemplate@1fe2537...a9afa1d)

Updates `ptr727/ProjectTemplate/.github/workflows/validate-task.yml` from 2.0.536 to 2.0.539
- [Release notes](https://github.com/ptr727/projecttemplate/releases)
- [Changelog](https://github.com/ptr727/ProjectTemplate/blob/main/HISTORY.md)
- [Commits](ptr727/ProjectTemplate@1fe2537...a9afa1d)

Updates `ptr727/ProjectTemplate/.github/workflows/build-release-task.yml` from 2.0.536 to 2.0.539
- [Release notes](https://github.com/ptr727/projecttemplate/releases)
- [Changelog](https://github.com/ptr727/ProjectTemplate/blob/main/HISTORY.md)
- [Commits](ptr727/ProjectTemplate@1fe2537...a9afa1d)

---
updated-dependencies:
- dependency-name: ptr727/ProjectTemplate/.github/workflows/merge-bot-task.yml
  dependency-version: 2.0.539
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions-deps
- dependency-name: ptr727/ProjectTemplate/.github/workflows/publish-plan-task.yml
  dependency-version: 2.0.539
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions-deps
- dependency-name: ptr727/ProjectTemplate/.github/workflows/validate-task.yml
  dependency-version: 2.0.539
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions-deps
- dependency-name: ptr727/ProjectTemplate/.github/workflows/build-release-task.yml
  dependency-version: 2.0.539
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions-deps
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps the actions-deps group with 4 updates:
[ptr727/ProjectTemplate/.github/workflows/merge-bot-task.yml](https://github.com/ptr727/projecttemplate),
[ptr727/ProjectTemplate/.github/workflows/publish-plan-task.yml](https://github.com/ptr727/projecttemplate),
[ptr727/ProjectTemplate/.github/workflows/validate-task.yml](https://github.com/ptr727/projecttemplate)
and
[ptr727/ProjectTemplate/.github/workflows/build-release-task.yml](https://github.com/ptr727/projecttemplate).

Updates `ptr727/ProjectTemplate/.github/workflows/merge-bot-task.yml`
from 2.0.536 to 2.0.539
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ptr727/projecttemplate/releases">ptr727/ProjectTemplate/.github/workflows/merge-bot-task.yml's
releases</a>.</em></p>
<blockquote>
<h2>2.0.539</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix Carried Text a Downstream Repository Cannot Fix in Its Own Copy
by <a href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1157">ptr727/ProjectTemplate#1157</a></li>
<li>Treat an Escaped Backtick as a Literal, Not a Span Delimiter by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1180">ptr727/ProjectTemplate#1180</a></li>
<li>Split Two Sentences That Carried Several Instructions Each by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1181">ptr727/ProjectTemplate#1181</a></li>
<li>Promote develop to main: carried-text fixes a downstream repository
cannot make in its own copy by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1179">ptr727/ProjectTemplate#1179</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/ptr727/ProjectTemplate/compare/2.0.536...2.0.539">https://github.com/ptr727/ProjectTemplate/compare/2.0.536...2.0.539</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/a9afa1d0f56e0160b65baf70ae64a9b6122e8405"><code>a9afa1d</code></a>
Promote develop to main: carried-text fixes a downstream repository
cannot ma...</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/52b0c550ab07ab58b940a353a83247d7451e76e5"><code>52b0c55</code></a>
Split Two Sentences That Carried Several Instructions Each (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1181">#1181</a>)</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/42522c23365390d8a2cee5433c008afcda44465e"><code>42522c2</code></a>
Treat an Escaped Backtick as a Literal, Not a Span Delimiter (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1180">#1180</a>)</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/c58e8056da2402c155271ba2b4ae381a0fee1230"><code>c58e805</code></a>
Fix Carried Text a Downstream Repository Cannot Fix in Its Own Copy (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1157">#1157</a>)</li>
<li>See full diff in <a
href="https://github.com/ptr727/projecttemplate/compare/1fe25376c68bccf6b4581db1568bf325a854dba0...a9afa1d0f56e0160b65baf70ae64a9b6122e8405">compare
view</a></li>
</ul>
</details>
<br />

Updates `ptr727/ProjectTemplate/.github/workflows/publish-plan-task.yml`
from 2.0.536 to 2.0.539
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ptr727/projecttemplate/releases">ptr727/ProjectTemplate/.github/workflows/publish-plan-task.yml's
releases</a>.</em></p>
<blockquote>
<h2>2.0.539</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix Carried Text a Downstream Repository Cannot Fix in Its Own Copy
by <a href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1157">ptr727/ProjectTemplate#1157</a></li>
<li>Treat an Escaped Backtick as a Literal, Not a Span Delimiter by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1180">ptr727/ProjectTemplate#1180</a></li>
<li>Split Two Sentences That Carried Several Instructions Each by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1181">ptr727/ProjectTemplate#1181</a></li>
<li>Promote develop to main: carried-text fixes a downstream repository
cannot make in its own copy by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1179">ptr727/ProjectTemplate#1179</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/ptr727/ProjectTemplate/compare/2.0.536...2.0.539">https://github.com/ptr727/ProjectTemplate/compare/2.0.536...2.0.539</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/a9afa1d0f56e0160b65baf70ae64a9b6122e8405"><code>a9afa1d</code></a>
Promote develop to main: carried-text fixes a downstream repository
cannot ma...</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/52b0c550ab07ab58b940a353a83247d7451e76e5"><code>52b0c55</code></a>
Split Two Sentences That Carried Several Instructions Each (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1181">#1181</a>)</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/42522c23365390d8a2cee5433c008afcda44465e"><code>42522c2</code></a>
Treat an Escaped Backtick as a Literal, Not a Span Delimiter (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1180">#1180</a>)</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/c58e8056da2402c155271ba2b4ae381a0fee1230"><code>c58e805</code></a>
Fix Carried Text a Downstream Repository Cannot Fix in Its Own Copy (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1157">#1157</a>)</li>
<li>See full diff in <a
href="https://github.com/ptr727/projecttemplate/compare/1fe25376c68bccf6b4581db1568bf325a854dba0...a9afa1d0f56e0160b65baf70ae64a9b6122e8405">compare
view</a></li>
</ul>
</details>
<br />

Updates `ptr727/ProjectTemplate/.github/workflows/validate-task.yml`
from 2.0.536 to 2.0.539
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ptr727/projecttemplate/releases">ptr727/ProjectTemplate/.github/workflows/validate-task.yml's
releases</a>.</em></p>
<blockquote>
<h2>2.0.539</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix Carried Text a Downstream Repository Cannot Fix in Its Own Copy
by <a href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1157">ptr727/ProjectTemplate#1157</a></li>
<li>Treat an Escaped Backtick as a Literal, Not a Span Delimiter by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1180">ptr727/ProjectTemplate#1180</a></li>
<li>Split Two Sentences That Carried Several Instructions Each by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1181">ptr727/ProjectTemplate#1181</a></li>
<li>Promote develop to main: carried-text fixes a downstream repository
cannot make in its own copy by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1179">ptr727/ProjectTemplate#1179</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/ptr727/ProjectTemplate/compare/2.0.536...2.0.539">https://github.com/ptr727/ProjectTemplate/compare/2.0.536...2.0.539</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/a9afa1d0f56e0160b65baf70ae64a9b6122e8405"><code>a9afa1d</code></a>
Promote develop to main: carried-text fixes a downstream repository
cannot ma...</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/52b0c550ab07ab58b940a353a83247d7451e76e5"><code>52b0c55</code></a>
Split Two Sentences That Carried Several Instructions Each (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1181">#1181</a>)</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/42522c23365390d8a2cee5433c008afcda44465e"><code>42522c2</code></a>
Treat an Escaped Backtick as a Literal, Not a Span Delimiter (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1180">#1180</a>)</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/c58e8056da2402c155271ba2b4ae381a0fee1230"><code>c58e805</code></a>
Fix Carried Text a Downstream Repository Cannot Fix in Its Own Copy (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1157">#1157</a>)</li>
<li>See full diff in <a
href="https://github.com/ptr727/projecttemplate/compare/1fe25376c68bccf6b4581db1568bf325a854dba0...a9afa1d0f56e0160b65baf70ae64a9b6122e8405">compare
view</a></li>
</ul>
</details>
<br />

Updates
`ptr727/ProjectTemplate/.github/workflows/build-release-task.yml` from
2.0.536 to 2.0.539
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ptr727/projecttemplate/releases">ptr727/ProjectTemplate/.github/workflows/build-release-task.yml's
releases</a>.</em></p>
<blockquote>
<h2>2.0.539</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix Carried Text a Downstream Repository Cannot Fix in Its Own Copy
by <a href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1157">ptr727/ProjectTemplate#1157</a></li>
<li>Treat an Escaped Backtick as a Literal, Not a Span Delimiter by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1180">ptr727/ProjectTemplate#1180</a></li>
<li>Split Two Sentences That Carried Several Instructions Each by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1181">ptr727/ProjectTemplate#1181</a></li>
<li>Promote develop to main: carried-text fixes a downstream repository
cannot make in its own copy by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1179">ptr727/ProjectTemplate#1179</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/ptr727/ProjectTemplate/compare/2.0.536...2.0.539">https://github.com/ptr727/ProjectTemplate/compare/2.0.536...2.0.539</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/a9afa1d0f56e0160b65baf70ae64a9b6122e8405"><code>a9afa1d</code></a>
Promote develop to main: carried-text fixes a downstream repository
cannot ma...</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/52b0c550ab07ab58b940a353a83247d7451e76e5"><code>52b0c55</code></a>
Split Two Sentences That Carried Several Instructions Each (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1181">#1181</a>)</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/42522c23365390d8a2cee5433c008afcda44465e"><code>42522c2</code></a>
Treat an Escaped Backtick as a Literal, Not a Span Delimiter (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1180">#1180</a>)</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/c58e8056da2402c155271ba2b4ae381a0fee1230"><code>c58e805</code></a>
Fix Carried Text a Downstream Repository Cannot Fix in Its Own Copy (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1157">#1157</a>)</li>
<li>See full diff in <a
href="https://github.com/ptr727/projecttemplate/compare/1fe25376c68bccf6b4581db1568bf325a854dba0...a9afa1d0f56e0160b65baf70ae64a9b6122e8405">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the actions-deps group with 4 updates:
[ptr727/ProjectTemplate/.github/workflows/merge-bot-task.yml](https://github.com/ptr727/projecttemplate),
[ptr727/ProjectTemplate/.github/workflows/publish-plan-task.yml](https://github.com/ptr727/projecttemplate),
[ptr727/ProjectTemplate/.github/workflows/validate-task.yml](https://github.com/ptr727/projecttemplate)
and
[ptr727/ProjectTemplate/.github/workflows/build-release-task.yml](https://github.com/ptr727/projecttemplate).

Updates `ptr727/ProjectTemplate/.github/workflows/merge-bot-task.yml`
from 2.0.536 to 2.0.539
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ptr727/projecttemplate/releases">ptr727/ProjectTemplate/.github/workflows/merge-bot-task.yml's
releases</a>.</em></p>
<blockquote>
<h2>2.0.539</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix Carried Text a Downstream Repository Cannot Fix in Its Own Copy
by <a href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1157">ptr727/ProjectTemplate#1157</a></li>
<li>Treat an Escaped Backtick as a Literal, Not a Span Delimiter by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1180">ptr727/ProjectTemplate#1180</a></li>
<li>Split Two Sentences That Carried Several Instructions Each by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1181">ptr727/ProjectTemplate#1181</a></li>
<li>Promote develop to main: carried-text fixes a downstream repository
cannot make in its own copy by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1179">ptr727/ProjectTemplate#1179</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/ptr727/ProjectTemplate/compare/2.0.536...2.0.539">https://github.com/ptr727/ProjectTemplate/compare/2.0.536...2.0.539</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/a9afa1d0f56e0160b65baf70ae64a9b6122e8405"><code>a9afa1d</code></a>
Promote develop to main: carried-text fixes a downstream repository
cannot ma...</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/52b0c550ab07ab58b940a353a83247d7451e76e5"><code>52b0c55</code></a>
Split Two Sentences That Carried Several Instructions Each (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1181">#1181</a>)</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/42522c23365390d8a2cee5433c008afcda44465e"><code>42522c2</code></a>
Treat an Escaped Backtick as a Literal, Not a Span Delimiter (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1180">#1180</a>)</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/c58e8056da2402c155271ba2b4ae381a0fee1230"><code>c58e805</code></a>
Fix Carried Text a Downstream Repository Cannot Fix in Its Own Copy (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1157">#1157</a>)</li>
<li>See full diff in <a
href="https://github.com/ptr727/projecttemplate/compare/1fe25376c68bccf6b4581db1568bf325a854dba0...a9afa1d0f56e0160b65baf70ae64a9b6122e8405">compare
view</a></li>
</ul>
</details>
<br />

Updates `ptr727/ProjectTemplate/.github/workflows/publish-plan-task.yml`
from 2.0.536 to 2.0.539
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ptr727/projecttemplate/releases">ptr727/ProjectTemplate/.github/workflows/publish-plan-task.yml's
releases</a>.</em></p>
<blockquote>
<h2>2.0.539</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix Carried Text a Downstream Repository Cannot Fix in Its Own Copy
by <a href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1157">ptr727/ProjectTemplate#1157</a></li>
<li>Treat an Escaped Backtick as a Literal, Not a Span Delimiter by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1180">ptr727/ProjectTemplate#1180</a></li>
<li>Split Two Sentences That Carried Several Instructions Each by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1181">ptr727/ProjectTemplate#1181</a></li>
<li>Promote develop to main: carried-text fixes a downstream repository
cannot make in its own copy by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1179">ptr727/ProjectTemplate#1179</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/ptr727/ProjectTemplate/compare/2.0.536...2.0.539">https://github.com/ptr727/ProjectTemplate/compare/2.0.536...2.0.539</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/a9afa1d0f56e0160b65baf70ae64a9b6122e8405"><code>a9afa1d</code></a>
Promote develop to main: carried-text fixes a downstream repository
cannot ma...</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/52b0c550ab07ab58b940a353a83247d7451e76e5"><code>52b0c55</code></a>
Split Two Sentences That Carried Several Instructions Each (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1181">#1181</a>)</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/42522c23365390d8a2cee5433c008afcda44465e"><code>42522c2</code></a>
Treat an Escaped Backtick as a Literal, Not a Span Delimiter (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1180">#1180</a>)</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/c58e8056da2402c155271ba2b4ae381a0fee1230"><code>c58e805</code></a>
Fix Carried Text a Downstream Repository Cannot Fix in Its Own Copy (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1157">#1157</a>)</li>
<li>See full diff in <a
href="https://github.com/ptr727/projecttemplate/compare/1fe25376c68bccf6b4581db1568bf325a854dba0...a9afa1d0f56e0160b65baf70ae64a9b6122e8405">compare
view</a></li>
</ul>
</details>
<br />

Updates `ptr727/ProjectTemplate/.github/workflows/validate-task.yml`
from 2.0.536 to 2.0.539
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ptr727/projecttemplate/releases">ptr727/ProjectTemplate/.github/workflows/validate-task.yml's
releases</a>.</em></p>
<blockquote>
<h2>2.0.539</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix Carried Text a Downstream Repository Cannot Fix in Its Own Copy
by <a href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1157">ptr727/ProjectTemplate#1157</a></li>
<li>Treat an Escaped Backtick as a Literal, Not a Span Delimiter by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1180">ptr727/ProjectTemplate#1180</a></li>
<li>Split Two Sentences That Carried Several Instructions Each by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1181">ptr727/ProjectTemplate#1181</a></li>
<li>Promote develop to main: carried-text fixes a downstream repository
cannot make in its own copy by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1179">ptr727/ProjectTemplate#1179</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/ptr727/ProjectTemplate/compare/2.0.536...2.0.539">https://github.com/ptr727/ProjectTemplate/compare/2.0.536...2.0.539</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/a9afa1d0f56e0160b65baf70ae64a9b6122e8405"><code>a9afa1d</code></a>
Promote develop to main: carried-text fixes a downstream repository
cannot ma...</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/52b0c550ab07ab58b940a353a83247d7451e76e5"><code>52b0c55</code></a>
Split Two Sentences That Carried Several Instructions Each (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1181">#1181</a>)</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/42522c23365390d8a2cee5433c008afcda44465e"><code>42522c2</code></a>
Treat an Escaped Backtick as a Literal, Not a Span Delimiter (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1180">#1180</a>)</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/c58e8056da2402c155271ba2b4ae381a0fee1230"><code>c58e805</code></a>
Fix Carried Text a Downstream Repository Cannot Fix in Its Own Copy (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1157">#1157</a>)</li>
<li>See full diff in <a
href="https://github.com/ptr727/projecttemplate/compare/1fe25376c68bccf6b4581db1568bf325a854dba0...a9afa1d0f56e0160b65baf70ae64a9b6122e8405">compare
view</a></li>
</ul>
</details>
<br />

Updates
`ptr727/ProjectTemplate/.github/workflows/build-release-task.yml` from
2.0.536 to 2.0.539
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ptr727/projecttemplate/releases">ptr727/ProjectTemplate/.github/workflows/build-release-task.yml's
releases</a>.</em></p>
<blockquote>
<h2>2.0.539</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix Carried Text a Downstream Repository Cannot Fix in Its Own Copy
by <a href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1157">ptr727/ProjectTemplate#1157</a></li>
<li>Treat an Escaped Backtick as a Literal, Not a Span Delimiter by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1180">ptr727/ProjectTemplate#1180</a></li>
<li>Split Two Sentences That Carried Several Instructions Each by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1181">ptr727/ProjectTemplate#1181</a></li>
<li>Promote develop to main: carried-text fixes a downstream repository
cannot make in its own copy by <a
href="https://github.com/ptr727"><code>@​ptr727</code></a> in <a
href="https://redirect.github.com/ptr727/ProjectTemplate/pull/1179">ptr727/ProjectTemplate#1179</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/ptr727/ProjectTemplate/compare/2.0.536...2.0.539">https://github.com/ptr727/ProjectTemplate/compare/2.0.536...2.0.539</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/a9afa1d0f56e0160b65baf70ae64a9b6122e8405"><code>a9afa1d</code></a>
Promote develop to main: carried-text fixes a downstream repository
cannot ma...</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/52b0c550ab07ab58b940a353a83247d7451e76e5"><code>52b0c55</code></a>
Split Two Sentences That Carried Several Instructions Each (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1181">#1181</a>)</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/42522c23365390d8a2cee5433c008afcda44465e"><code>42522c2</code></a>
Treat an Escaped Backtick as a Literal, Not a Span Delimiter (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1180">#1180</a>)</li>
<li><a
href="https://github.com/ptr727/ProjectTemplate/commit/c58e8056da2402c155271ba2b4ae381a0fee1230"><code>c58e805</code></a>
Fix Carried Text a Downstream Repository Cannot Fix in Its Own Copy (<a
href="https://redirect.github.com/ptr727/projecttemplate/issues/1157">#1157</a>)</li>
<li>See full diff in <a
href="https://github.com/ptr727/projecttemplate/compare/1fe25376c68bccf6b4581db1568bf325a854dba0...a9afa1d0f56e0160b65baf70ae64a9b6122e8405">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>
## Summary

Routine dependency sweep: checked NuGet packages, local dotnet tools,
and pinned GitHub Actions
for updates.

- **NuGet packages** (`Directory.Packages.props`): all 12 already at
their latest stable version.
  No change.
- **Local dotnet tools** (`.config/dotnet-tools.json`, csharpier/husky):
both already at their
  latest version. No change.
- **Third-party Actions** (`actions/checkout`,
`actions/download-artifact`,
`actions/setup-dotnet`, `dorny/paths-filter`, `NuGet/login`): all
already pinned to their
  latest release SHA. No change.
- **Hub-hosted reusable workflow pins** (`ptr727/ProjectTemplate`):
bumped from 2.0.539 to
2.0.560 across all six references in `test-pull-request.yml`,
`publish-release.yml`, and
  `merge-bot-pull-request.yml`.

## Verification

- `actionlint` (Docker `rhysd/actionlint:latest`): clean.
- `.NET Format` clean-compile chain (CSharpier, build, `dotnet format
style
  --verify-no-changes`): 0 warnings, 0 pending formatting changes.
- `dotnet test`: 212/212 passed.
- Confirmed the new pin (`d6a4d7e1cc0f5ed8477e01cebe717b7ae3fabd58`)
resolves to hub tag
`2.0.560`, and that the hub's
`build-release-task.yml`/`validate-task.yml`/
`publish-plan-task.yml`/`merge-bot-task.yml` interfaces are unchanged
between 2.0.539 and
  2.0.560 for the inputs this repo's callers actually pass.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
# Conflicts:
#	.github/workflows/merge-bot-pull-request.yml
#	.github/workflows/publish-release.yml
#	.github/workflows/test-pull-request.yml
Copilot AI lite review requested due to automatic review settings September 6, 2026 15:23
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@coderabbitai

coderabbitai Bot commented Sep 6, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Team

Run ID: 59510d1a-59c3-4b3f-b166-dc9fd979b6eb


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Sep 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 70.54%. Comparing base (093d4a1) to head (f09878a).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #464   +/-   ##
=======================================
  Coverage   70.54%   70.54%           
=======================================
  Files          13       13           
  Lines        1219     1219           
  Branches      111      111           
=======================================
  Hits          860      860           
  Misses        319      319           
  Partials       40       40           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The change is limited to updating reusable-workflow SHA pins (with matching version comments) across three workflows, with no remaining references to the prior pin.

Pull request overview

This PR promotes develop to main by updating this repo’s reusable workflow pins to the ptr727/ProjectTemplate hub release 2.0.560, aligning main with the already-merged workflow pin bump on develop.

Changes:

  • Bump validate-task.yml and build-release-task.yml pins in the PR workflow to 2.0.560.
  • Bump publish-plan-task.yml, validate-task.yml, and build-release-task.yml pins in the release publisher workflow to 2.0.560.
  • Bump merge-bot-task.yml pin in the merge-bot PR workflow to 2.0.560.
File summaries
File Description
.github/workflows/test-pull-request.yml Updates hub reusable workflow pins used by PR validation and smoke build.
.github/workflows/publish-release.yml Updates hub reusable workflow pins used by release planning, validation, and build/release.
.github/workflows/merge-bot-pull-request.yml Updates hub reusable workflow pin used by the merge-bot caller workflow.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@ptr727 ptr727 closed this Sep 6, 2026
@ptr727 ptr727 mentioned this pull request Sep 6, 2026
ptr727 added a commit that referenced this pull request Sep 6, 2026
## Summary

Promotes `develop` to `main`:
[#463](#463) bumped the
`ptr727/ProjectTemplate` hub-hosted reusable workflow pins from 2.0.539
to 2.0.560 across
`test-pull-request.yml`, `publish-release.yml`, and
`merge-bot-pull-request.yml`. NuGet
packages, dotnet local tools, and third-party Actions were already at
their latest versions on
both branches, so no other change is carried.

`main` had not yet picked up this hub-pin bump on its own (its
independent dependabot bumps
since the last promotion,
[#460](https://github.com/ptr727/Utilities/pull/460)/[#462](https://github.com/ptr727/Utilities/pull/462),
covered nuget-deps/actions-deps groups only), so this promotion could
not fast-forward and used a
`promote/develop-to-main` branch to resolve the resulting three-file
merge conflict.

## Supersedes #464

[#464](#464) carried this same
promotion and was
auto-closed by GitHub when `main` was force-pushed during the
commit-signature remediation
described below: its timeline records `base_ref_force_pushed` and
`closed` at the same
timestamp. Its recorded head commit is no longer reachable from the
branch, so GitHub refuses to
reopen it, and this pull request replaces it. The promoted content is
unchanged.

## Every commit was re-signed

All history on `main`, `develop`, and this branch was rewritten to
restore commit signatures.
Background: an earlier identity rewrite (removing a stale
`pieter_viljoen@symantec.com` author
identity from 27 commits dating to 2018-2019) shifted the parent chain
of every descendant
commit, and `git filter-repo` drops the now-stale `gpgsig` field from
every commit it rewrites.
That silently left the entire mainline unsigned, which is what blocked
#464 under
`Commits must have verified signatures`.

The remediation re-signed all 884 commits with the maintainer's SSH key.
Because GitHub matches a
signing key against the **committer** identity, the committer on every
commit is now
`Pieter Viljoen <ptr727@users.noreply.github.com>`. Commit **authors**
are preserved unchanged,
including `dependabot[bot]`, `Copilot`, `github-actions[bot]`, and
`ptr727-codegen[bot]`, as are
the original author and committer dates.

## Verification

- This branch's tree is unchanged by the re-sign: the merge commit's
tree is `7b43593e`, which
equals `origin/develop^{tree}` exactly, so no content was lost or
introduced.
- Commit counts match pre-rewrite exactly: `main` 880, `develop` 807,
this branch 884.
- GitHub reports every commit as verified: 880/880 on `main`, 807/807 on
`develop`, and 884/884
  on this branch.
- This branch's tip is a clean two-parent merge of the current `main`
and `develop` tips.
- The content-level verification of the promoted change (clean-compile
chain with 0 warnings,
212/212 tests, `actionlint` clean, and the reusable-workflow interface
compatibility check
across the 2.0.539 to 2.0.560 pin bump) was performed on #464 against a
tree byte-identical to
  this one.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants