Skip to content

Commit ae696de

Browse files
committed
Docs: Organize governance examples and references
1 parent c76c330 commit ae696de

9 files changed

Lines changed: 191 additions & 5 deletions

File tree

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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+
</Project>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
using DecisionTaxonomy.Scenarios;
2+
3+
GovernanceDecisionTaxonomyScenario.Run();
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Governance DecisionTaxonomy
2+
3+
This example shows why governance request decisions are split into separate categories instead of being kept in one flat enum.
4+
5+
It demonstrates:
6+
7+
- lifecycle decisions such as `Submitted` and `Approved`
8+
- approval decisions such as `Requested`, `Granted`, and `Rejected`
9+
- version-resolution decisions such as `Validated` and `RejectedAsStale`
10+
- the shared `MutationRequestDecisionType` wrapper with:
11+
- `Category`
12+
- `Code`
13+
- `ToString()`
14+
15+
## Key files
16+
17+
- [`Program.cs`](Program.cs)
18+
- [`Scenarios/GovernanceDecisionTaxonomyScenario.cs`](Scenarios/GovernanceDecisionTaxonomyScenario.cs)
19+
- [`src/Governance/Abstractions/Requests/Decisions/MutationRequestDecisionType.cs`](../../../src/Governance/Abstractions/Requests/Decisions/MutationRequestDecisionType.cs)
20+
- [`src/Governance/Abstractions/Requests/Decisions/MutationRequestDecisionCategory.cs`](../../../src/Governance/Abstractions/Requests/Decisions/MutationRequestDecisionCategory.cs)
21+
- [`src/Governance/Abstractions/Requests/Decisions/MutationRequestLifecycleDecisionType.cs`](../../../src/Governance/Abstractions/Requests/Decisions/MutationRequestLifecycleDecisionType.cs)
22+
- [`src/Governance/Abstractions/Requests/Decisions/MutationRequestApprovalDecisionType.cs`](../../../src/Governance/Abstractions/Requests/Decisions/MutationRequestApprovalDecisionType.cs)
23+
- [`src/Governance/Abstractions/Requests/Decisions/MutationRequestVersionResolutionDecisionType.cs`](../../../src/Governance/Abstractions/Requests/Decisions/MutationRequestVersionResolutionDecisionType.cs)
24+
25+
## Run
26+
27+
```bash
28+
dotnet run --project Examples/Governance/DecisionTaxonomy/DecisionTaxonomy.csproj
29+
```
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using ModularityKit.Mutator.Abstractions.Context;
2+
using ModularityKit.Mutator.Governance.Abstractions.Requests.Decisions;
3+
4+
namespace DecisionTaxonomy.Scenarios;
5+
6+
internal static class GovernanceDecisionTaxonomyScenario
7+
{
8+
public static void Run()
9+
{
10+
PrintSection("Lifecycle Decisions");
11+
PrintDecision(MutationRequestDecision.Create(
12+
MutationRequestDecisionType.Lifecycle(MutationRequestLifecycleDecisionType.Submitted),
13+
MutationContext.User("requester", "Requester", "Submit request"),
14+
reason: "Request was submitted into governance."));
15+
PrintDecision(MutationRequestDecision.Create(
16+
MutationRequestDecisionType.Lifecycle(MutationRequestLifecycleDecisionType.Approved),
17+
MutationContext.User("system", "System", "Request reached executable state"),
18+
reason: "Request is now approved for execution."));
19+
20+
PrintSection("Approval Decisions");
21+
PrintDecision(MutationRequestDecision.Create(
22+
MutationRequestDecisionType.Approval(MutationRequestApprovalDecisionType.Requested),
23+
MutationContext.User("requester", "Requester", "Approval needed for sensitive change"),
24+
reason: "Sensitive change requires explicit sign-off."));
25+
PrintDecision(MutationRequestDecision.Create(
26+
MutationRequestDecisionType.Approval(MutationRequestApprovalDecisionType.Granted),
27+
MutationContext.User("alice", "Alice", "Manager approved"),
28+
reason: "Manager granted the required approval."));
29+
PrintDecision(MutationRequestDecision.Create(
30+
MutationRequestDecisionType.Approval(MutationRequestApprovalDecisionType.Rejected),
31+
MutationContext.User("bob", "Bob", "Security rejected"),
32+
reason: "Security review rejected the request."));
33+
34+
PrintSection("Version Resolution Decisions");
35+
PrintDecision(MutationRequestDecision.Create(
36+
MutationRequestDecisionType.VersionResolution(MutationRequestVersionResolutionDecisionType.Validated),
37+
MutationContext.User("approver", "Approver", "Version still matches"),
38+
reason: "Current state version still matches the approved request."));
39+
PrintDecision(MutationRequestDecision.Create(
40+
MutationRequestDecisionType.VersionResolution(MutationRequestVersionResolutionDecisionType.RejectedAsStale),
41+
MutationContext.User("approver", "Approver", "State drift invalidated the request"),
42+
reason: "Request was rejected because the approved version is stale."));
43+
PrintDecision(MutationRequestDecision.Create(
44+
MutationRequestDecisionType.VersionResolution(MutationRequestVersionResolutionDecisionType.RenewedApprovalRequired),
45+
MutationContext.User("approver", "Approver", "Re-approval required on latest state"),
46+
reason: "Request must be approved again on the latest state version."));
47+
}
48+
49+
private static void PrintSection(string title)
50+
{
51+
Console.WriteLine();
52+
Console.WriteLine($"=== {title} ===");
53+
}
54+
55+
private static void PrintDecision(MutationRequestDecision decision)
56+
{
57+
Console.WriteLine($"Category: {decision.Type.Category}");
58+
Console.WriteLine($"Code: {decision.Type.Code}");
59+
Console.WriteLine($"Display: {decision.Type}");
60+
Console.WriteLine($"Actor: {decision.Context.ActorId ?? "system"}");
61+
Console.WriteLine($"Reason: {decision.Reason ?? "-"}");
62+
Console.WriteLine();
63+
}
64+
}

‎Examples/Governance/RequestLifecycle/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ It focuses on `MutationRequest`, `IMutationRequestStore`, and `MutationRequestLi
2121

2222
- [`Program.cs`](Program.cs)
2323
- [`Scenarios/GovernanceRequestLifecycleScenario.cs`](Scenarios/GovernanceRequestLifecycleScenario.cs)
24-
- [`src/Governance/Abstractions/Requests/MutationRequest.cs`](../../../src/Governance/Abstractions/Requests/MutationRequest.cs)
24+
- [`src/Governance/Abstractions/Requests/Model/MutationRequest.cs`](../../../src/Governance/Abstractions/Requests/Model/MutationRequest.cs)
2525
- [`src/Governance/Abstractions/Lifecycle/IMutationRequestLifecycleManager.cs`](../../../src/Governance/Abstractions/Lifecycle/IMutationRequestLifecycleManager.cs)
2626
- [`src/Governance/Runtime/MutationRequestLifecycleManager.cs`](../../../src/Governance/Runtime/MutationRequestLifecycleManager.cs)
2727
- [`src/Governance/Runtime/InMemoryMutationRequestStore.cs`](../../../src/Governance/Runtime/InMemoryMutationRequestStore.cs)

‎Examples/Governance/VersionedResolution/README.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ It is the direct runnable example for the semantics introduced around `ExpectedS
1717

1818
- [`Program.cs`](Program.cs)
1919
- [`Scenarios/GovernanceVersionedResolutionScenario.cs`](Scenarios/GovernanceVersionedResolutionScenario.cs)
20-
- [`src/Governance/Runtime/Resolution/MutationRequestVersionResolver.cs`](../../../src/Governance/Runtime/Resolution/MutationRequestVersionResolver.cs)
21-
- [`src/Governance/Runtime/Resolution/MutationRequestVersionResolutionManager.cs`](../../../src/Governance/Runtime/Resolution/MutationRequestVersionResolutionManager.cs)
22-
- [`src/Governance/Abstractions/Resolution/VersionedRequestResolutionStrategy.cs`](../../../src/Governance/Abstractions/Resolution/VersionedRequestResolutionStrategy.cs)
23-
- [`src/Governance/Abstractions/Resolution/MutationRequestVersionResolution.cs`](../../../src/Governance/Abstractions/Resolution/MutationRequestVersionResolution.cs)
20+
- [`src/Governance/Runtime/Resolution/Execution/MutationRequestVersionResolver.cs`](../../../src/Governance/Runtime/Resolution/Execution/MutationRequestVersionResolver.cs)
21+
- [`src/Governance/Runtime/Resolution/Execution/MutationRequestVersionResolutionManager.cs`](../../../src/Governance/Runtime/Resolution/Execution/MutationRequestVersionResolutionManager.cs)
22+
- [`src/Governance/Abstractions/Resolution/Strategies/VersionedRequestResolutionStrategy.cs`](../../../src/Governance/Abstractions/Resolution/Strategies/VersionedRequestResolutionStrategy.cs)
23+
- [`src/Governance/Abstractions/Resolution/Model/MutationRequestVersionResolution.cs`](../../../src/Governance/Abstractions/Resolution/Model/MutationRequestVersionResolution.cs)
2424

2525
## Run
2626

‎Examples/README.md‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ 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+
| `DecisionTaxonomy` | lifecycle, approval, and version-resolution decision categories | [`Examples/Governance/DecisionTaxonomy/README.md`](Governance/DecisionTaxonomy/README.md) |
27+
| `ApprovalWorkflow` | request-level approvals, multi-step sign-off, and governed approval actions | [`Examples/Governance/ApprovalWorkflow/README.md`](Governance/ApprovalWorkflow/README.md) |
2628
| `VersionedResolution` | stale request handling and expected state version semantics | [`Examples/Governance/VersionedResolution/README.md`](Governance/VersionedResolution/README.md) |
2729

2830
## How to use these examples
@@ -52,6 +54,8 @@ dotnet build Examples/Core/FeatureFlags/FeatureFlags.csproj -c Release
5254
dotnet build Examples/Core/IamRoles/IamRoles.csproj -c Release
5355
dotnet build Examples/Core/WorkflowApprovals/WorkflowApprovals.csproj -c Release
5456
dotnet build Examples/Governance/RequestLifecycle/RequestLifecycle.csproj -c Release
57+
dotnet build Examples/Governance/DecisionTaxonomy/DecisionTaxonomy.csproj -c Release
58+
dotnet build Examples/Governance/ApprovalWorkflow/ApprovalWorkflow.csproj -c Release
5559
dotnet build Examples/Governance/VersionedResolution/VersionedResolution.csproj -c Release
5660
```
5761

@@ -67,6 +71,8 @@ dotnet run --project Examples/Core/FeatureFlags/FeatureFlags.csproj
6771
dotnet run --project Examples/Core/IamRoles/IamRoles.csproj
6872
dotnet run --project Examples/Core/WorkflowApprovals/WorkflowApprovals.csproj
6973
dotnet run --project Examples/Governance/RequestLifecycle/RequestLifecycle.csproj
74+
dotnet run --project Examples/Governance/DecisionTaxonomy/DecisionTaxonomy.csproj
75+
dotnet run --project Examples/Governance/ApprovalWorkflow/ApprovalWorkflow.csproj
7076
dotnet run --project Examples/Governance/VersionedResolution/VersionedResolution.csproj
7177
```
7278

@@ -131,6 +137,18 @@ Shows the governance runtime as a request lifecycle system instead of an immedia
131137

132138
See [`Governance/RequestLifecycle/README.md`](Governance/RequestLifecycle/README.md).
133139

140+
### ApprovalWorkflow
141+
142+
Shows how governance turns approval requirements into explicit request-level approval actions with ordered steps and terminal approval or rejection behavior.
143+
144+
See [`Governance/ApprovalWorkflow/README.md`](Governance/ApprovalWorkflow/README.md).
145+
146+
### DecisionTaxonomy
147+
148+
Shows why governance request decisions are split into lifecycle, approval, and version-resolution categories instead of being kept in one flat enum.
149+
150+
See [`Governance/DecisionTaxonomy/README.md`](Governance/DecisionTaxonomy/README.md).
151+
134152
### VersionedResolution
135153

136154
Shows how governance resolves approved requests once the underlying state version has moved. This is the example to read if you want concrete stale request semantics.

‎ModularityKit.Mutator.slnx‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
<Project Path="Examples/Core/FeatureFlags/FeatureFlags.csproj" />
99
<Project Path="Examples/Core/IamRoles/IamRoles.csproj" />
1010
<Project Path="Examples/Core/WorkflowApprovals/WorkflowApprovals.csproj" />
11+
<Project Path="Examples/Governance/ApprovalWorkflow/ApprovalWorkflow.csproj" />
12+
<Project Path="Examples/Governance/DecisionTaxonomy/DecisionTaxonomy.csproj" />
1113
<Project Path="Examples/Governance/RequestLifecycle/RequestLifecycle.csproj" />
1214
<Project Path="Examples/Governance/VersionedResolution/VersionedResolution.csproj" />
1315
</Folder>

