Skip to content

Commit 0cc7674

Browse files
committed
Feat: Add governed execution runtime
1 parent 6ab8750 commit 0cc7674

22 files changed

Lines changed: 932 additions & 145 deletions

Examples/Governance/ApprovalWorkflow/Scenarios/GovernanceApprovalWorkflowScenario.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using ModularityKit.Mutator.Abstractions.Context;
22
using ModularityKit.Mutator.Abstractions.Intent;
33
using ModularityKit.Mutator.Abstractions.Policies;
4+
using ModularityKit.Mutator.Governance.Abstractions.Requests.Factory;
45
using ModularityKit.Mutator.Governance.Abstractions.Requests.Model;
56
using ModularityKit.Mutator.Governance.Runtime.Approval.Execution;
67
using ModularityKit.Mutator.Governance.Runtime.Storage;
@@ -45,7 +46,7 @@ public static async Task Run()
4546

4647
private static MutationRequest CreateApprovalRequest()
4748
{
48-
return MutationRequest.PendingApproval(
49+
return MutationRequestFactory.PendingApproval(
4950
stateId: "tenant-42:roles",
5051
stateType: "IamRoleState",
5152
mutationType: "GrantRoleMutation",
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net10.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<ProjectReference Include="..\..\..\src\ModularityKit.Mutator.Governance.csproj" />
12+
</ItemGroup>
13+
14+
<ItemGroup>
15+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.2" />
16+
</ItemGroup>
17+
18+
</Project>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
using GovernedExecution.Scenarios;
2+
3+
await GovernanceExecutionScenario.Run();
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# GovernedExecution
2+
3+
This example shows the full governed execution loop:
4+
5+
- approved request
6+
- version resolution
7+
- mutation execution through the core engine
8+
- terminal `Executed` request decision
9+
10+
## Key Files
11+
12+
- [`Program.cs`](Program.cs)
13+
- [`Scenarios/GovernanceExecutionScenario.cs`](Scenarios/GovernanceExecutionScenario.cs)
14+
- [`src/Governance/Runtime/Execution/Orchestration/GovernanceExecutionManager.cs`](../../../src/Governance/Runtime/Execution/Orchestration/GovernanceExecutionManager.cs)
15+
- [`src/Governance/Abstractions/Execution/Contracts/IGovernanceExecutionManager.cs`](../../../src/Governance/Abstractions/Execution/Contracts/IGovernanceExecutionManager.cs)
16+
17+
## Run
18+
19+
```bash
20+
dotnet run --project Examples/Governance/GovernedExecution/GovernedExecution.csproj
21+
```
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using ModularityKit.Mutator.Abstractions;
3+
using ModularityKit.Mutator.Abstractions.Changes;
4+
using ModularityKit.Mutator.Abstractions.Context;
5+
using ModularityKit.Mutator.Abstractions.Engine;
6+
using ModularityKit.Mutator.Abstractions.Intent;
7+
using ModularityKit.Mutator.Abstractions.Results;
8+
using ModularityKit.Mutator.Governance.Abstractions.Requests.Factory;
9+
using ModularityKit.Mutator.Governance.Abstractions.Requests.Model;
10+
using ModularityKit.Mutator.Governance.Abstractions.Resolution.Strategies;
11+
using ModularityKit.Mutator.Governance.Runtime.Execution.Orchestration;
12+
using ModularityKit.Mutator.Governance.Runtime.Resolution.Execution;
13+
using ModularityKit.Mutator.Governance.Runtime.Storage;
14+
using ModularityKit.Mutator.Runtime;
15+
16+
namespace GovernedExecution.Scenarios;
17+
18+
internal static class GovernanceExecutionScenario
19+
{
20+
public static async Task Run()
21+
{
22+
var services = new ServiceCollection();
23+
services.AddMutators(MutationEngineOptions.Strict);
24+
await using var provider = services.BuildServiceProvider();
25+
26+
var engine = provider.GetRequiredService<IMutationEngine>();
27+
var store = new InMemoryMutationRequestStore();
28+
var resolutionManager = new MutationRequestVersionResolutionManager(store, new MutationRequestVersionResolver());
29+
var executionManager = new GovernanceExecutionManager(store, resolutionManager, engine);
30+
31+
var request = await store.Create(MutationRequestFactory.Approved(
32+
stateId: "tenant-42:feature-flags",
33+
stateType: "FeatureFlagState",
34+
mutationType: nameof(EnableFeatureMutation),
35+
intent: new MutationIntent
36+
{
37+
OperationName = "EnableFeature",
38+
Category = "Configuration",
39+
Description = "Enable a rollout after governance approval"
40+
},
41+
context: MutationContext.User("requester-1", "Requester One", "Enable guarded rollout"),
42+
expectedStateVersion: "v10"));
43+
44+
var currentState = new FeatureFlagState(
45+
request.StateId,
46+
IsEnabled: false,
47+
Version: "v10");
48+
49+
var execution = await executionManager.ExecuteApproved(
50+
request.RequestId,
51+
new EnableFeatureMutation(MutationContext.Service("release-orchestrator", "Execute approved rollout"), "v11"),
52+
currentState,
53+
currentState.Version,
54+
resultingStateVersionProvider: state => state.Version,
55+
governanceContext: MutationContext.Service("governance-runtime", "Execute approved governance request"),
56+
strategy: VersionedRequestResolutionStrategy.RejectStale);
57+
58+
Console.WriteLine("=== Governed Execution ===");
59+
Console.WriteLine($"Executed: {execution.WasExecuted}");
60+
Console.WriteLine($"Resolution: {execution.Resolution.Outcome}");
61+
Console.WriteLine($"Request status: {execution.Request.Status}");
62+
Console.WriteLine($"Resulting version: {execution.ResultingStateVersion ?? "-"}");
63+
Console.WriteLine($"Last decision: {execution.Request.Decisions[^1].Type}");
64+
Console.WriteLine($"Reason: {execution.Request.Decisions[^1].Reason}");
65+
}
66+
67+
private sealed record FeatureFlagState(string StateId, bool IsEnabled, string Version);
68+
69+
private sealed class EnableFeatureMutation(MutationContext context, string nextVersion) : IMutation<FeatureFlagState>
70+
{
71+
public MutationIntent Intent { get; } = new()
72+
{
73+
OperationName = "EnableFeature",
74+
Category = "Configuration",
75+
Description = "Enable a feature after governance approval"
76+
};
77+
78+
public MutationContext Context { get; } = context;
79+
80+
public MutationResult<FeatureFlagState> Apply(FeatureFlagState state)
81+
{
82+
var newState = state with
83+
{
84+
IsEnabled = true,
85+
Version = nextVersion
86+
};
87+
88+
return MutationResult<FeatureFlagState>.Success(
89+
newState,
90+
ChangeSet.Single(StateChange.Modified("IsEnabled", state.IsEnabled, newState.IsEnabled)));
91+
}
92+
93+
public ValidationResult Validate(FeatureFlagState state)
94+
{
95+
return state.IsEnabled
96+
? ValidationResult.WithError("IsEnabled", "Feature is already enabled.")
97+
: ValidationResult.Success();
98+
}
99+
100+
public MutationResult<FeatureFlagState> Simulate(FeatureFlagState state) => Apply(state);
101+
}
102+
}

Examples/Governance/RequestLifecycle/Scenarios/GovernanceRequestLifecycleScenario.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using ModularityKit.Mutator.Abstractions.Intent;
33
using ModularityKit.Mutator.Abstractions.Policies;
44
using ModularityKit.Mutator.Governance.Abstractions.Lifecycle.Model;
5+
using ModularityKit.Mutator.Governance.Abstractions.Requests.Factory;
56
using ModularityKit.Mutator.Governance.Abstractions.Requests.Model;
67
using ModularityKit.Mutator.Governance.Runtime.Lifecycle.Execution;
78
using ModularityKit.Mutator.Governance.Runtime.Storage;
@@ -17,7 +18,7 @@ public static async Task Run()
1718

1819
var submittedAt = DateTimeOffset.UtcNow;
1920

20-
var quotaApprovalRequest = MutationRequest.Pending(
21+
var quotaApprovalRequest = MutationRequestFactory.Pending(
2122
stateId: "tenant-42:quota",
2223
stateType: "QuotaPolicy",
2324
mutationType: "IncreaseQuotaMutation",
@@ -40,7 +41,7 @@ public static async Task Run()
4041
["TenantId"] = "tenant-42"
4142
});
4243

43-
var scheduledRequest = MutationRequest.Pending(
44+
var scheduledRequest = MutationRequestFactory.Pending(
4445
stateId: "tenant-42:quota",
4546
stateType: "QuotaPolicy",
4647
mutationType: "ResetQuotaMutation",
@@ -55,7 +56,7 @@ public static async Task Run()
5556
expectedStateVersion: "v12",
5657
expiresAt: submittedAt.AddMinutes(-5));
5758

58-
var externalCheckRequest = MutationRequest.Approved(
59+
var externalCheckRequest = MutationRequestFactory.Approved(
5960
stateId: "tenant-99:flags",
6061
stateType: "FeatureFlagState",
6162
mutationType: "EnableFeatureMutation",

Examples/Governance/VersionedResolution/Scenarios/GovernanceVersionedResolutionScenario.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using ModularityKit.Mutator.Abstractions.Context;
22
using ModularityKit.Mutator.Abstractions.Intent;
3+
using ModularityKit.Mutator.Governance.Abstractions.Requests.Factory;
34
using ModularityKit.Mutator.Governance.Abstractions.Requests.Model;
45
using ModularityKit.Mutator.Governance.Abstractions.Resolution.Model;
56
using ModularityKit.Mutator.Governance.Abstractions.Resolution.Strategies;
@@ -62,7 +63,7 @@ public static async Task Run()
6263

6364
private static MutationRequest CreateApprovedRequest(string expectedStateVersion)
6465
{
65-
return MutationRequest.Approved(
66+
return MutationRequestFactory.Approved(
6667
stateId: "tenant-42:roles",
6768
stateType: "IamRoleState",
6869
mutationType: "GrantRoleMutation",

Examples/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ The projects are intentionally small and focused. Each one demonstrates a differ
2323
| Example | Focus | Readme |
2424
| --- | --- | --- |
2525
| `RequestLifecycle` | pending requests, lifecycle transitions, expiration, and cancellation | [`Examples/Governance/RequestLifecycle/README.md`](Governance/RequestLifecycle/README.md) |
26+
| `GovernedExecution` | approved request -> resolution -> execution -> executed decision | [`Examples/Governance/GovernedExecution/README.md`](Governance/GovernedExecution/README.md) |
2627
| `DecisionTaxonomy` | lifecycle, approval, and version-resolution decision categories | [`Examples/Governance/DecisionTaxonomy/README.md`](Governance/DecisionTaxonomy/README.md) |
2728
| `ApprovalWorkflow` | request-level approvals, multi-step sign-off, and governed approval actions | [`Examples/Governance/ApprovalWorkflow/README.md`](Governance/ApprovalWorkflow/README.md) |
2829
| `VersionedResolution` | stale request handling and expected state version semantics | [`Examples/Governance/VersionedResolution/README.md`](Governance/VersionedResolution/README.md) |
@@ -54,6 +55,7 @@ dotnet build Examples/Core/FeatureFlags/FeatureFlags.csproj -c Release
5455
dotnet build Examples/Core/IamRoles/IamRoles.csproj -c Release
5556
dotnet build Examples/Core/WorkflowApprovals/WorkflowApprovals.csproj -c Release
5657
dotnet build Examples/Governance/RequestLifecycle/RequestLifecycle.csproj -c Release
58+
dotnet build Examples/Governance/GovernedExecution/GovernedExecution.csproj -c Release
5759
dotnet build Examples/Governance/DecisionTaxonomy/DecisionTaxonomy.csproj -c Release
5860
dotnet build Examples/Governance/ApprovalWorkflow/ApprovalWorkflow.csproj -c Release
5961
dotnet build Examples/Governance/VersionedResolution/VersionedResolution.csproj -c Release
@@ -71,6 +73,7 @@ dotnet run --project Examples/Core/FeatureFlags/FeatureFlags.csproj
7173
dotnet run --project Examples/Core/IamRoles/IamRoles.csproj
7274
dotnet run --project Examples/Core/WorkflowApprovals/WorkflowApprovals.csproj
7375
dotnet run --project Examples/Governance/RequestLifecycle/RequestLifecycle.csproj
76+
dotnet run --project Examples/Governance/GovernedExecution/GovernedExecution.csproj
7477
dotnet run --project Examples/Governance/DecisionTaxonomy/DecisionTaxonomy.csproj
7578
dotnet run --project Examples/Governance/ApprovalWorkflow/ApprovalWorkflow.csproj
7679
dotnet run --project Examples/Governance/VersionedResolution/VersionedResolution.csproj
@@ -137,6 +140,12 @@ Shows the governance runtime as a request lifecycle system instead of an immedia
137140

138141
See [`Governance/RequestLifecycle/README.md`](Governance/RequestLifecycle/README.md).
139142

143+
### GovernedExecution
144+
145+
Shows the full governed execution loop from approved request to version resolution, core mutation execution, and terminal executed decision.
146+
147+
See [`Governance/GovernedExecution/README.md`](Governance/GovernedExecution/README.md).
148+
140149
### ApprovalWorkflow
141150

142151
Shows how governance turns approval requirements into explicit request-level approval actions with ordered steps and terminal approval or rejection behavior.

ModularityKit.Mutator.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<Project Path="Examples/Core/IamRoles/IamRoles.csproj" />
1010
<Project Path="Examples/Core/WorkflowApprovals/WorkflowApprovals.csproj" />
1111
<Project Path="Examples/Governance/ApprovalWorkflow/ApprovalWorkflow.csproj" />
12+
<Project Path="Examples/Governance/GovernedExecution/GovernedExecution.csproj" />
1213
<Project Path="Examples/Governance/DecisionTaxonomy/DecisionTaxonomy.csproj" />
1314
<Project Path="Examples/Governance/RequestLifecycle/RequestLifecycle.csproj" />
1415
<Project Path="Examples/Governance/VersionedResolution/VersionedResolution.csproj" />

Tests/ModularityKit.Mutator.Governance.Tests/Approval/MutationRequestApprovalWorkflowTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using ModularityKit.Mutator.Governance.Abstractions.Exceptions.Approval;
66
using ModularityKit.Mutator.Governance.Abstractions.Lifecycle.Model;
77
using ModularityKit.Mutator.Governance.Abstractions.Requests.Decisions;
8+
using ModularityKit.Mutator.Governance.Abstractions.Requests.Factory;
89
using ModularityKit.Mutator.Governance.Abstractions.Requests.Model;
910
using ModularityKit.Mutator.Governance.Runtime.Approval.Execution;
1011
using ModularityKit.Mutator.Governance.Runtime.Storage;
@@ -17,7 +18,7 @@ public sealed class MutationRequestApprovalWorkflowTests
1718
[Fact]
1819
public void PendingApproval_maps_policy_requirements_into_visible_request_approval_requirements()
1920
{
20-
var request = MutationRequest.PendingApproval(
21+
var request = MutationRequestFactory.PendingApproval(
2122
stateId: "tenant-42:roles",
2223
stateType: "IamRoleState",
2324
mutationType: "GrantRoleMutation",
@@ -141,7 +142,7 @@ public async Task RejectRequirement_marks_request_rejected_and_records_explicit_
141142

142143
private static MutationRequest CreateMultiStepApprovalRequest()
143144
{
144-
return MutationRequest.PendingApproval(
145+
return MutationRequestFactory.PendingApproval(
145146
stateId: "tenant-42:roles",
146147
stateType: "IamRoleState",
147148
mutationType: "GrantRoleMutation",

0 commit comments

Comments
 (0)