From bb60fdfbce9d764ea8b906ea2ebf322ea595e453 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 29 Sep 2026 14:53:44 +0200 Subject: [PATCH] Pin the sink-off report in readHost and the timeout hint, and the a/../b capture path Co-Authored-By: Claude Sonnet 5 --- .../BrokkrCommandCliTests.cs | 28 +++++++++++++++++++ .../BrokkrCommandPolicyTests.cs | 1 + brokkr-contracts.Tests/EditorProbe.cs | 5 +++- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/brokkr-contracts.Tests/BrokkrCommandCliTests.cs b/brokkr-contracts.Tests/BrokkrCommandCliTests.cs index 0d905e7..28ad4f1 100644 --- a/brokkr-contracts.Tests/BrokkrCommandCliTests.cs +++ b/brokkr-contracts.Tests/BrokkrCommandCliTests.cs @@ -130,6 +130,34 @@ public sealed class BrokkrCommandCliTests Assert.False(Directory.Exists(Path.GetDirectoryName(project.StorePath))); } + [Fact] + public async Task ReadHostReportsTheSinkOff() + { + using var project = new ScratchProject(); + using var editor = await EditorProbe.StartAsync(project.StorePath); + editor.AgentCommandsEnabled = false; + await editor.TickAsync(); + + var result = await RunAsync("--unity-cache", project.StorePath, "--action", "readHost"); + + Assert.Equal(0, result.Exit); + Assert.Contains("agent-commands: off", result.Out); + } + + [Fact] + public async Task TimeoutSaysWhenTheEditorReportsTheSinkOff() + { + using var project = new ScratchProject(); + using var editor = await EditorProbe.StartAsync(project.StorePath); + editor.AgentCommandsEnabled = false; + await editor.TickAsync(); + editor.Dispose(); + + var result = await RunAsync("--unity-cache", project.StorePath, "--action", "refreshAssets", "--wait-ms", "600"); + + Assert.Equal(2, result.Exit); + Assert.Contains("agent commands off", result.Error); + } [Fact] public async Task ReadHostShowsWhetherTheSinkIsEnabled() { diff --git a/brokkr-contracts.Tests/BrokkrCommandPolicyTests.cs b/brokkr-contracts.Tests/BrokkrCommandPolicyTests.cs index 8a8de76..fd6a026 100644 --- a/brokkr-contracts.Tests/BrokkrCommandPolicyTests.cs +++ b/brokkr-contracts.Tests/BrokkrCommandPolicyTests.cs @@ -88,6 +88,7 @@ public sealed class BrokkrCommandPolicyTests [InlineData("../../x.png")] [InlineData("..\\x.png")] [InlineData("a/../../x.png")] + [InlineData("a/../b.png")] [InlineData("shot.png:stream")] [InlineData("x.txt")] [InlineData("x.cs")] diff --git a/brokkr-contracts.Tests/EditorProbe.cs b/brokkr-contracts.Tests/EditorProbe.cs index 6e00a78..cde3451 100644 --- a/brokkr-contracts.Tests/EditorProbe.cs +++ b/brokkr-contracts.Tests/EditorProbe.cs @@ -20,6 +20,9 @@ internal sealed class EditorProbe : IDisposable // What the "editor" answers with. Real Unity answers accepted or failed per the executor. internal Func StatusFor { get; set; } = _ => "accepted"; + // What the host snapshot says about the sink; the real editor reports the operator's toggle. + internal bool AgentCommandsEnabled { get; set; } = true; + private EditorProbe(CultMeshNode node) { this.node = node; @@ -59,7 +62,7 @@ internal sealed class EditorProbe : IDisposable await node.Database.PutAsync( new CultRecordKey("unity/host/current"), - new BrokkrHostSnapshot { observedAt = DateTime.UtcNow.ToString("O"), projectPath = "probe", agentCommandsEnabled = true }); + new BrokkrHostSnapshot { observedAt = DateTime.UtcNow.ToString("O"), projectPath = "probe", agentCommandsEnabled = AgentCommandsEnabled }); await node.FlushAsync(soft: true); }