diff --git a/src/DiffEngine.Tests/BundledViewerRidTests.cs b/src/DiffEngine.Tests/BundledViewerRidTests.cs
new file mode 100644
index 00000000..6b6efd8b
--- /dev/null
+++ b/src/DiffEngine.Tests/BundledViewerRidTests.cs
@@ -0,0 +1,36 @@
+#if NET10_0
+///
+/// Which RIDs the bundled viewer is probed for.
+///
+/// The framework's own RID comes first, and on Alpine that is linux-musl-x64, which the package
+/// does not ship - so the probe is supposed to miss and the caller falls through to the dotnet
+/// tool. The synthesised linux-{arch} that followed it undid that, because it names the glibc
+/// build, and resolving one against musl hands back an apphost that cannot start.
+///
+///
+public class BundledViewerRidTests
+{
+ [Test]
+ [Arguments("linux-musl-x64")]
+ [Arguments("linux-musl-arm64")]
+ public async Task MuslProbesItsOwnRidAndNothingElse(string runtimeIdentifier)
+ {
+ var rids = BundledViewerDirectory.Rids(runtimeIdentifier).ToList();
+
+ await Assert.That(rids).IsEquivalentTo([runtimeIdentifier]);
+ }
+
+ ///
+ /// Everywhere else the synthesised RID still follows, which is what makes the probe work when
+ /// the framework reports something the package does not ship under that exact name.
+ ///
+ [Test]
+ public async Task GlibcStillFallsBackToTheSynthesisedRid()
+ {
+ var rids = BundledViewerDirectory.Rids("linux-x64").ToList();
+
+ await Assert.That(rids.Count).IsGreaterThan(1);
+ await Assert.That(rids[0]).IsEqualTo("linux-x64");
+ }
+}
+#endif
diff --git a/src/DiffEngine/Viewer/BundledViewerDirectory.cs b/src/DiffEngine/Viewer/BundledViewerDirectory.cs
index 8f108f3e..abda2325 100644
--- a/src/DiffEngine/Viewer/BundledViewerDirectory.cs
+++ b/src/DiffEngine/Viewer/BundledViewerDirectory.cs
@@ -80,13 +80,30 @@ static class BundledViewerDirectory
}
#endif
- static IEnumerable Rids()
- {
+ static IEnumerable Rids() =>
#if NET6_0_OR_GREATER
+ Rids(RuntimeInformation.RuntimeIdentifier);
+
+ internal static IEnumerable Rids(string runtimeIdentifier)
+ {
// The framework's own value first. On Alpine that is linux-musl-x64, a RID we do not
// ship, so the probe misses and the caller falls through to the dotnet tool rather than
// resolving a glibc build against musl.
- yield return RuntimeInformation.RuntimeIdentifier;
+ yield return runtimeIdentifier;
+
+ // And nothing else, or the synthesised RID below undoes that: linux-{arch} is the glibc
+ // build, so on musl the probe would hit after all and hand back an apphost that cannot
+ // start. Falling through to the dotnet tool is the outcome the comment above describes and
+ // was not what happened
+ if (runtimeIdentifier.Contains("-musl-", StringComparison.Ordinal))
+ {
+ yield break;
+ }
+#else
+ InnerRids();
+
+ static IEnumerable InnerRids()
+ {
#endif
var architecture = RuntimeInformation.OSArchitecture switch