Skip to content

Commit 7213a37

Browse files
committed
Merge remote-tracking branch 'origin/main' into codex/epic-11-foundation-contracts
# Conflicts: # DotPilot.Runtime/Features/RuntimeFoundation/RuntimeFoundationCatalog.cs # DotPilot.Tests/Features/ControlPlaneDomain/ControlPlaneDomainContractsTests.cs # docs/ADR/ADR-0003-vertical-slices-and-ui-only-uno-app.md # docs/Architecture.md
2 parents 5e38051 + 2be757f commit 7213a37

94 files changed

Lines changed: 3633 additions & 619 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ This file defines how AI agents work in this solution.
2323
- `DotPilot`
2424
- `DotPilot.Core`
2525
- `DotPilot.Runtime`
26+
- `DotPilot.Runtime.Host`
2627
- `DotPilot.ReleaseTool`
2728
- `DotPilot.Tests`
2829
- `DotPilot.UITests`
@@ -143,13 +144,23 @@ For this app:
143144
- the repo-root lowercase `.editorconfig` is the source of truth for formatting, naming, style, and analyzer severity
144145
- local and CI build commands must pass `-warnaserror`; warnings are not an acceptable "green" build state in this repository
145146
- 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
147+
- 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
146148
- 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
147149
- `Directory.Build.props` owns the shared analyzer and warning policy for future projects
148150
- `Directory.Packages.props` owns centrally managed package versions
149151
- `global.json` pins the .NET SDK and Uno SDK version used by the app and tests
150152
- `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
151153
- 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
152154
- 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
155+
- when the user asks to implement an epic, the delivery branch and PR must cover all of that epic's direct child issues that belong to the requested scope, not just one child issue with a partial close-out
156+
- epic implementation PRs must include automated tests for every direct child issue they claim to cover, plus the broader runtime and UI regressions required by the touched flows
157+
- do not claim an epic is implemented unless every direct child issue in the requested scope is both realized in code and covered by automated tests; partial coverage is not an acceptable close-out
158+
- 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
159+
- the first embedded Orleans runtime cut must use `UseLocalhostClustering` together with in-memory Orleans grain storage and in-memory reminders; do not introduce remote clustering or external durable stores until a later backlog item explicitly requires them, and keep durable resume/replay outside Orleans storage until the cluster topology is intentionally upgraded
160+
- GitHub is the backlog, not the product: use issues and PRs only to drive task scope and traceability, and never copy GitHub issue text, labels, workflow language, or tracker metadata into production code, runtime snapshots, or user-facing UI
161+
- never claim an epic is complete until its current GitHub scope is verified against the live issue graph; check which issues are real children versus issues that merely depend on the epic or belong to a different parent epic
162+
- Desktop responsiveness is a product requirement: avoid synchronous probe, filesystem, network, or process work on UI-facing construction and navigation paths so the app stays fast and immediately reactive
163+
- Do not invent a repo-specific product framing such as "workbench" unless the active issue or feature spec explicitly uses it; implement the app features described in the backlog instead of turning internal implementation language into the product narrative
153164
- 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
154165
- 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
155166
- 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
@@ -302,6 +313,7 @@ Local `AGENTS.md` files may tighten these values, but they must not loosen them
302313
- Hardcoded values are forbidden.
303314
- String literals are forbidden in implementation code. Declare them once as named constants, enums, configuration entries, or dedicated value objects, then reuse those symbols.
304315
- Avoid magic literals. Extract shared values into constants, enums, configuration, or dedicated types.
316+
- Backlog metadata does not belong in product code: issue numbers, PR numbers, review language, and planning terminology must never appear in production runtime models, diagnostics, or user-facing text unless the feature explicitly exposes source-control metadata.
305317
- Design boundaries so real behaviour can be tested through public interfaces.
306318
- For `.NET`, the repo-root `.editorconfig` is the source of truth for formatting, naming, style, and analyzer severity.
307319
- Use nested `.editorconfig` files when they serve a clear subtree-specific purpose. Do not let IDE defaults, pipeline flags, and repo config disagree.
@@ -360,6 +372,8 @@ Ask first:
360372
- Installing stale, non-canonical, or non-`mcaf-*` skills into the repo-local agent skill directory.
361373
- Moving root governance out of the repository root.
362374
- Mixing multiple `.NET` test frameworks in the active solution without a documented migration plan.
375+
- Creating auxiliary `git worktree` directories for normal PR follow-up when straightforward branch switching in the main checkout is enough.
376+
- Running build, test, or verification commands for file-only structural reorganizations when the user explicitly asked for folder cleanup without behavior changes.
363377
- Adding fallback paths or alternate harnesses that only make failures disappear in tests while the primary product path remains broken.
364378
- Switching desktop Uno pages into stacked or mobile-style responsive layouts during resize work unless the user explicitly asks for a different composition; desktop pages must stay desktop-first and protect geometry through sizing constraints instead.
365379
- Adding extra UI-test orchestration complexity when the actual goal is simply to run the tests and get an honest pass or fail result.

Directory.Packages.props

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
<PackageVersion Include="coverlet.collector" Version="8.0.0" />
1313
<PackageVersion Include="FluentAssertions" Version="6.12.0" />
1414
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
15+
<PackageVersion Include="Microsoft.Agents.AI.Workflows" Version="1.0.0-rc4" />
16+
<PackageVersion Include="Microsoft.Orleans.Core.Abstractions" Version="10.0.1" />
17+
<PackageVersion Include="Microsoft.Orleans.Persistence.Memory" Version="10.0.1" />
18+
<PackageVersion Include="Microsoft.Orleans.Reminders" Version="10.0.1" />
19+
<PackageVersion Include="Microsoft.Orleans.Server" Version="10.0.1" />
1520
<PackageVersion Include="NUnit" Version="4.5.1" />
1621
<PackageVersion Include="NUnit3TestAdapter" Version="6.1.0" />
1722
<PackageVersion Include="GitHubActionsTestLogger" Version="3.0.1" />

DotPilot.Core/DotPilot.Core.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,8 @@
66
<NoWarn>$(NoWarn);CS1591</NoWarn>
77
</PropertyGroup>
88

9+
<ItemGroup>
10+
<PackageReference Include="Microsoft.Orleans.Core.Abstractions" />
11+
</ItemGroup>
12+
913
</Project>

DotPilot.Core/Features/ControlPlaneDomain/ControlPlaneIdentifiers.cs

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,77 +2,96 @@
22

33
namespace DotPilot.Core.Features.ControlPlaneDomain;
44

5-
public readonly record struct WorkspaceId(Guid Value)
5+
[GenerateSerializer]
6+
public readonly record struct WorkspaceId([property: Id(0)] Guid Value)
67
{
78
public static WorkspaceId New() => new(ControlPlaneIdentifier.NewValue());
89

910
public override string ToString() => ControlPlaneIdentifier.Format(Value);
1011
}
1112

12-
public readonly record struct AgentProfileId(Guid Value)
13+
[GenerateSerializer]
14+
public readonly record struct AgentProfileId([property: Id(0)] Guid Value)
1315
{
1416
public static AgentProfileId New() => new(ControlPlaneIdentifier.NewValue());
1517

1618
public override string ToString() => ControlPlaneIdentifier.Format(Value);
1719
}
1820

19-
public readonly record struct SessionId(Guid Value)
21+
[GenerateSerializer]
22+
public readonly record struct SessionId([property: Id(0)] Guid Value)
2023
{
2124
public static SessionId New() => new(ControlPlaneIdentifier.NewValue());
2225

2326
public override string ToString() => ControlPlaneIdentifier.Format(Value);
2427
}
2528

26-
public readonly record struct FleetId(Guid Value)
29+
[GenerateSerializer]
30+
public readonly record struct FleetId([property: Id(0)] Guid Value)
2731
{
2832
public static FleetId New() => new(ControlPlaneIdentifier.NewValue());
2933

3034
public override string ToString() => ControlPlaneIdentifier.Format(Value);
3135
}
3236

33-
public readonly record struct ProviderId(Guid Value)
37+
[GenerateSerializer]
38+
public readonly record struct PolicyId([property: Id(0)] Guid Value)
39+
{
40+
public static PolicyId New() => new(ControlPlaneIdentifier.NewValue());
41+
42+
public override string ToString() => ControlPlaneIdentifier.Format(Value);
43+
}
44+
45+
[GenerateSerializer]
46+
public readonly record struct ProviderId([property: Id(0)] Guid Value)
3447
{
3548
public static ProviderId New() => new(ControlPlaneIdentifier.NewValue());
3649

3750
public override string ToString() => ControlPlaneIdentifier.Format(Value);
3851
}
3952

40-
public readonly record struct ModelRuntimeId(Guid Value)
53+
[GenerateSerializer]
54+
public readonly record struct ModelRuntimeId([property: Id(0)] Guid Value)
4155
{
4256
public static ModelRuntimeId New() => new(ControlPlaneIdentifier.NewValue());
4357

4458
public override string ToString() => ControlPlaneIdentifier.Format(Value);
4559
}
4660

47-
public readonly record struct ToolCapabilityId(Guid Value)
61+
[GenerateSerializer]
62+
public readonly record struct ToolCapabilityId([property: Id(0)] Guid Value)
4863
{
4964
public static ToolCapabilityId New() => new(ControlPlaneIdentifier.NewValue());
5065

5166
public override string ToString() => ControlPlaneIdentifier.Format(Value);
5267
}
5368

54-
public readonly record struct ApprovalId(Guid Value)
69+
[GenerateSerializer]
70+
public readonly record struct ApprovalId([property: Id(0)] Guid Value)
5571
{
5672
public static ApprovalId New() => new(ControlPlaneIdentifier.NewValue());
5773

5874
public override string ToString() => ControlPlaneIdentifier.Format(Value);
5975
}
6076

61-
public readonly record struct ArtifactId(Guid Value)
77+
[GenerateSerializer]
78+
public readonly record struct ArtifactId([property: Id(0)] Guid Value)
6279
{
6380
public static ArtifactId New() => new(ControlPlaneIdentifier.NewValue());
6481

6582
public override string ToString() => ControlPlaneIdentifier.Format(Value);
6683
}
6784

68-
public readonly record struct TelemetryRecordId(Guid Value)
85+
[GenerateSerializer]
86+
public readonly record struct TelemetryRecordId([property: Id(0)] Guid Value)
6987
{
7088
public static TelemetryRecordId New() => new(ControlPlaneIdentifier.NewValue());
7189

7290
public override string ToString() => ControlPlaneIdentifier.Format(Value);
7391
}
7492

75-
public readonly record struct EvaluationId(Guid Value)
93+
[GenerateSerializer]
94+
public readonly record struct EvaluationId([property: Id(0)] Guid Value)
7695
{
7796
public static EvaluationId New() => new(ControlPlaneIdentifier.NewValue());
7897

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,58 @@
11
namespace DotPilot.Core.Features.ControlPlaneDomain;
22

3+
[GenerateSerializer]
34
public sealed record WorkspaceDescriptor
45
{
6+
[Id(0)]
57
public WorkspaceId Id { get; init; }
68

9+
[Id(1)]
710
public string Name { get; init; } = string.Empty;
811

12+
[Id(2)]
913
public string RootPath { get; init; } = string.Empty;
1014

15+
[Id(3)]
1116
public string BranchName { get; init; } = string.Empty;
1217
}
1318

19+
[GenerateSerializer]
1420
public sealed record AgentProfileDescriptor
1521
{
22+
[Id(0)]
1623
public AgentProfileId Id { get; init; }
1724

25+
[Id(1)]
1826
public string Name { get; init; } = string.Empty;
1927

28+
[Id(2)]
2029
public AgentRoleKind Role { get; init; }
2130

31+
[Id(3)]
2232
public ProviderId? ProviderId { get; init; }
2333

34+
[Id(4)]
2435
public ModelRuntimeId? ModelRuntimeId { get; init; }
2536

26-
public IReadOnlyList<ToolCapabilityId> ToolCapabilityIds { get; init; } = [];
37+
[Id(5)]
38+
public ToolCapabilityId[] ToolCapabilityIds { get; init; } = [];
2739

28-
public IReadOnlyList<string> Tags { get; init; } = [];
40+
[Id(6)]
41+
public string[] Tags { get; init; } = [];
2942
}
3043

44+
[GenerateSerializer]
3145
public sealed record FleetDescriptor
3246
{
47+
[Id(0)]
3348
public FleetId Id { get; init; }
3449

50+
[Id(1)]
3551
public string Name { get; init; } = string.Empty;
3652

53+
[Id(2)]
3754
public FleetExecutionMode ExecutionMode { get; init; } = FleetExecutionMode.SingleAgent;
3855

39-
public IReadOnlyList<AgentProfileId> AgentProfileIds { get; init; } = [];
56+
[Id(3)]
57+
public AgentProfileId[] AgentProfileIds { get; init; } = [];
4058
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
namespace DotPilot.Core.Features.ControlPlaneDomain;
2+
3+
[GenerateSerializer]
4+
public sealed record PolicyDescriptor
5+
{
6+
[Id(0)]
7+
public PolicyId Id { get; init; }
8+
9+
[Id(1)]
10+
public string Name { get; init; } = string.Empty;
11+
12+
[Id(2)]
13+
public ApprovalState DefaultApprovalState { get; init; } = ApprovalState.NotRequired;
14+
15+
[Id(3)]
16+
public bool AllowsNetworkAccess { get; init; }
17+
18+
[Id(4)]
19+
public bool AllowsFileSystemWrites { get; init; }
20+
21+
[Id(5)]
22+
public ApprovalScope[] ProtectedScopes { get; init; } = [];
23+
}
Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,73 @@
11
namespace DotPilot.Core.Features.ControlPlaneDomain;
22

3+
[GenerateSerializer]
34
public sealed record ToolCapabilityDescriptor
45
{
6+
[Id(0)]
57
public ToolCapabilityId Id { get; init; }
68

9+
[Id(1)]
710
public string Name { get; init; } = string.Empty;
811

12+
[Id(2)]
913
public string DisplayName { get; init; } = string.Empty;
1014

15+
[Id(3)]
1116
public ToolCapabilityKind Kind { get; init; }
1217

18+
[Id(4)]
1319
public bool RequiresApproval { get; init; }
1420

21+
[Id(5)]
1522
public bool IsEnabledByDefault { get; init; }
1623

17-
public IReadOnlyList<string> Tags { get; init; } = [];
24+
[Id(6)]
25+
public string[] Tags { get; init; } = [];
1826
}
1927

28+
[GenerateSerializer]
2029
public sealed record ProviderDescriptor
2130
{
31+
[Id(0)]
2232
public ProviderId Id { get; init; }
2333

34+
[Id(1)]
2435
public string DisplayName { get; init; } = string.Empty;
2536

37+
[Id(2)]
2638
public string CommandName { get; init; } = string.Empty;
2739

40+
[Id(3)]
2841
public ProviderConnectionStatus Status { get; init; } = ProviderConnectionStatus.Unavailable;
2942

43+
[Id(4)]
3044
public string StatusSummary { get; init; } = string.Empty;
3145

46+
[Id(5)]
3247
public bool RequiresExternalToolchain { get; init; }
3348

34-
public IReadOnlyList<ToolCapabilityId> SupportedToolIds { get; init; } = [];
49+
[Id(6)]
50+
public ToolCapabilityId[] SupportedToolIds { get; init; } = [];
3551
}
3652

53+
[GenerateSerializer]
3754
public sealed record ModelRuntimeDescriptor
3855
{
56+
[Id(0)]
3957
public ModelRuntimeId Id { get; init; }
4058

59+
[Id(1)]
4160
public string DisplayName { get; init; } = string.Empty;
4261

62+
[Id(2)]
4363
public string EngineName { get; init; } = string.Empty;
4464

65+
[Id(3)]
4566
public RuntimeKind RuntimeKind { get; init; }
4667

68+
[Id(4)]
4769
public ProviderConnectionStatus Status { get; init; } = ProviderConnectionStatus.Unavailable;
4870

49-
public IReadOnlyList<string> SupportedModelFamilies { get; init; } = [];
71+
[Id(5)]
72+
public string[] SupportedModelFamilies { get; init; } = [];
5073
}

0 commit comments

Comments
 (0)