Skip to content

Commit 6efe165

Browse files
committed
Feat: Introduce governance package and execution model
Added - Separate package under - Governance abstractions for mutation requests, lifecycle, request decisions, and request storage - In-memory governance request store for development and tests - ADR set for governance package boundaries and request lifecycle concepts - Roadmap and execution model documents for governance evolution Changed - Solution now includes the governance package alongside the core runtime - Core project excludes governance sources to preserve package boundaries - Repository documentation now describes the split between core runtime and governance extension - ADR index is split between core and governance decisions Result The repository now has a clear architectural seam between direct mutation execution and governed mutation request lifecycle work, so future approval and pending execution features can evolve without bloating the core package.
1 parent 8de3a67 commit 6efe165

20 files changed

Lines changed: 1238 additions & 0 deletions
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# ADR-019: Governance Package Separation
2+
3+
## Tag
4+
#adr_019
5+
6+
## Status
7+
Accepted
8+
9+
## Date
10+
2026-06-21
11+
12+
## Scope
13+
ModularityKit.Mutator
14+
ModularityKit.Mutator.Governance
15+
16+
## Context
17+
18+
`ModularityKit.Mutator` started as focused mutation runtime:
19+
20+
- mutation execution
21+
- policy evaluation
22+
- audit and history basics
23+
- side effects
24+
- metrics and interception
25+
26+
At the same time, the roadmap and emerging API gaps point toward broader governance model:
27+
28+
- mutation requests
29+
- pending execution lifecycle
30+
- approval workflows
31+
- version aware deferred execution
32+
- governance-specific persistence and query capabilities
33+
- compensation and resolution flows
34+
35+
Those concerns are related to mutation execution, but they are not the same layer.
36+
37+
If they are added directly into the core package, the main risk is that `ModularityKit.Mutator` turns from lightweight mutation runtime into heavy workflow and governance framework. That would make the core package harder to understand, harder to keep small, and harder to adopt for users who only need deterministic mutation execution.
38+
39+
## Decision
40+
41+
- Keep `ModularityKit.Mutator` as the core execution package.
42+
- Introduce `ModularityKit.Mutator.Governance` as separate package in the same repository.
43+
- Place governance specific abstractions and runtime components under the governance package rather than in the core runtime.
44+
- Keep both packages in one repository for now, with separate project files and separate package boundaries.
45+
46+
Current package split:
47+
48+
### Core: `ModularityKit.Mutator`
49+
50+
Responsible for:
51+
52+
- mutation execution
53+
- policy evaluation
54+
- audit and history basics
55+
- side effects
56+
- metrics
57+
- interceptor pipeline
58+
59+
### Extension: `ModularityKit.Mutator.Governance`
60+
61+
Responsible for:
62+
63+
- `MutationRequest`
64+
- pending mutation lifecycle
65+
- request decisions and resolution
66+
- approval-oriented contracts
67+
- governance request storage contracts
68+
69+
## Design Rationale
70+
71+
- Preserves small and execution focused core package.
72+
- Allows governance to evolve at different pace than the core runtime.
73+
- Makes governance an opt in capability instead of default weight for all users.
74+
- Keeps repo level development simple by avoiding an early split into multiple repositories.
75+
- Provides a clean place for future packages such as persistence providers without polluting the core runtime surface.
76+
77+
## Consequences
78+
79+
### Positive
80+
81+
- The mutation engine stays focused on direct execution concerns.
82+
- Governance can grow into a richer model without forcing all consumers to adopt it.
83+
- Future packages such as `EntityFrameworkCore` or `PostgreSql` governance providers have natural home.
84+
- The repository structure now reflects the architectural boundary explicitly.
85+
86+
### Negative
87+
88+
- Some concepts will span package boundaries and require careful API ownership.
89+
- Documentation must explain clearly when a feature belongs to core versus governance.
90+
- Cross-package evolution will need discipline to avoid circular design pressure.
91+
92+
## Follow up
93+
94+
- Keep new governance runtime features out of `ModularityKit.Mutator` unless they are fundamental to direct execution.
95+
- Grow pending lifecycle, approval flow, and request storage inside `ModularityKit.Mutator.Governance`.
96+
- Revisit repo/package boundaries only if governance becomes large enough to justify separate repository in the future.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# ADR-020: Governance MutationRequest Model
2+
3+
## Tag
4+
#adr_020
5+
6+
## Status
7+
Accepted
8+
9+
## Date
10+
2026-06-21
11+
12+
## Scope
13+
ModularityKit.Mutator.Governance.Abstractions
14+
15+
## Context
16+
17+
The governance layer needs primary unit that can represent more than direct mutation execution.
18+
19+
Core runtime mutations are immediate execution objects. Governance needs model that can survive over time and carry:
20+
21+
- request identity
22+
- state targeting
23+
- mutation classification
24+
- request context
25+
- pending requirements
26+
- request decisions
27+
- version expectations
28+
29+
Without such a model, deferred execution would have to be represented through ad hoc flags on mutation results, which is too weak for approval, expiration, cancellation, and re-resolution scenarios.
30+
31+
## Decision
32+
33+
- Introduce `MutationRequest` as the primary governance aggregate.
34+
- `MutationRequest` carries:
35+
- `RequestId`
36+
- `StateId`
37+
- `StateType`
38+
- `MutationType`
39+
- `Intent`
40+
- `Context`
41+
- `Status`
42+
- `PendingReason`
43+
- `Requirements`
44+
- `Decisions`
45+
- `ExpectedStateVersion`
46+
- `ExpiresAt`
47+
- `CreatedAt`
48+
- `UpdatedAt`
49+
- request-level `Metadata`
50+
- Provide factory methods for:
51+
- `Pending(...)`
52+
- `Approved(...)`
53+
54+
## Design Rationale
55+
56+
- Gives governance durable model that is distinct from direct mutation execution.
57+
- Keeps request lifecycle concerns out of the core `MutationResult`.
58+
- Preserves enough context to support future approval, persistence, and re-execution flows.
59+
- Makes version-aware deferred execution possible without leaking governance concerns into the core package.
60+
61+
## Consequences
62+
63+
### Positive
64+
65+
- Governance now has clear primary aggregate.
66+
- Future approval and pending lifecycle features have stable model to build on.
67+
- Request level persistence and query APIs have a natural root entity.
68+
69+
### Negative
70+
71+
- Some mutation data is now represented in both core and governance layers, with different purposes.
72+
- Governance logic will need discipline to avoid turning `MutationRequest` into an unbounded bag of state.
73+
74+
## Related ADRs
75+
76+
- ADR-019: Governance Package Separation
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# ADR-021: Governance Pending Mutation Lifecycle
2+
3+
## Tag
4+
#adr_021
5+
6+
## Status
7+
Accepted
8+
9+
## Date
10+
2026-06-21
11+
12+
## Scope
13+
ModularityKit.Mutator.Governance.Abstractions
14+
15+
## Context
16+
17+
Not every governed mutation should execute immediately.
18+
19+
Governance needs an explicit lifecycle for requests that are:
20+
21+
- waiting for approval
22+
- blocked on external checks
23+
- delayed by scheduling
24+
- waiting on dependencies
25+
- held for quota or manual review
26+
27+
If pending execution is represented only as denial or boolean flag, the runtime cannot express expiration, cancellation, superseding, or eventual execution.
28+
29+
## Decision
30+
31+
- Introduce `MutationRequestStatus` as the lifecycle status enum for governed requests.
32+
- Supported statuses:
33+
- `Created`
34+
- `Pending`
35+
- `Approved`
36+
- `Rejected`
37+
- `Canceled`
38+
- `Expired`
39+
- `Superseded`
40+
- `Executed`
41+
- Introduce `PendingMutationReason` to explain why a request is pending.
42+
- Supported pending reasons:
43+
- `Approval`
44+
- `ExternalCheck`
45+
- `Schedule`
46+
- `Dependency`
47+
- `Quota`
48+
- `ManualReview`
49+
50+
## Design Rationale
51+
52+
- Separates lifecycle state from lifecycle cause.
53+
- Makes pending execution first class governance concept instead of terminal failure state.
54+
- Supports future query APIs such as “all pending approvals” or “all expired requests”.
55+
- Allows approval flow to be one specialization of pending execution, rather than the only pending model.
56+
57+
## Consequences
58+
59+
### Positive
60+
61+
- Governance can represent deferred execution explicitly.
62+
- Approval workflows, external checks, and scheduling can share one lifecycle model.
63+
- Future persistence and query layers have stable status dimensions to index.
64+
65+
### Negative
66+
67+
- Lifecycle semantics now need to be enforced consistently in runtime logic that does not exist yet.
68+
- Some statuses, especially `Superseded` and `Executed`, will require careful definition once version-aware execution is implemented.
69+
70+
## Related ADRs
71+
72+
- ADR-019: Governance Package Separation
73+
- ADR-020: Governance MutationRequest Model
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# ADR-022: Governance Request Decisions and Storage
2+
3+
## Tag
4+
#adr_022
5+
6+
## Status
7+
Accepted
8+
9+
## Date
10+
2026-06-21
11+
12+
## Scope
13+
ModularityKit.Mutator.Governance.Abstractions
14+
ModularityKit.Mutator.Governance.Runtime
15+
16+
## Context
17+
18+
Once mutation requests become durable governance objects, they need:
19+
20+
- a history of lifecycle decisions
21+
- a storage contract
22+
- a minimal runtime implementation for local development and tests
23+
24+
Without decisions, the request only shows current state and loses governance history.
25+
Without a store contract, governance cannot grow into persistence or query features.
26+
27+
## Decision
28+
29+
- Introduce `MutationRequestDecision` as the record of lifecycle transition or governance action.
30+
- Introduce `MutationRequestDecisionType` with:
31+
- `Submitted`
32+
- `Approved`
33+
- `Rejected`
34+
- `Canceled`
35+
- `Expired`
36+
- `Superseded`
37+
- `Executed`
38+
- Introduce `IMutationRequestStore` with operations for:
39+
- storing request
40+
- retrieving by request id
41+
- retrieving by state id
42+
- retrieving pending requests
43+
- Provide `InMemoryMutationRequestStore` as the first runtime implementation.
44+
45+
## Design Rationale
46+
47+
- Keeps current request state and decision history together at the model level.
48+
- Establishes a storage seam before adding provider specific persistence packages.
49+
- Mirrors the existing core approach of starting with in-memory runtime implementations before introducing durable adapters.
50+
51+
## Consequences
52+
53+
### Positive
54+
55+
- Governance now has durable decision log model.
56+
- The storage contract is in place for future provider packages.
57+
- Examples, tests, and local runtime flows can use `InMemoryMutationRequestStore` immediately.
58+
59+
### Negative
60+
61+
- Decision history and current status can drift if future runtime transitions are not applied carefully.
62+
- Query capabilities are still minimal and intentionally incomplete at this stage.
63+
64+
## Related ADRs
65+
66+
- ADR-019: Governance Package Separation
67+
- ADR-020: Governance MutationRequest Model
68+
- ADR-021: Governance Pending Mutation Lifecycle
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# ADR-023: Governance Versioned Request Resolution
2+
3+
## Tag
4+
#adr_023
5+
6+
## Status
7+
Proposed
8+
9+
## Date
10+
2026-06-21
11+
12+
## Scope
13+
ModularityKit.Mutator.Governance
14+
15+
## Context
16+
17+
Pending mutation requests may be resolved long after they were created.
18+
19+
Example:
20+
21+
- request created against state version `v10`
22+
- request enters `PendingApproval`
23+
- approval happens after the state has advanced to `v15`
24+
25+
At that point, governance must define what approval means:
26+
27+
- execute against the latest state
28+
- reject as stale
29+
- require re-approval
30+
- attempt re-validation and branch from there
31+
32+
This is a governance concern, not just a core mutation concern, because it only appears once requests can survive beyond immediate execution.
33+
34+
## Decision
35+
36+
The governance package should adopt explicit version-aware request resolution semantics.
37+
38+
Expected direction:
39+
40+
- `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.
49+
50+
## Design Rationale
51+
52+
- Approval and deferred execution are not safe without explicit state version semantics.
53+
- Silent execution on drifted state would weaken governance guarantees.
54+
- The model already contains the right seam through `ExpectedStateVersion`.
55+
56+
## Consequences
57+
58+
### Positive
59+
60+
- Governance runtime will have explicit semantics for stale approvals.
61+
- Deferred execution becomes safer and more auditable.
62+
63+
### Negative
64+
65+
- This introduces additional policy and runtime complexity.
66+
- Different domains may want different stale resolution strategies.
67+
68+
## Related ADRs
69+
70+
- ADR-020: Governance MutationRequest Model
71+
- ADR-021: Governance Pending Mutation Lifecycle

0 commit comments

Comments
 (0)