‎src/Governance/README.md‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ The core package stays responsible for direct mutation execution. Governance bui
99
- **Mutation Requests** - model governed mutation submission as a durable request
1010
- **Pending Lifecycle** - represent requests that cannot execute immediately
1111
- **Decision History** - record approvals, rejections, cancellations, and other lifecycle transitions
12+
- **Approval Workflow** - model request-level approval requirements and explicit approver actions
1213
- **Request Storage Contracts** - define a persistence seam for governance-oriented stores
1314
- **Runtime Lifecycle Management** - move requests through pending, approval, expiration, and execution transitions
1415
- **In-Memory Runtime Support** - provide lightweight request runtime services for development and tests
@@ -20,6 +21,7 @@ The core package stays responsible for direct mutation execution. Governance bui
2021
The package defines governance-first abstractions under:
2122

2223
- `Abstractions/Requests`
24+
- `Abstractions/Approval`
2325
- `Abstractions/Lifecycle`
2426
- `Abstractions/Storage`
2527
- `Abstractions/Resolution`
@@ -28,31 +30,85 @@ The package defines governance-first abstractions under:
2830
Key types:
2931

3032
- `MutationRequest`
33+
- `MutationApprovalRequirement`
34+
- `MutationApprovalRequirementStatus`
3135
- `MutationRequestDecision`
3236
- `MutationRequestDecisionType`
37+
- `MutationRequestDecisionCategory`
38+
- `MutationRequestLifecycleDecisionType`
39+
- `MutationRequestApprovalDecisionType`
40+
- `MutationRequestVersionResolutionDecisionType`
3341
- `MutationRequestStatus`
3442
- `PendingMutationReason`
3543
- `IMutationRequestStore`
44+
- `IMutationRequestApprovalWorkflowManager`
3645
- `IMutationRequestLifecycleManager`
3746
- `IMutationRequestVersionResolver`
3847
- `IMutationRequestVersionResolutionManager`
3948
- `MutationRequestVersionResolution`
4049
- `MutationRequestVersionResolutionOutcome`
4150
- `VersionedRequestResolutionStrategy`
4251
- `MutationRequestAlreadyExistsException`
52+
- `MutationApprovalRequirementNotFoundException`
53+
- `InvalidMutationApprovalActionException`
4354
- `MutationRequestConcurrencyException`
4455
- `MutationRequestNotFoundException`
4556
- `InvalidMutationRequestTransitionException`
4657

58+
`Abstractions/Requests` is further split into:
59+
60+
- `Requests/Model`
61+
- `Requests/Decisions`
62+
63+
`Abstractions/Approval` is further split into:
64+
65+
- `Approval/Contracts`
66+
- `Approval/Model`
67+
- `Approval/Mapping`
68+
69+
`Abstractions/Resolution` is further split into:
70+
71+
- `Resolution/Contracts`
72+
- `Resolution/Model`
73+
- `Resolution/Strategies`
74+
75+
`Abstractions/Lifecycle` is further split into:
76+
77+
- `Lifecycle/Contracts`
78+
- `Lifecycle/Model`
79+
80+
`Abstractions/Exceptions` is further split into:
81+
82+
- `Exceptions/Approval`
83+
- `Exceptions/Lifecycle`
84+
- `Exceptions/Storage`
85+
4786
### Runtime
4887

4988
The initial runtime layer currently provides:
5089

5190
- `Runtime/Storage/InMemoryMutationRequestStore`
91+
- `Runtime/Approval/MutationRequestApprovalWorkflowManager`
5292
- `Runtime/Lifecycle/MutationRequestLifecycleManager`
5393
- `Runtime/Resolution/MutationRequestVersionResolver`
5494
- `Runtime/Resolution/MutationRequestVersionResolutionManager`
5595

96+
`Runtime/Resolution` is further split into:
97+
98+
- `Resolution/Evaluation`
99+
- `Resolution/Execution`
100+
101+
`Runtime/Lifecycle` is further split into:
102+
103+
- `Lifecycle/Execution`
104+
- `Lifecycle/Validation`
105+
- `Lifecycle/State`
106+
107+
`Runtime/Approval` is further split into:
108+
109+
- `Approval/Execution`
110+
- `Approval/State`
111+
56112
This keeps the first version small while leaving room for later persistence providers such as Entity Framework Core or PostgreSQL-backed governance stores.
57113

58114
## Relationship to Core

0 commit comments

Comments
 (0)