Skip to content

Commit 645bf7c

Browse files
committed
benchmarks: add governance query
1 parent bff6015 commit 645bf7c

6 files changed

Lines changed: 444 additions & 0 deletions
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using BenchmarkDotNet.Attributes;
2+
using ModularityKit.Mutator.Governance.Abstractions.Queries.Model.Decisions;
3+
using ModularityKit.Mutator.Governance.Abstractions.Queries.Model.Requests;
4+
using ModularityKit.Mutator.Benchmarks.Governance.Queries.Support;
5+
6+
namespace ModularityKit.Mutator.Benchmarks.Governance.Queries;
7+
8+
/// <summary>
9+
/// Benchmarks governance query and read paths in the governance runtime.
10+
/// </summary>
11+
[BenchmarkCategory("Governance")]
12+
[MemoryDiagnoser]
13+
[InProcess]
14+
public class GovernanceQueryReadBenchmarks
15+
{
16+
private GovernanceQueryReadBenchmarkSupport.GovernanceQueryReadBenchmarkFixture _fixture = null!;
17+
18+
/// <summary>
19+
/// Prepares a seeded query store for the read benchmarks.
20+
/// </summary>
21+
[GlobalSetup]
22+
public void Setup()
23+
{
24+
_fixture = GovernanceQueryReadBenchmarkSupport.CreateFixture();
25+
}
26+
27+
/// <summary>
28+
/// Measures listing pending governance requests.
29+
/// </summary>
30+
[Benchmark(Baseline = true)]
31+
public async Task GetPendingRequests()
32+
{
33+
var result = await _fixture.RequestStore.GetPendingRequestsAsync(
34+
MutationRequestQueries.Pending()).ConfigureAwait(false);
35+
36+
GC.KeepAlive(result);
37+
}
38+
39+
/// <summary>
40+
/// Measures listing pending approval queue entries.
41+
/// </summary>
42+
[Benchmark]
43+
public async Task GetPendingApprovalQueue()
44+
{
45+
var result = await _fixture.ApprovalStore.GetPendingApprovalQueueAsync(
46+
MutationRequestQueries.PendingApprovalQueue()).ConfigureAwait(false);
47+
48+
GC.KeepAlive(result);
49+
}
50+
51+
/// <summary>
52+
/// Measures reading recent execution outcome decisions.
53+
/// </summary>
54+
[Benchmark]
55+
public async Task GetRecentExecutionOutcomes()
56+
{
57+
var result = await _fixture.DecisionStore.GetRecentDecisionsAsync(
58+
MutationRequestDecisionQuery.RecentExecutionOutcomes(),
59+
take: 64).ConfigureAwait(false);
60+
61+
GC.KeepAlive(result);
62+
}
63+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using ModularityKit.Mutator.Governance.Runtime.Storage;
2+
3+
namespace ModularityKit.Mutator.Benchmarks.Governance.Queries.Support;
4+
5+
/// <summary>
6+
/// Builds repeatable governance query benchmark fixtures.
7+
/// </summary>
8+
internal static class GovernanceQueryReadBenchmarkSupport
9+
{
10+
/// <summary>
11+
/// Creates a seeded fixture for query and read benchmarks.
12+
/// </summary>
13+
public static GovernanceQueryReadBenchmarkFixture CreateFixture()
14+
=> new(
15+
RequestStore: PendingRequestQueryBenchmarkSeed.CreateStore(),
16+
ApprovalStore: PendingApprovalQueryBenchmarkSeed.CreateStore(),
17+
DecisionStore: RecentDecisionQueryBenchmarkSeed.CreateStore());
18+
19+
/// <summary>
20+
/// Shared fixture for governance query and read scenarios.
21+
/// </summary>
22+
internal sealed record GovernanceQueryReadBenchmarkFixture(
23+
InMemoryMutationRequestStore RequestStore,
24+
InMemoryMutationRequestStore ApprovalStore,
25+
InMemoryMutationRequestStore DecisionStore);
26+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
using ModularityKit.Mutator.Abstractions.Context;
2+
using ModularityKit.Mutator.Abstractions.Intent;
3+
using ModularityKit.Mutator.Abstractions.Policies;
4+
using ModularityKit.Mutator.Governance.Abstractions.Approval.Model;
5+
using ModularityKit.Mutator.Governance.Abstractions.Lifecycle.Model;
6+
using ModularityKit.Mutator.Governance.Abstractions.Requests.Factory;
7+
using ModularityKit.Mutator.Governance.Abstractions.Requests.Model;
8+
using ModularityKit.Mutator.Governance.Runtime.Storage;
9+
10+
namespace ModularityKit.Mutator.Benchmarks.Governance.Queries.Support;
11+
12+
/// <summary>
13+
/// Seeds pending approval queue scenarios.
14+
/// </summary>
15+
internal static class PendingApprovalQueryBenchmarkSeed
16+
{
17+
private static readonly DateTimeOffset BaseTime = new(2026, 6, 1, 14, 0, 0, TimeSpan.Zero);
18+
19+
/// <summary>
20+
/// Creates a store preloaded with pending approval queue and noise data.
21+
/// </summary>
22+
public static InMemoryMutationRequestStore CreateStore()
23+
{
24+
var store = new InMemoryMutationRequestStore();
25+
26+
for (var index = 0; index < 64; index++)
27+
{
28+
var approverId = index % 2 == 0 ? "security-lead" : "platform-lead";
29+
var category = index % 2 == 0 ? "Security" : "Platform";
30+
31+
var request = MutationRequestFactory.PendingApproval(
32+
stateId: "governance-benchmark:query-approval",
33+
stateType: "GovernanceState",
34+
mutationType: "GovernanceBenchmarkApprovalMutation",
35+
intent: CreateIntent(),
36+
context: MutationContext.User("requester", "Requester", "List pending approvals"),
37+
requirements:
38+
[
39+
PolicyRequirement.Approval(approverId, "Benchmark approval")
40+
],
41+
expectedStateVersion: "v10")
42+
with
43+
{
44+
RequestId = $"approval-request-{index:000}",
45+
Lifecycle = new MutationRequestLifecycleDetails
46+
{
47+
Status = MutationRequestStatus.Pending,
48+
PendingReason = PendingMutationReason.Approval,
49+
CreatedAt = BaseTime.AddMinutes(index),
50+
UpdatedAt = BaseTime.AddMinutes(index)
51+
},
52+
ApprovalRequirements =
53+
[
54+
new MutationApprovalRequirement
55+
{
56+
ApproverId = approverId,
57+
ApproverRole = category == "Security" ? "SecurityLead" : "PlatformLead",
58+
ApproverGroup = category.ToLowerInvariant(),
59+
Status = MutationApprovalRequirementStatus.Pending,
60+
StepOrder = 1
61+
}
62+
]
63+
};
64+
65+
store.Create(request).GetAwaiter().GetResult();
66+
}
67+
68+
for (var index = 0; index < 48; index++)
69+
{
70+
var request = new MutationRequest
71+
{
72+
RequestId = $"approval-noise-{index:000}",
73+
Scope = new MutationRequestScopeDetails
74+
{
75+
StateId = "governance-benchmark:query-approval",
76+
StateType = "GovernanceState",
77+
MutationType = "GovernanceBenchmarkCompletedMutation"
78+
},
79+
Payload = new MutationRequestPayloadDetails
80+
{
81+
Intent = CreateIntent("CompletedApprovalNoise", "Completed governance approval noise"),
82+
Context = MutationContext.User("requester", "Requester", "Completed request")
83+
},
84+
Lifecycle = new MutationRequestLifecycleDetails
85+
{
86+
Status = MutationRequestStatus.Approved,
87+
CreatedAt = BaseTime.AddHours(1).AddMinutes(index),
88+
UpdatedAt = BaseTime.AddHours(1).AddMinutes(index + 1)
89+
}
90+
};
91+
92+
store.Create(request).GetAwaiter().GetResult();
93+
}
94+
95+
return store;
96+
}
97+
98+
private static MutationIntent CreateIntent()
99+
=> new()
100+
{
101+
OperationName = "ListPendingApprovals",
102+
Category = "Governance",
103+
Description = "List pending approval queue entries",
104+
RiskLevel = MutationRiskLevel.Low,
105+
IsReversible = true
106+
};
107+
108+
private static MutationIntent CreateIntent(string operationName, string description)
109+
=> new()
110+
{
111+
OperationName = operationName,
112+
Category = "Governance",
113+
Description = description,
114+
RiskLevel = MutationRiskLevel.Low,
115+
IsReversible = true
116+
};
117+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
using ModularityKit.Mutator.Abstractions.Context;
2+
using ModularityKit.Mutator.Abstractions.Intent;
3+
using ModularityKit.Mutator.Abstractions.Policies;
4+
using ModularityKit.Mutator.Governance.Abstractions.Lifecycle.Model;
5+
using ModularityKit.Mutator.Governance.Abstractions.Requests.Factory;
6+
using ModularityKit.Mutator.Governance.Abstractions.Requests.Model;
7+
using ModularityKit.Mutator.Governance.Runtime.Storage;
8+
9+
namespace ModularityKit.Mutator.Benchmarks.Governance.Queries.Support;
10+
11+
/// <summary>
12+
/// Seeds pending request read scenarios.
13+
/// </summary>
14+
internal static class PendingRequestQueryBenchmarkSeed
15+
{
16+
private static readonly DateTimeOffset BaseTime = new(2026, 6, 1, 12, 0, 0, TimeSpan.Zero);
17+
18+
/// <summary>
19+
/// Creates a store preloaded with pending request and noise data.
20+
/// </summary>
21+
public static InMemoryMutationRequestStore CreateStore()
22+
{
23+
var store = new InMemoryMutationRequestStore();
24+
25+
for (var index = 0; index < 96; index++)
26+
{
27+
var request = MutationRequestFactory.Pending(
28+
stateId: "governance-benchmark:query-pending",
29+
stateType: "GovernanceState",
30+
mutationType: "GovernanceBenchmarkMutation",
31+
intent: CreateIntent(),
32+
context: MutationContext.User("requester", "Requester", "List pending governance requests"),
33+
pendingReason: index % 2 == 0
34+
? PendingMutationReason.Approval
35+
: PendingMutationReason.ExternalCheck)
36+
with
37+
{
38+
RequestId = $"pending-request-{index:000}",
39+
Lifecycle = new MutationRequestLifecycleDetails
40+
{
41+
Status = MutationRequestStatus.Pending,
42+
PendingReason = index % 2 == 0
43+
? PendingMutationReason.Approval
44+
: PendingMutationReason.ExternalCheck,
45+
CreatedAt = BaseTime.AddMinutes(index),
46+
UpdatedAt = BaseTime.AddMinutes(index)
47+
}
48+
};
49+
50+
store.Create(request).GetAwaiter().GetResult();
51+
}
52+
53+
for (var index = 0; index < 48; index++)
54+
{
55+
var request = new MutationRequest
56+
{
57+
RequestId = $"completed-request-{index:000}",
58+
Scope = new MutationRequestScopeDetails
59+
{
60+
StateId = "governance-benchmark:query-pending",
61+
StateType = "GovernanceState",
62+
MutationType = "GovernanceBenchmarkCompletedMutation"
63+
},
64+
Payload = new MutationRequestPayloadDetails
65+
{
66+
Intent = CreateIntent("CompletedRequest", "Completed governance request"),
67+
Context = MutationContext.User("requester", "Requester", "Completed request")
68+
},
69+
Lifecycle = new MutationRequestLifecycleDetails
70+
{
71+
Status = index % 3 == 0
72+
? MutationRequestStatus.Approved
73+
: MutationRequestStatus.Executed,
74+
CreatedAt = BaseTime.AddHours(1).AddMinutes(index),
75+
UpdatedAt = BaseTime.AddHours(1).AddMinutes(index + 1)
76+
}
77+
};
78+
79+
store.Create(request).GetAwaiter().GetResult();
80+
}
81+
82+
return store;
83+
}
84+
85+
private static MutationIntent CreateIntent()
86+
=> new()
87+
{
88+
OperationName = "ListPendingRequests",
89+
Category = "Governance",
90+
Description = "List pending governance requests",
91+
RiskLevel = MutationRiskLevel.Low,
92+
IsReversible = true
93+
};
94+
95+
private static MutationIntent CreateIntent(string operationName, string description)
96+
=> new()
97+
{
98+
OperationName = operationName,
99+
Category = "Governance",
100+
Description = description,
101+
RiskLevel = MutationRiskLevel.Low,
102+
IsReversible = true
103+
};
104+
}

0 commit comments

Comments
 (0)