Skip to content

Commit 2c53e29

Browse files
authored
Feat: Add governance runtime foundations and examples (#9)
2 parents b985faa + 24fa1d3 commit 2c53e29

83 files changed

Lines changed: 1499 additions & 78 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.

.github/workflows/publish-artifacts.yml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ permissions:
1313

1414
jobs:
1515
package:
16-
name: Pack library
16+
name: Pack packages
1717
runs-on: ubuntu-latest
1818

1919
steps:
@@ -26,7 +26,7 @@ jobs:
2626
dotnet-version: 10.0.x
2727

2828
- name: Restore
29-
run: dotnet restore src/ModularityKit.Mutator.csproj
29+
run: dotnet restore ModularityKit.Mutator.slnx
3030

3131
- name: Resolve package version
3232
id: version
@@ -44,16 +44,24 @@ jobs:
4444
fi
4545
echo "package_version=$version" >> "$GITHUB_OUTPUT"
4646
47-
- name: Pack package
47+
- name: Pack core package
4848
run: >
4949
dotnet pack src/ModularityKit.Mutator.csproj
5050
-c Release
5151
--no-restore
5252
-o nupkg
5353
-p:PackageVersion=${{ steps.version.outputs.package_version }}
5454
55-
- name: Upload package
55+
- name: Pack governance package
56+
run: >
57+
dotnet pack src/ModularityKit.Mutator.Governance.csproj
58+
-c Release
59+
--no-restore
60+
-o nupkg
61+
-p:PackageVersion=${{ steps.version.outputs.package_version }}
62+
63+
- name: Upload packages
5664
uses: actions/upload-artifact@v4
5765
with:
58-
name: ModularityKit.Mutator-nupkg
66+
name: ModularityKit-packages
5967
path: nupkg/*.nupkg

.github/workflows/publish-attested.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
- name: Download published artifacts
2626
uses: actions/download-artifact@v6
2727
with:
28-
pattern: ModularityKit.Mutator-nupkg
28+
pattern: ModularityKit-packages
2929
path: dist
3030
merge-multiple: true
3131

.github/workflows/release-drafter.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
- name: Download published artifacts
5353
uses: actions/download-artifact@v6
5454
with:
55-
pattern: ModularityKit.Mutator-nupkg
55+
pattern: ModularityKit-packages
5656
path: dist
5757
merge-multiple: true
5858

Docs/Decision/Adr/ADR_023_Governance_Versioned_Request_Resolution.md

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#adr_023
55

66
## Status
7-
Proposed
7+
Accepted
88

99
## Date
1010
2026-06-21
@@ -33,19 +33,33 @@ This is a governance concern, not just a core mutation concern, because it only
3333

3434
## Decision
3535

36-
The governance package should adopt explicit version-aware request resolution semantics.
37-
38-
Expected direction:
36+
The governance package adopts explicit version-aware request resolution semantics.
3937

4038
- `MutationRequest` keeps an `ExpectedStateVersion`
41-
- request resolution must compare current state version with expected version
42-
- stale requests must not silently execute without an explicit rule
43-
- runtime resolution should choose among:
44-
- re-validate and execute against latest state
45-
- reject as stale
46-
- require renewed approval
47-
48-
The exact resolution policy is intentionally left open for the first runtime implementation.
39+
- request resolution compares current state version with expected version
40+
- stale requests do not silently execute
41+
- governance runtime resolves stale requests through one of three explicit strategies:
42+
- `RejectStale`
43+
- `RequireRenewedApproval`
44+
- `RevalidateOnLatestState`
45+
46+
Current runtime contract:
47+
48+
- matching version, or no expected version:
49+
- request receives `VersionValidated`
50+
- outcome is `ExecuteApprovedVersion`
51+
- stale request with `RejectStale`:
52+
- request becomes `Rejected`
53+
- request receives `RejectedAsStale`
54+
- stale request with `RequireRenewedApproval`:
55+
- request returns to `Pending`
56+
- `PendingReason` becomes `Approval`
57+
- `ExpectedStateVersion` is updated to the current version
58+
- request receives `RenewedApprovalRequired`
59+
- stale request with `RevalidateOnLatestState`:
60+
- request stays `Approved`
61+
- `ExpectedStateVersion` is updated to the current version
62+
- request receives `RevalidationRequired`
4963

5064
## Design Rationale
5165

@@ -57,15 +71,18 @@ The exact resolution policy is intentionally left open for the first runtime imp
5771

5872
### Positive
5973

60-
- Governance runtime will have explicit semantics for stale approvals.
74+
- Governance runtime now has explicit semantics for stale approvals.
6175
- Deferred execution becomes safer and more auditable.
76+
- Request decision history reflects stale detection and final resolution path.
6277

6378
### Negative
6479

6580
- This introduces additional policy and runtime complexity.
6681
- Different domains may want different stale resolution strategies.
82+
- Revalidation itself is still a separate runtime step beyond this version-resolution contract.
6783

6884
## Related ADRs
6985

7086
- ADR-020: Governance MutationRequest Model
7187
- ADR-021: Governance Pending Mutation Lifecycle
88+
- ADR-022: Governance Request Decisions and Storage
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# ADR-024: Governance Runtime Pending Request Handling
2+
3+
## Tag
4+
#adr_024
5+
6+
## Status
7+
Accepted
8+
9+
## Date
10+
2026-06-22
11+
12+
## Scope
13+
ModularityKit.Mutator.Governance.Runtime
14+
15+
## Context
16+
17+
The governance package already defines:
18+
19+
- `MutationRequest`
20+
- `MutationRequestStatus`
21+
- `PendingMutationReason`
22+
- `MutationRequestDecision`
23+
- `IMutationRequestStore`
24+
25+
That gives the package a request model, but not yet a runtime lifecycle.
26+
27+
To become operational, governance must handle requests that stay pending over time instead of treating them as static records. This includes:
28+
29+
- entering pending state
30+
- canceling pending requests
31+
- expiring pending requests
32+
- superseding older requests
33+
- listing and resolving pending requests
34+
35+
Without this runtime layer, governance remains only a set of abstractions and cannot drive actual request lifecycle flows.
36+
37+
## Decision
38+
39+
The governance package should introduce first-class runtime handling for pending mutation requests.
40+
41+
Expected direction:
42+
43+
- a governance runtime service should own pending request transitions
44+
- pending transitions must be recorded through `MutationRequestDecision`
45+
- expiration and cancellation must be explicit runtime actions
46+
- pending requests must remain queryable by status and pending reason
47+
- the runtime must not collapse pending state into ordinary mutation failure semantics
48+
49+
The first implementation uses:
50+
51+
- `IMutationRequestLifecycleManager` as the runtime transition contract
52+
- `MutationRequestLifecycleManager` as the default runtime implementation
53+
- explicit `MutationRequestDecision` entries for pending, approval, rejection, cancellation, expiration, superseding, and execution transitions
54+
- `IMutationRequestStore.GetPendingByStateIdAsync(...)` for listing pending requests by state and reason
55+
56+
## Design Rationale
57+
58+
- The model already distinguishes request lifecycle from direct execution.
59+
- Pending execution is central to governance and should be handled explicitly.
60+
- Runtime transitions should remain inside the governance package instead of leaking into the core mutation engine.
61+
62+
## Consequences
63+
64+
### Positive
65+
66+
- Governance can evolve from static request records into a real deferred execution runtime.
67+
- Future approval, scheduling, and external check flows can share one pending lifecycle engine.
68+
69+
### Negative
70+
71+
- This introduces a new runtime layer with state transition rules that need consistent enforcement.
72+
- The first implementation must define carefully which transitions are allowed from each status.
73+
74+
## Related ADRs
75+
76+
- ADR-020: Governance MutationRequest Model
77+
- ADR-021: Governance Pending Mutation Lifecycle
78+
- ADR-022: Governance Request Decisions and Storage
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# ADR-025: Governance Approval Workflow
2+
3+
## Tag
4+
#adr_025
5+
6+
## Status
7+
Proposed
8+
9+
## Date
10+
2026-06-22
11+
12+
## Scope
13+
ModularityKit.Mutator.Governance
14+
15+
## Context
16+
17+
The core mutation model already supports `PolicyRequirement`, and the governance package already introduces pending mutation requests.
18+
19+
What is still missing is the explicit approval flow that connects both concepts:
20+
21+
- a mutation request enters `PendingApproval`
22+
- request-level requirements become visible and durable
23+
- approvers can approve or reject
24+
- decisions become part of request history
25+
- approved requests move toward execution
26+
27+
Without this workflow, approval remains only a modeled intention and not an executable governance capability.
28+
29+
## Decision
30+
31+
The governance package should implement approval as a first-class specialization of pending request lifecycle.
32+
33+
Expected direction:
34+
35+
- `PolicyRequirement` should map into request-level approval requirements
36+
- approval should not be represented only as a policy denial outcome
37+
- approval and rejection must be explicit governance actions
38+
- approval decisions must be recorded through `MutationRequestDecision`
39+
- approved requests must have a defined path toward execution
40+
- rejected requests must transition into a terminal governed status
41+
42+
Multi-step and multi-actor approvals should be supported by the model, even if the first runtime implementation starts with a simpler flow.
43+
44+
## Design Rationale
45+
46+
- Approval is one of the main reasons to introduce governance separately from core runtime.
47+
- The request model already provides the right seam for deferred approval-based execution.
48+
- Approval should build on pending lifecycle rather than creating a parallel flow model.
49+
50+
## Consequences
51+
52+
### Positive
53+
54+
- Governance gains a real approval process instead of a placeholder concept.
55+
- Request history becomes meaningful for approval-driven changes.
56+
- Future integrations with identity, ticketing, or compliance systems have a natural workflow hook.
57+
58+
### Negative
59+
60+
- Approval introduces additional lifecycle complexity and version-drift concerns.
61+
- The runtime must define how approved requests behave when state has changed since submission.
62+
63+
## Related ADRs
64+
65+
- ADR-021: Governance Pending Mutation Lifecycle
66+
- ADR-023: Governance Versioned Request Resolution
67+
- ADR-024: Governance Runtime Pending Request Handling
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# ADR-026: Governance Request Query API
2+
3+
## Tag
4+
#adr_026
5+
6+
## Status
7+
Proposed
8+
9+
## Date
10+
2026-06-22
11+
12+
## Scope
13+
ModularityKit.Mutator.Governance
14+
15+
## Context
16+
17+
The governance package is moving toward durable request lifecycle, approval history, and future persistence providers.
18+
19+
Point lookups by request id are not enough for operational governance scenarios. Users need queries such as:
20+
21+
- all pending approvals
22+
- requests for a given state
23+
- requests by actor
24+
- requests by category or risk level
25+
- requests filtered by tags, metadata, or blast radius
26+
- recent approval decisions
27+
28+
Without a query API, persistence becomes only storage and governance data remains hard to use operationally.
29+
30+
## Decision
31+
32+
The governance package should define a storage-agnostic request query API.
33+
34+
Expected direction:
35+
36+
- expose query-oriented contracts in the governance package
37+
- support filtering by status, pending reason, actor, category, and time range
38+
- support governance-specific filters such as tags, metadata, and blast radius
39+
- support approval-oriented views such as pending approval queues and recent decisions
40+
- keep the query surface provider-neutral so future persistence packages can implement it consistently
41+
42+
The exact query object model is intentionally left open for the first implementation.
43+
44+
## Design Rationale
45+
46+
- Governance data becomes useful only when it is operationally queryable.
47+
- Query semantics should be owned by governance rather than improvised in store implementations.
48+
- A storage-agnostic contract keeps future provider packages aligned.
49+
50+
## Consequences
51+
52+
### Positive
53+
54+
- Governance can support real review and operational workflows.
55+
- Future persistence providers have a clear contract to implement.
56+
- Tags, metadata, and blast radius fields get a practical consumer path.
57+
58+
### Negative
59+
60+
- Query surface design can grow quickly if not kept disciplined.
61+
- Different storage providers may support different performance characteristics for the same filters.
62+
63+
## Related ADRs
64+
65+
- ADR-020: Governance MutationRequest Model
66+
- ADR-022: Governance Request Decisions and Storage
67+
- ADR-023: Governance Versioned Request Resolution

Docs/Decision/listadr.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,8 @@ These ADRs describe the `ModularityKit.Mutator.Governance` extension layer and i
3939
| ADR-021 | Governance Pending Mutation Lifecycle | [ADR-021](Adr/ADR_021_Governance_Pending_Mutation_Lifecycle.md) |
4040
| ADR-022 | Governance Request Decisions and Storage | [ADR-022](Adr/ADR_022_Governance_Request_Decisions_and_Storage.md) |
4141
| ADR-023 | Governance Versioned Request Resolution | [ADR-023](Adr/ADR_023_Governance_Versioned_Request_Resolution.md) |
42+
| ADR-024 | Governance Runtime Pending Request Handling | [ADR-024](Adr/ADR_024_Governance_Runtime_Pending_Request_Handling.md) |
43+
| ADR-025 | Governance Approval Workflow | [ADR-025](Adr/ADR_025_Governance_Approval_Workflow.md) |
44+
| ADR-026 | Governance Request Query API | [ADR-026](Adr/ADR_026_Governance_Request_Query_API.md) |
4245

4346
> See individual ADRs for detailed context, decision rationale, and consequences.

Examples/BillingQuotas/BillingQuotas.csproj renamed to Examples/Core/BillingQuotas/BillingQuotas.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<ProjectReference Include="..\..\src\ModularityKit.Mutator.csproj" />
11+
<ProjectReference Include="..\..\..\src\ModularityKit.Mutator.csproj" />
1212
</ItemGroup>
1313

1414
<ItemGroup>

Examples/BillingQuotas/Mutations/DecreaseQuotaMutation.cs renamed to Examples/Core/BillingQuotas/Mutations/DecreaseQuotaMutation.cs

File renamed without changes.

0 commit comments

Comments
 (0)