From 5e5f7aa6ae7044132960849df91b3a8c0bf2d7aa Mon Sep 17 00:00:00 2001 From: Connor <115328188+clindsay94@users.noreply.github.com> Date: Thu, 8 Oct 2026 07:44:27 +0000 Subject: [PATCH] fix(tests): find HostIdentityUnificationTests sources on case-sensitive Linux PairingHandlerResponse_UsesHostIdNotInstanceId and QrBootstrapEndpoint_UsesHostIdNotInstanceId read their source from "Remex.Agent/...", but the project folder is "remex.agent". Windows ignored the case; Linux failed every run with "Could not locate". Anchor the repo root on [CallerFilePath] like the other source-scanning tests and build each path from the on-disk case (git ls-files). No other test shared the capitalised path. Defect-injected HostId -> InstanceId in both pinned spots: both tests went red on Linux, green after revert. No bead: this cloud checkout has no .beads database. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01SgA1bVsAN4GSRo8kFMXHyT --- docs/CHANGELOG.md | 9 ++++++ .../HostIdentityUnificationTests.cs | 32 +++++++++---------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index d6df146bd..e42d6e55c 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -18,6 +18,15 @@ Jump to: [Unreleased](#unreleased) · [3.0.0](#300--2026-10-04) · [2.5.0](#250- on Google Play. If you'd rather use the PC, **Open in browser instead** under the code still opens the listing there. (RemEx-2p7um) +### Internal + +- **`HostIdentityUnificationTests` now runs on Linux.** `PairingHandlerResponse_UsesHostIdNotInstanceId` and + `QrBootstrapEndpoint_UsesHostIdNotInstanceId` read their source from `Remex.Agent/...`, but the project folder is + `remex.agent`. Windows ignored the case, so they passed there and failed every time on Linux (CachyOS, CI, WSL) + with "Could not locate". They now find the repo root through `[CallerFilePath]`, like the other source-scanning + tests, and build each path from the on-disk case. No other test shared the capitalised path. Checked by swapping + `HostId` for `InstanceId` in both pinned places: both tests went red on Linux, and green again once reverted. + ## [3.0.0] — 2026-10-04 **Routines, one look on the PC and the phone, and a new startup splash.** The first release on Google Play diff --git a/remex.agent.tests/HostIdentityUnificationTests.cs b/remex.agent.tests/HostIdentityUnificationTests.cs index b1127347c..ef4518b0a 100644 --- a/remex.agent.tests/HostIdentityUnificationTests.cs +++ b/remex.agent.tests/HostIdentityUnificationTests.cs @@ -1,3 +1,5 @@ +using System.Runtime.CompilerServices; + namespace Remex.Agent.Tests; /// @@ -42,7 +44,7 @@ public void QrBootstrapEndpoint_UsesHostIdNotInstanceId() { // Contract test on the source: the /pairing-qr endpoint must return HostBootstrapper.HostId, // not HostBootstrapper.InstanceId. A regression here re-introduces review-report.md Finding 5. - var bootstrapper = ReadSource("Remex.Agent/HostBootstrapper.cs"); + var bootstrapper = ReadSource("remex.agent", "HostBootstrapper.cs"); var qrBlock = ExtractMapGetBlock(bootstrapper, "/pairing-qr"); Assert.Contains("hostId = HostId", qrBlock); @@ -56,7 +58,7 @@ public void PairingHandlerResponse_UsesHostIdNotInstanceId() // Contract test: the PairingHandler's PairingResponse payload must populate HostId // from HostBootstrapper.HostId (the stable identity), never from InstanceId. The // review report's Finding 5 specifically called out this asymmetry. - var pairingHandler = ReadSource("Remex.Agent/Handlers/PairingHandler.cs"); + var pairingHandler = ReadSource("remex.agent", "Handlers", "PairingHandler.cs"); // Locate the PairingResponse construction and the HostId assignment within it. var idx = pairingHandler.IndexOf("PairingResponse = new PairingResponse", StringComparison.Ordinal); @@ -67,24 +69,20 @@ public void PairingHandlerResponse_UsesHostIdNotInstanceId() Assert.DoesNotContain("HostId = HostBootstrapper.InstanceId", snippet); } - private static string ReadSource(string repoRelativePath) + // Segments are the on-disk case from `git ls-files`: the project folder is `remex.agent`, not + // `Remex.Agent`. Windows forgave the old capitalised path; Linux never found the file. + private static string ReadSource(params string[] repoRelativeSegments) { - // Test runner cwd is the test project's bin directory. Walk up until we find the - // repo root (the directory containing the file path we're asked for). - var dir = new DirectoryInfo(Directory.GetCurrentDirectory()); - while (dir is not null) - { - var candidate = Path.Combine(dir.FullName, repoRelativePath); - if (File.Exists(candidate)) - { - return File.ReadAllText(candidate); - } - dir = dir.Parent; - } - Assert.Fail($"Could not locate {repoRelativePath} starting from {Directory.GetCurrentDirectory()}."); - return string.Empty; // unreachable + var path = Path.Combine([RepoRoot(), .. repoRelativeSegments]); + Assert.True(File.Exists(path), $"Could not locate {path}."); + return File.ReadAllText(path); } + // [CallerFilePath] rather than walking up from the assembly, matching the other source-scanning + // tests, so building with --artifacts-path outside the repo does not break this (RemEx-6i1l). + private static string RepoRoot([CallerFilePath] string thisSourceFile = "") + => Path.GetFullPath(Path.Combine(Path.GetDirectoryName(thisSourceFile)!, "..")); + private static string ExtractMapGetBlock(string source, string route) { var sentinel = $"app.MapGet(\"{route}\"";