Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions .github/workflows/publish-artifacts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ permissions:

jobs:
package:
name: Pack library
name: Pack packages
runs-on: ubuntu-latest

steps:
Expand All @@ -26,7 +26,7 @@ jobs:
dotnet-version: 10.0.x

- name: Restore
run: dotnet restore src/ModularityKit.Mutator.csproj
run: dotnet restore ModularityKit.Mutator.slnx

- name: Resolve package version
id: version
Expand All @@ -44,16 +44,24 @@ jobs:
fi
echo "package_version=$version" >> "$GITHUB_OUTPUT"

- name: Pack package
- name: Pack core package
run: >
dotnet pack src/ModularityKit.Mutator.csproj
-c Release
--no-restore
-o nupkg
-p:PackageVersion=${{ steps.version.outputs.package_version }}

- name: Upload package
- name: Pack governance package
run: >
dotnet pack src/ModularityKit.Mutator.Governance.csproj
-c Release
--no-restore
-o nupkg
-p:PackageVersion=${{ steps.version.outputs.package_version }}

- name: Upload packages
uses: actions/upload-artifact@v4
with:
name: ModularityKit.Mutator-nupkg
name: ModularityKit-packages
path: nupkg/*.nupkg
2 changes: 1 addition & 1 deletion .github/workflows/publish-attested.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Download published artifacts
uses: actions/download-artifact@v6
with:
pattern: ModularityKit.Mutator-nupkg
pattern: ModularityKit-packages
path: dist
merge-multiple: true

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-drafter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
- name: Download published artifacts
uses: actions/download-artifact@v6
with:
pattern: ModularityKit.Mutator-nupkg
pattern: ModularityKit-packages
path: dist
merge-multiple: true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#adr_023

## Status
Proposed
Accepted

## Date
2026-06-21
Expand Down Expand Up @@ -33,19 +33,33 @@ This is a governance concern, not just a core mutation concern, because it only

## Decision

The governance package should adopt explicit version-aware request resolution semantics.

Expected direction:
The governance package adopts explicit version-aware request resolution semantics.

- `MutationRequest` keeps an `ExpectedStateVersion`
- request resolution must compare current state version with expected version
- stale requests must not silently execute without an explicit rule
- runtime resolution should choose among:
- re-validate and execute against latest state
- reject as stale
- require renewed approval

The exact resolution policy is intentionally left open for the first runtime implementation.
- request resolution compares current state version with expected version
- stale requests do not silently execute
- governance runtime resolves stale requests through one of three explicit strategies:
- `RejectStale`
- `RequireRenewedApproval`
- `RevalidateOnLatestState`

Current runtime contract:

- matching version, or no expected version:
- request receives `VersionValidated`
- outcome is `ExecuteApprovedVersion`
- stale request with `RejectStale`:
- request becomes `Rejected`
- request receives `RejectedAsStale`
- stale request with `RequireRenewedApproval`:
- request returns to `Pending`
- `PendingReason` becomes `Approval`
- `ExpectedStateVersion` is updated to the current version
- request receives `RenewedApprovalRequired`
- stale request with `RevalidateOnLatestState`:
- request stays `Approved`
- `ExpectedStateVersion` is updated to the current version
- request receives `RevalidationRequired`

## Design Rationale

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

### Positive

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

### Negative

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

## Related ADRs

- ADR-020: Governance MutationRequest Model
- ADR-021: Governance Pending Mutation Lifecycle
- ADR-022: Governance Request Decisions and Storage
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# ADR-024: Governance Runtime Pending Request Handling

## Tag
#adr_024

## Status
Accepted

## Date
2026-06-22

## Scope
ModularityKit.Mutator.Governance.Runtime

## Context

The governance package already defines:

- `MutationRequest`
- `MutationRequestStatus`
- `PendingMutationReason`
- `MutationRequestDecision`
- `IMutationRequestStore`

That gives the package a request model, but not yet a runtime lifecycle.

To become operational, governance must handle requests that stay pending over time instead of treating them as static records. This includes:

- entering pending state
- canceling pending requests
- expiring pending requests
- superseding older requests
- listing and resolving pending requests

Without this runtime layer, governance remains only a set of abstractions and cannot drive actual request lifecycle flows.

## Decision

The governance package should introduce first-class runtime handling for pending mutation requests.

Expected direction:

- a governance runtime service should own pending request transitions
- pending transitions must be recorded through `MutationRequestDecision`
- expiration and cancellation must be explicit runtime actions
- pending requests must remain queryable by status and pending reason
- the runtime must not collapse pending state into ordinary mutation failure semantics

The first implementation uses:

- `IMutationRequestLifecycleManager` as the runtime transition contract
- `MutationRequestLifecycleManager` as the default runtime implementation
- explicit `MutationRequestDecision` entries for pending, approval, rejection, cancellation, expiration, superseding, and execution transitions
- `IMutationRequestStore.GetPendingByStateIdAsync(...)` for listing pending requests by state and reason

## Design Rationale

- The model already distinguishes request lifecycle from direct execution.
- Pending execution is central to governance and should be handled explicitly.
- Runtime transitions should remain inside the governance package instead of leaking into the core mutation engine.

## Consequences

### Positive

- Governance can evolve from static request records into a real deferred execution runtime.
- Future approval, scheduling, and external check flows can share one pending lifecycle engine.

### Negative

- This introduces a new runtime layer with state transition rules that need consistent enforcement.
- The first implementation must define carefully which transitions are allowed from each status.

## Related ADRs

- ADR-020: Governance MutationRequest Model
- ADR-021: Governance Pending Mutation Lifecycle
- ADR-022: Governance Request Decisions and Storage
67 changes: 67 additions & 0 deletions Docs/Decision/Adr/ADR_025_Governance_Approval_Workflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# ADR-025: Governance Approval Workflow

## Tag
#adr_025

## Status
Proposed

## Date
2026-06-22

## Scope
ModularityKit.Mutator.Governance

## Context

The core mutation model already supports `PolicyRequirement`, and the governance package already introduces pending mutation requests.

What is still missing is the explicit approval flow that connects both concepts:

- a mutation request enters `PendingApproval`
- request-level requirements become visible and durable
- approvers can approve or reject
- decisions become part of request history
- approved requests move toward execution

Without this workflow, approval remains only a modeled intention and not an executable governance capability.

## Decision

The governance package should implement approval as a first-class specialization of pending request lifecycle.

Expected direction:

- `PolicyRequirement` should map into request-level approval requirements
- approval should not be represented only as a policy denial outcome
- approval and rejection must be explicit governance actions
- approval decisions must be recorded through `MutationRequestDecision`
- approved requests must have a defined path toward execution
- rejected requests must transition into a terminal governed status

Multi-step and multi-actor approvals should be supported by the model, even if the first runtime implementation starts with a simpler flow.

## Design Rationale

- Approval is one of the main reasons to introduce governance separately from core runtime.
- The request model already provides the right seam for deferred approval-based execution.
- Approval should build on pending lifecycle rather than creating a parallel flow model.

## Consequences

### Positive

- Governance gains a real approval process instead of a placeholder concept.
- Request history becomes meaningful for approval-driven changes.
- Future integrations with identity, ticketing, or compliance systems have a natural workflow hook.

### Negative

- Approval introduces additional lifecycle complexity and version-drift concerns.
- The runtime must define how approved requests behave when state has changed since submission.

## Related ADRs

- ADR-021: Governance Pending Mutation Lifecycle
- ADR-023: Governance Versioned Request Resolution
- ADR-024: Governance Runtime Pending Request Handling
67 changes: 67 additions & 0 deletions Docs/Decision/Adr/ADR_026_Governance_Request_Query_API.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# ADR-026: Governance Request Query API

## Tag
#adr_026

## Status
Proposed

## Date
2026-06-22

## Scope
ModularityKit.Mutator.Governance

## Context

The governance package is moving toward durable request lifecycle, approval history, and future persistence providers.

Point lookups by request id are not enough for operational governance scenarios. Users need queries such as:

- all pending approvals
- requests for a given state
- requests by actor
- requests by category or risk level
- requests filtered by tags, metadata, or blast radius
- recent approval decisions

Without a query API, persistence becomes only storage and governance data remains hard to use operationally.

## Decision

The governance package should define a storage-agnostic request query API.

Expected direction:

- expose query-oriented contracts in the governance package
- support filtering by status, pending reason, actor, category, and time range
- support governance-specific filters such as tags, metadata, and blast radius
- support approval-oriented views such as pending approval queues and recent decisions
- keep the query surface provider-neutral so future persistence packages can implement it consistently

The exact query object model is intentionally left open for the first implementation.

## Design Rationale

- Governance data becomes useful only when it is operationally queryable.
- Query semantics should be owned by governance rather than improvised in store implementations.
- A storage-agnostic contract keeps future provider packages aligned.

## Consequences

### Positive

- Governance can support real review and operational workflows.
- Future persistence providers have a clear contract to implement.
- Tags, metadata, and blast radius fields get a practical consumer path.

### Negative

- Query surface design can grow quickly if not kept disciplined.
- Different storage providers may support different performance characteristics for the same filters.

## Related ADRs

- ADR-020: Governance MutationRequest Model
- ADR-022: Governance Request Decisions and Storage
- ADR-023: Governance Versioned Request Resolution
3 changes: 3 additions & 0 deletions Docs/Decision/listadr.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,8 @@ These ADRs describe the `ModularityKit.Mutator.Governance` extension layer and i
| ADR-021 | Governance Pending Mutation Lifecycle | [ADR-021](Adr/ADR_021_Governance_Pending_Mutation_Lifecycle.md) |
| ADR-022 | Governance Request Decisions and Storage | [ADR-022](Adr/ADR_022_Governance_Request_Decisions_and_Storage.md) |
| ADR-023 | Governance Versioned Request Resolution | [ADR-023](Adr/ADR_023_Governance_Versioned_Request_Resolution.md) |
| ADR-024 | Governance Runtime Pending Request Handling | [ADR-024](Adr/ADR_024_Governance_Runtime_Pending_Request_Handling.md) |
| ADR-025 | Governance Approval Workflow | [ADR-025](Adr/ADR_025_Governance_Approval_Workflow.md) |
| ADR-026 | Governance Request Query API | [ADR-026](Adr/ADR_026_Governance_Request_Query_API.md) |

> See individual ADRs for detailed context, decision rationale, and consequences.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\ModularityKit.Mutator.csproj" />
<ProjectReference Include="..\..\..\src\ModularityKit.Mutator.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ It shows:
## Run

```bash
dotnet run --project Examples/BillingQuotas/BillingQuotas.csproj
dotnet run --project Examples/Core/BillingQuotas/BillingQuotas.csproj
```

## Expected output
Expand All @@ -152,4 +152,3 @@ The sample prints:
- aggregate engine statistics

The exact numbers depend on the runtime and any policy thresholds you change.

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\ModularityKit.Mutator.csproj" />
<ProjectReference Include="..\..\..\src\ModularityKit.Mutator.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
File renamed without changes.
Loading
Loading