Skip to content

[ENHANCEMENT] Expose mutation actor type to policy consumers #84

Description

@rian-be

Overview

MutationContext currently keeps the actor type as an internal property:

internalActorTypeActorType{get;init;}

This means that consumers of ModularityKit.Mutator cannot determine whether mutation was initiated by a User, Service, or System. This becomes limitation for external mutation policies and governance components that need to make security or authorization decisions based on the mutation execution context.

Problem

The framework already provides explicit actor types through:

MutationContext.System(...)MutationContext.User(...)MutationContext.Service(...)

However, external consumers cannot inspect the resulting actor type. For example, financial ledger application may need to enforce rule such as:

User nitiated mutations must not be allowed to post entries to protected system accounts, while system level mutations may be allowed.

The mutation policy has access to:

mutation.Context

but cannot inspect:

mutation.Context.ActorType

because ActorType is internal.

As a result, consumers may be forced to rely on application specific conventions, such as checking string prefixes:

varisSystemActor=transaction.InitiatedBy.StartsWith("system:",StringComparison.OrdinalIgnoreCase);

This is fragile because domain or audit data should not be used as the authoritative source for mutation authorization decisions.

Proposed solution

Expose the actor type for reading while keeping mutation of the property restricted to the framework.

Change:

internalActorTypeActorType{get;init;}

to:

publicActorTypeActorType{get;internalinit;}

This would allow external consumers to inspect the actor type:

if(mutation.Context.ActorType==ActorType.System){// System level mutation}

while preventing external code from directly assigning the value:

context.ActorType=ActorType.System;// still not allowed

The framework would still retain control over how the actor type is assigned.

Optional convenience API

Alternatively, or in addition, MutationContext could expose convenience properties:

publicboolIsSystemActor=>
ActorType == ActorType.System;publicboolIsUserActor=>
ActorType == ActorType.User;publicboolIsServiceActor=>
ActorType == ActorType.Service;

This would allow policies to express their intent more clearly:

if(!mutation.Context.IsSystemActor){returnPolicyDecision.Deny("Non system actors cannot modify protected accounts.",Name);}

Additional consideration: System actor identity

MutationContext.System() currently creates system context without an ActorId:

MutationContext.System("Post settlement transaction");

Resulting conceptually in:

ActorType = System
ActorId = null

For auditing and governance purposes, it may be useful to identify the specific system component responsible for the mutation. For example:

MutationContext.System(systemId:"ledger-service",reason:"Post settlement transaction");

This would allow downstream consumers to distinguish between different system components while still treating them as system level actors. For example:

ActorType = System
ActorId = ledger-service
Reason = Post settlement transaction

This could be particularly useful in distributed systems where multiple internal services perform mutations.

Expected outcome

External mutation policies should be able to reliably distinguish between:

  • User
  • Service
  • System
  • Unknown

without relying on application specific string conventions or domain data.

This would make MutationContext more useful for:

  • Security policies
  • Authorization decisions
  • Governance rules
  • Audit trails
  • Compliance controls
  • Financial domain policies
  • Multi service mutation workflows

The key principle is that MutationContext should provide the authoritative execution context, while domain entities such as LedgerTransaction should remain responsible for storing audit information about the resulting mutation.

Metadata

Metadata

Assignees

Labels

enhancementNew functionality or behavior

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions