Skip to content

Commit 3860872

Browse files
committed
tests and fixes
1 parent b23194b commit 3860872

26 files changed

+121
-33
lines changed

AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,15 @@ For this app:
143143
- the repo-root lowercase `.editorconfig` is the source of truth for formatting, naming, style, and analyzer severity
144144
- local and CI build commands must pass `-warnaserror`; warnings are not an acceptable "green" build state in this repository
145145
- do not run parallel `dotnet` or `MSBuild` work that shares the same checkout, target outputs, or NuGet package cache; the multi-target Uno app must build serially in CI to avoid `Uno.Resizetizer` file-lock failures
146+
- do not commit user-specific local paths, usernames, or machine-specific identifiers in tests, docs, snapshots, or fixtures; use neutral synthetic values so the repo stays portable and does not leak personal machine details
146147
- quality gates should prefer analyzer-backed build failures over separate one-off CI tools; for overloaded methods and maintainability drift, enable build-time analyzers such as `CA1502` instead of adding a formatting-only gate
147148
- `Directory.Build.props` owns the shared analyzer and warning policy for future projects
148149
- `Directory.Packages.props` owns centrally managed package versions
149150
- `global.json` pins the .NET SDK and Uno SDK version used by the app and tests
150151
- `DotPilot/DotPilot.csproj` keeps `GenerateDocumentationFile=true` with `CS1591` suppressed so `IDE0005` stays enforceable in CI across all target frameworks without inventing command-line-only build flags
151152
- architecture work must keep a vertical-slice shape: each feature owns its contracts, orchestration, and tests behind clear boundaries instead of growing a shared horizontal service layer
152153
- keep the Uno app project presentation-only; domain, runtime host, orchestration, integrations, and persistence code must live in separate class-library projects so UI composition does not mix with feature implementation
154+
- structure both `DotPilot.Tests` and `DotPilot.UITests` by vertical slice and explicit harness boundaries; do not keep test files in one flat project-root pile
153155
- GitHub Actions workflows must use descriptive names and filenames that reflect their purpose; do not use a generic `ci.yml` catch-all because build validation and release automation are separate operator flows
154156
- GitHub Actions must be split into at least one validation workflow for normal builds/tests and one release workflow for CI-driven version resolution, release-note generation, desktop publishing, and GitHub Release publication
155157
- meaningful GitHub review comments must be evaluated and fixed when they still apply even if the original PR was closed; closed review threads are not a reason to ignore valid engineering feedback

DotPilot.Runtime/Features/RuntimeFoundation/DeterministicAgentRuntimeClient.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Diagnostics;
12
using DotPilot.Core.Features.ControlPlaneDomain;
23
using DotPilot.Core.Features.RuntimeCommunication;
34
using DotPilot.Core.Features.RuntimeFoundation;
@@ -8,7 +9,6 @@ namespace DotPilot.Runtime.Features.RuntimeFoundation;
89
public sealed class DeterministicAgentRuntimeClient : IAgentRuntimeClient
910
{
1011
private const string ApprovalKeyword = "approval";
11-
private const string DeterministicProviderDisplayName = "Deterministic Runtime Client";
1212
private const string PlanSummary =
1313
"Planned the runtime foundation flow with contracts first, then communication, host lifecycle, and orchestration.";
1414
private const string ExecuteSummary =
@@ -35,7 +35,7 @@ public ValueTask<Result<AgentTurnResult>> ExecuteAsync(AgentTurnRequest request,
3535
Result<AgentTurnResult>.Fail(
3636
RuntimeCommunicationProblems.ProviderUnavailable(
3737
request.ProviderStatus,
38-
DeterministicProviderDisplayName)));
38+
ProviderToolchainNames.DeterministicClientDisplayName)));
3939
}
4040

4141
return ValueTask.FromResult(request.Mode switch
@@ -64,7 +64,7 @@ AgentExecutionMode.Execute when RequiresApproval(request.Prompt) => Result<Agent
6464
SessionPhase.Review,
6565
ApprovalState.Approved,
6666
[CreateArtifact(request.SessionId, ReviewArtifact, ArtifactKind.Report)])),
67-
_ => Result<AgentTurnResult>.Fail(RuntimeCommunicationProblems.OrchestrationUnavailable()),
67+
_ => throw new UnreachableException(),
6868
});
6969
}
7070

@@ -77,12 +77,12 @@ private static ArtifactDescriptor CreateArtifact(SessionId sessionId, string art
7777
{
7878
return new ArtifactDescriptor
7979
{
80-
Id = ArtifactId.New(),
80+
Id = RuntimeFoundationDeterministicIdentity.CreateArtifactId(sessionId, artifactName),
8181
SessionId = sessionId,
8282
Name = artifactName,
8383
Kind = artifactKind,
8484
RelativePath = artifactName,
85-
CreatedAt = DateTimeOffset.UtcNow,
85+
CreatedAt = RuntimeFoundationDeterministicIdentity.ArtifactCreatedAt,
8686
};
8787
}
8888
}

DotPilot.Runtime/Features/RuntimeFoundation/ProviderToolchainProbe.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ status is ProviderConnectionStatus.Available
2626

2727
return new ProviderDescriptor
2828
{
29-
Id = ProviderId.New(),
29+
Id = RuntimeFoundationDeterministicIdentity.CreateProviderId(commandName),
3030
DisplayName = displayName,
3131
CommandName = commandName,
3232
Status = status,

DotPilot.Runtime/Features/RuntimeFoundation/RuntimeFoundationCatalog.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ private static IReadOnlyList<ProviderDescriptor> CreateProviders()
7272
[
7373
new ProviderDescriptor
7474
{
75-
Id = ProviderId.New(),
75+
Id = RuntimeFoundationDeterministicIdentity.CreateProviderId(ProviderToolchainNames.DeterministicClientCommandName),
7676
DisplayName = ProviderToolchainNames.DeterministicClientDisplayName,
7777
CommandName = ProviderToolchainNames.DeterministicClientCommandName,
7878
Status = ProviderConnectionStatus.Available,
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System.Security.Cryptography;
2+
using System.Text;
3+
using DotPilot.Core.Features.ControlPlaneDomain;
4+
5+
namespace DotPilot.Runtime.Features.RuntimeFoundation;
6+
7+
internal static class RuntimeFoundationDeterministicIdentity
8+
{
9+
private const string ArtifactSeedPrefix = "runtime-foundation-artifact";
10+
private const string ProviderSeedPrefix = "runtime-foundation-provider";
11+
private const string SeedSeparator = "|";
12+
13+
public static DateTimeOffset ArtifactCreatedAt { get; } = new(2026, 3, 13, 0, 0, 0, TimeSpan.Zero);
14+
15+
public static ArtifactId CreateArtifactId(SessionId sessionId, string artifactName)
16+
{
17+
return new(CreateGuid(string.Concat(ArtifactSeedPrefix, SeedSeparator, sessionId, SeedSeparator, artifactName)));
18+
}
19+
20+
public static ProviderId CreateProviderId(string commandName)
21+
{
22+
return new(CreateGuid(string.Concat(ProviderSeedPrefix, SeedSeparator, commandName)));
23+
}
24+
25+
private static Guid CreateGuid(string seed)
26+
{
27+
var hash = SHA256.HashData(Encoding.UTF8.GetBytes(seed));
28+
Span<byte> guidBytes = stackalloc byte[16];
29+
hash[..guidBytes.Length].CopyTo(guidBytes);
30+
guidBytes[7] = (byte)((guidBytes[7] & 0x0F) | 0x80);
31+
guidBytes[8] = (byte)((guidBytes[8] & 0x3F) | 0x80);
32+
return new Guid(guidBytes);
33+
}
34+
}

DotPilot.Tests/AGENTS.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Stack: `.NET 10`, `NUnit`, `FluentAssertions`, `coverlet.collector`
1111
## Entry Points
1212

1313
- `DotPilot.Tests.csproj`
14-
- `AppInfoTests.cs`
14+
- `Features/*`
1515

1616
## Boundaries
1717

@@ -21,6 +21,7 @@ Stack: `.NET 10`, `NUnit`, `FluentAssertions`, `coverlet.collector`
2121
- Prefer production-facing flows and public contracts over implementation-detail assertions.
2222
- Keep a deterministic in-repo test AI client available for CI so provider-independent agent flows remain testable even when Codex, Claude Code, or GitHub Copilot are unavailable.
2323
- Tests that require real provider CLIs or auth must detect availability and run only when the corresponding external toolchain is present.
24+
- Organize test files by feature slice, with shared helpers living next to the slice that owns them instead of a flat project root.
2425

2526
## Local Commands
2627

DotPilot.Tests/AppInfoTests.cs renamed to DotPilot.Tests/Features/ApplicationShell/AppConfigTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
namespace DotPilot.Tests;
1+
namespace DotPilot.Tests.Features.ApplicationShell;
22

3-
public class AppInfoTests
3+
public class AppConfigTests
44
{
55
[SetUp]
66
public void Setup()

DotPilot.Tests/ControlPlaneDomainContractsTests.cs renamed to DotPilot.Tests/Features/ControlPlaneDomain/ControlPlaneDomainContractsTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
using System.Text.Json;
22

3-
namespace DotPilot.Tests;
3+
namespace DotPilot.Tests.Features.ControlPlaneDomain;
44

55
public class ControlPlaneDomainContractsTests
66
{
7+
private const string SyntheticWorkspaceRootPath = "/repo/dotPilot";
78
private static readonly DateTimeOffset CreatedAt = new(2026, 3, 13, 10, 15, 30, TimeSpan.Zero);
89
private static readonly DateTimeOffset UpdatedAt = new(2026, 3, 13, 10, 45, 30, TimeSpan.Zero);
910
private static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web);
@@ -97,7 +98,7 @@ private static ControlPlaneDomainEnvelope CreateEnvelope()
9798
{
9899
Id = WorkspaceId.New(),
99100
Name = "dotPilot",
100-
RootPath = "/Users/ksemenenko/Developer/dotPilot",
101+
RootPath = SyntheticWorkspaceRootPath,
101102
BranchName = "codex/issue-22-domain-model",
102103
};
103104

DotPilot.Tests/DebugHttpHandlerTests.cs renamed to DotPilot.Tests/Features/HttpDiagnostics/DebugHttpHandlerTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System.Net;
22
using DotPilot.Runtime.Features.HttpDiagnostics;
33

4-
namespace DotPilot.Tests;
4+
namespace DotPilot.Tests.Features.HttpDiagnostics;
55

66
public class DebugHttpHandlerTests
77
{

DotPilot.Tests/RuntimeCommunicationProblemsTests.cs renamed to DotPilot.Tests/Features/RuntimeCommunication/RuntimeCommunicationProblemsTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace DotPilot.Tests;
1+
namespace DotPilot.Tests.Features.RuntimeCommunication;
22

33
public class RuntimeCommunicationProblemsTests
44
{

0 commit comments

Comments
 (0)