diff --git a/claude.md b/claude.md
index cdd57ea14..6c2f12e98 100644
--- a/claude.md
+++ b/claude.md
@@ -211,9 +211,13 @@ Reference existing adapters like `Verify.Xunit/Verifier.cs` or `Verify.NUnit/Ver
### Accepting New Snapshots
-When tests fail, `.received.*` files are created showing actual output. To accept a new snapshot, copy the `.received.*` file to the corresponding `.verified.*` filename.
+When tests fail, `.received.*` files are created showing actual output. To accept a new snapshot, copy the `.received.*` file to the path on the `Verified:` line of the exception message. Do not derive the verified name from the received name — the two are not always the same.
-**Multi-target naming**: When a test project targets multiple frameworks, `.received.` files include a runtime suffix (e.g., `.DotNet11_0.received.txt`) but `.verified.` files do **not** (e.g., `.verified.txt`). When accepting snapshots, strip the runtime suffix from the filename.
+**Multi-target naming**: When a test project targets multiple frameworks (e.g., `Verify.Tests`), the `.received.` file always carries a runtime and version suffix (e.g., `.DotNet11_0.received.txt`). The `.verified.` file carries whatever `UniqueFor*` the test asked for, which may be nothing (`.verified.txt`), the runtime (`.DotNet.verified.txt`), or the same runtime and version (`.DotNet11_0.verified.txt`).
+
+**Single-target naming**: When a test project targets a single framework (e.g., `StaticSettingsTests`), the `.received.` file uses the same uniqueness as its `.verified.` file, including any `UniqueForRuntime`/`UniqueForRuntimeAndVersion` suffix.
+
+**Parameters**: Ignored parameters (`IgnoreParameters`, `IgnoreParametersForVerified`, `IgnoreConstructorParameters`) are kept in the `.received.` name and dropped from the `.verified.` name, regardless of how many frameworks are targeted.
### Debugging Tests
diff --git a/docs/ai-usage.md b/docs/ai-usage.md
index 103a63be0..5d76d824e 100644
--- a/docs/ai-usage.md
+++ b/docs/ai-usage.md
@@ -75,13 +75,14 @@ Verified: TestClass.Method.verified.txt
### Step 3: Determine the action
-- **If the change is expected** (due to an intentional code change): copy the `.received.*` file over the `.verified.*` file to accept the new snapshot.
-- **If it is a new test** (no `.verified.*` file): accept the `.received.*` file as the new snapshot by renaming it to `.verified.*`.
+- **If the change is expected** (due to an intentional code change): copy the `.received.*` file to the `Verified:` path to accept the new snapshot.
+- **If it is a new test** (no `.verified.*` file): accept the `.received.*` file as the new snapshot by copying it to the `Verified:` path.
- **If the change is a bug**: fix the code, not the snapshot. Re-run the test to confirm the fix.
## Rules
- **Never hand-edit `.verified.*` files** to make tests pass. Always let Verify generate the correct output by running the test.
+- **Never derive the verified name from the received name.** The two are not always identical. Multi-targeted projects add a runtime and version suffix to the received file, and ignored parameters are kept in the received name but dropped from the verified name. Always take the destination from the `Verified:` line of the exception message.
- Snapshot files live next to the test source file. For a test in `Tests/MyTests.cs`, look for `Tests/MyTests.MethodName.verified.txt`.
## Scrubbed values
@@ -132,9 +133,10 @@ When a snapshot test fails:
1. Run the failing test and read the `.received.*` file that was generated.
2. Compare it to the corresponding `.verified.*` file.
3. Determine if the difference is expected (due to an intentional code change) or a bug.
- - **If expected**: copy the `.received.*` file over the `.verified.*` file to accept the new snapshot, or delete the `.verified.*` file and rename the `.received.*` file.
+ - **If expected**: copy the `.received.*` file to the `Verified:` path listed in the exception message to accept the new snapshot.
- **If a bug**: fix the code, not the snapshot.
4. Never hand-edit `.verified.*` files to make tests pass. Always let Verify generate the correct output by running the test.
+5. Never derive the verified name from the received name. The two are not always identical. Multi-targeted projects add a runtime and version suffix to the received file, and ignored parameters are kept in the received name but dropped from the verified name. Always take the destination from the `Verified:` line of the exception message.
### Scrubbed values
diff --git a/docs/mdsource/ai-usage.source.md b/docs/mdsource/ai-usage.source.md
index 3d64caf07..b1f7413d3 100644
--- a/docs/mdsource/ai-usage.source.md
+++ b/docs/mdsource/ai-usage.source.md
@@ -68,13 +68,14 @@ Verified: TestClass.Method.verified.txt
### Step 3: Determine the action
-- **If the change is expected** (due to an intentional code change): copy the `.received.*` file over the `.verified.*` file to accept the new snapshot.
-- **If it is a new test** (no `.verified.*` file): accept the `.received.*` file as the new snapshot by renaming it to `.verified.*`.
+- **If the change is expected** (due to an intentional code change): copy the `.received.*` file to the `Verified:` path to accept the new snapshot.
+- **If it is a new test** (no `.verified.*` file): accept the `.received.*` file as the new snapshot by copying it to the `Verified:` path.
- **If the change is a bug**: fix the code, not the snapshot. Re-run the test to confirm the fix.
## Rules
- **Never hand-edit `.verified.*` files** to make tests pass. Always let Verify generate the correct output by running the test.
+- **Never derive the verified name from the received name.** The two are not always identical. Multi-targeted projects add a runtime and version suffix to the received file, and ignored parameters are kept in the received name but dropped from the verified name. Always take the destination from the `Verified:` line of the exception message.
- Snapshot files live next to the test source file. For a test in `Tests/MyTests.cs`, look for `Tests/MyTests.MethodName.verified.txt`.
## Scrubbed values
@@ -125,9 +126,10 @@ When a snapshot test fails:
1. Run the failing test and read the `.received.*` file that was generated.
2. Compare it to the corresponding `.verified.*` file.
3. Determine if the difference is expected (due to an intentional code change) or a bug.
- - **If expected**: copy the `.received.*` file over the `.verified.*` file to accept the new snapshot, or delete the `.verified.*` file and rename the `.received.*` file.
+ - **If expected**: copy the `.received.*` file to the `Verified:` path listed in the exception message to accept the new snapshot.
- **If a bug**: fix the code, not the snapshot.
4. Never hand-edit `.verified.*` files to make tests pass. Always let Verify generate the correct output by running the test.
+5. Never derive the verified name from the received name. The two are not always identical. Multi-targeted projects add a runtime and version suffix to the received file, and ignored parameters are kept in the received name but dropped from the verified name. Always take the destination from the `Verified:` line of the exception message.
### Scrubbed values
diff --git a/docs/mdsource/naming.source.md b/docs/mdsource/naming.source.md
index 43cd3fc85..f1b57df8a 100644
--- a/docs/mdsource/naming.source.md
+++ b/docs/mdsource/naming.source.md
@@ -322,7 +322,19 @@ eg. add the following to `.gitignore`
## Received and multi-targeting
-When a test project uses more than one `TargetFrameworks` (eg `net48;net7.0`) the runtime and version will be always be added as a uniqueness to the received file. This prevents file locking contention when the tests from both target framework run in parallel.
+When a test project uses more than one `TargetFrameworks` (eg `net48;net7.0`) the runtime and version will always be added as a uniqueness to the received file name. This prevents file locking contention when the tests from both target framework run in parallel.
+
+This applies to the default file naming. Under [UseUniqueDirectory](#useuniquedirectory) the received files use the same uniqueness as the verified files.
+
+
+## Received and single-targeting
+
+When a test project uses a single `TargetFramework`, there is no such contention, so the received file uses the same uniqueness as the verified file. With `UniqueForRuntime` both files include the runtime:
+
+```
+TheTest.TheMethod.DotNet.received.txt
+TheTest.TheMethod.DotNet.verified.txt
+```
## Orphaned verified files
diff --git a/docs/naming.md b/docs/naming.md
index 92313bfc1..d865aef3d 100644
--- a/docs/naming.md
+++ b/docs/naming.md
@@ -897,7 +897,19 @@ eg. add the following to `.gitignore`
## Received and multi-targeting
-When a test project uses more than one `TargetFrameworks` (eg `net48;net7.0`) the runtime and version will be always be added as a uniqueness to the received file. This prevents file locking contention when the tests from both target framework run in parallel.
+When a test project uses more than one `TargetFrameworks` (eg `net48;net7.0`) the runtime and version will always be added as a uniqueness to the received file name. This prevents file locking contention when the tests from both target framework run in parallel.
+
+This applies to the default file naming. Under [UseUniqueDirectory](#useuniquedirectory) the received files use the same uniqueness as the verified files.
+
+
+## Received and single-targeting
+
+When a test project uses a single `TargetFramework`, there is no such contention, so the received file uses the same uniqueness as the verified file. With `UniqueForRuntime` both files include the runtime:
+
+```
+TheTest.TheMethod.DotNet.received.txt
+TheTest.TheMethod.DotNet.verified.txt
+```
## Orphaned verified files
diff --git a/src/StaticSettingsTests/SingleTfmTests.cs b/src/StaticSettingsTests/SingleTfmTests.cs
index 93960aec7..cab7d1285 100644
--- a/src/StaticSettingsTests/SingleTfmTests.cs
+++ b/src/StaticSettingsTests/SingleTfmTests.cs
@@ -20,4 +20,58 @@ public async Task Simple()
File.Delete(received);
}
}
+
+ // With a single target framework the received file carries the same uniqueness as the verified
+ // file, so the two names match and tooling can pair a received file with its verified file. When
+ // multiple frameworks are targeted the received file uses the runtime and version instead, which
+ // Verify.Tests covers via DanglingFiles.
+ [Fact]
+ public Task ReceivedUsesRuntime() =>
+ AssertReceivedIsSuffixed(
+ "SingleTfmTests.ReceivedUsesRuntime",
+ Namer.Runtime,
+ _ => _.UniqueForRuntime());
+
+ [Fact]
+ public Task ReceivedUsesRuntimeAndVersion() =>
+ AssertReceivedIsSuffixed(
+ "SingleTfmTests.ReceivedUsesRuntimeAndVersion",
+ Namer.RuntimeAndVersion,
+ _ => _.UniqueForRuntimeAndVersion());
+
+ [Fact]
+ public Task ReceivedUsesRuntimeForFileName() =>
+ AssertReceivedIsSuffixed(
+ "CustomFileName",
+ Namer.Runtime,
+ _ =>
+ {
+ _.UseFileName("CustomFileName");
+ _.UniqueForRuntime();
+ });
+
+ static async Task AssertReceivedIsSuffixed(string prefix, string suffix, Action configure)
+ {
+ var verified = CurrentFile.Relative($"{prefix}.{suffix}.verified.txt");
+ var received = CurrentFile.Relative($"{prefix}.{suffix}.received.txt");
+ var unsuffixed = CurrentFile.Relative($"{prefix}.received.txt");
+ File.Delete(verified);
+ File.Delete(received);
+ File.Delete(unsuffixed);
+ var settings = new VerifySettings();
+ settings.DisableDiff();
+ configure(settings);
+ try
+ {
+ await Assert.ThrowsAsync(() => Verify("value", settings));
+ Assert.True(File.Exists(received));
+ Assert.False(File.Exists(unsuffixed));
+ }
+ finally
+ {
+ File.Delete(verified);
+ File.Delete(received);
+ File.Delete(unsuffixed);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Verify/Verifier/InnerVerifier.cs b/src/Verify/Verifier/InnerVerifier.cs
index 6d089e20c..0ff3d3850 100644
--- a/src/Verify/Verifier/InnerVerifier.cs
+++ b/src/Verify/Verifier/InnerVerifier.cs
@@ -306,22 +306,18 @@ void InitForFileConvention(Namer namer, string typeAndMethod, Action