FabricOrg.Platform.Testing 1.4.0

dotnet add package FabricOrg.Platform.Testing --version 1.4.0
                    
NuGet\Install-Package FabricOrg.Platform.Testing -Version 1.4.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="FabricOrg.Platform.Testing" Version="1.4.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FabricOrg.Platform.Testing" Version="1.4.0" />
                    
Directory.Packages.props
<PackageReference Include="FabricOrg.Platform.Testing" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add FabricOrg.Platform.Testing --version 1.4.0
                    
#r "nuget: FabricOrg.Platform.Testing, 1.4.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package FabricOrg.Platform.Testing@1.4.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=FabricOrg.Platform.Testing&version=1.4.0
                    
Install as a Cake Addin
#tool nuget:?package=FabricOrg.Platform.Testing&version=1.4.0
                    
Install as a Cake Tool

FabricOrg.Platform

TypeScript is the reference governance contract. FabricOrg.Platform.Host persists GovernanceRuntimeEvidence on each new invocation so operators can identify the exact governance, Host, provider bridge, and policy generations that authorized a historical mutation. C# tests run the language-neutral fixture vendored under contracts/fabric-family, while the shared CI action requires it to remain byte-identical to Platform's canonical copy.

A governance kernel for .NET that enforces a single, auditable mutation pipeline for every domain state change. Every write flows through one canonical door (IActionRuntime.InvokeAsync), producing an immutable audit trail of ActionInvocation, PolicyEvaluation, and AssetEvent records.

This is the .NET-native port of the TypeScript @fabricorg/platform governance framework. It targets .NET Standard 2.1 for broad compatibility and integrates seamlessly with Microsoft Orleans, ASP.NET Core, and vanilla .NET applications.


Packages

Package Description Target
FabricOrg.Platform Core runtime — action pipeline, policy engine, state machines, event sourcing netstandard2.1
FabricOrg.Platform.Abstractions Interfaces and types — referenced by vertical modules netstandard2.1
FabricOrg.Platform.DependencyInjection IServiceCollection extensions netstandard2.1
FabricOrg.Platform.FluentValidation FluentValidation → ISchemaValidator bridge netstandard2.1
FabricOrg.Platform.Host Durable host — PostgreSQL, recovery, HITL, obligations, attestations, reconciliation net8.0
FabricOrg.Platform.Orleans Orleans grain base classes and interceptors netstandard2.1
FabricOrg.Platform.Polly Polly-based retry and circuit-breaker netstandard2.1
FabricOrg.Platform.Policies.OpenPolicyAgent OPA (Open Policy Agent) integration netstandard2.1
FabricOrg.Platform.Sdk HTTP SDK for external consumers netstandard2.1
FabricOrg.Platform.Analyzers Roslyn analyzers — development dependency only netstandard2.0

Quick Start

1. Install Packages

dotnet add package FabricOrg.Platform
dotnet add package FabricOrg.Platform.DependencyInjection
dotnet add package FabricOrg.Platform.FluentValidation
dotnet add package FabricOrg.Platform.Host
dotnet add package FabricOrg.Platform.Analyzers  # Dev dependency

2. Define a Module

public class LendingModule : IFabricModule<AppDbContext>
{
    public string Namespace => "lending";
    public string DisplayName => "Lending";

    public IReadOnlyList<ActionDefinition<AppDbContext>> Actions => new[]
    {
        new ActionDefinition<AppDbContext>
        {
            ActionId = ActionId.Parse("lending.accept_offer"),
            Namespace = "lending",
            Version = 1,
            Schema = new FluentValidationSchemaValidator(new AcceptOfferValidator()),
            Handler = AcceptOfferHandler.ExecuteAsync,
            RequiredRoles = new[] { "loan_consultant", "underwriter" },
            RequiredPermissions = new[] { "lending.offer.accept" },
            EmitsEvents = new[] { "OfferAccepted", "StateTransitioned" },
            Idempotent = true,
            MutatesDomain = true,
            StateMachine = new ActionStateMachineBinding(
                EntityType: "Offer",
                TargetStateResolver: p => "accepted",
                EntityIdResolver: p => ((AcceptOfferCommand)p).OfferId)
        }
    };

    public IReadOnlyList<StateMachineDefinition> StateMachines => new[]
    {
        new StateMachineDefinition(
            EntityType: "Offer",
            States: new Dictionary<string, StateDefinition>
            {
                ["generated"] = new("generated", "Generated", StateClass.Initial),
                ["presented"] = new("presented", "Presented", StateClass.Active),
                ["accepted"] = new("accepted", "Accepted", StateClass.Terminal),
                ["declined"] = new("declined", "Declined", StateClass.Terminal),
                ["expired"] = new("expired", "Expired", StateClass.Terminal)
            },
            Transitions: new[]
            {
                new StateTransition("generated", "presented", ActionId.Parse("lending.present_offer")),
                new StateTransition("presented", "accepted", ActionId.Parse("lending.accept_offer")),
                new StateTransition("presented", "declined", ActionId.Parse("lending.decline_offer")),
                new StateTransition("presented", "expired", ActionId.Parse("lending.expire_offer"))
            })
    };

    // ... policies, events, adapters
}

3. Register in Program.cs

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddFabricGovernance<AppDbContext>(options =>
{
    options.ValidateModulesOnStartup = true;
    options.EnforceBoundaryChecks = true;
});

builder.Services.AddFabricModule(new LendingModule());

// Optional: override with Orleans, Temporal, etc.
// builder.Services.WithSagaOrchestrator<TemporalSagaOrchestrator>();
// builder.Services.WithAsyncJobDispatcher<TemporalJobDispatcher>();

var app = builder.Build();

4. Invoke an Action

public class OffersController : ControllerBase
{
    private readonly IActionRuntime _runtime;
    private readonly AppDbContext _db;

    public OffersController(IActionRuntime runtime, AppDbContext db)
    {
        _runtime = runtime;
        _db = db;
    }

    [HttpPost("{offerId}/accept")]
    public async Task<IActionResult> Accept(string offerId)
    {
        var result = await _runtime.InvokeAsync(new InvokeActionRequest(
            ActionId.Parse("lending.accept_offer"),
            new Dictionary<string, object?> { ["offerId"] = offerId },
            User.Identity.Name!,
            ActorType.NaturalPerson,
            tenantId: "tenant_123",
            spaceId: "space_456"
        ), _db);

        return result.Status == ActionStatus.Completed
            ? Ok(result)
            : BadRequest(result);
    }
}

5. Orleans Integration

public class OfferGrain : GovernedGrain<IOfferRepository>, IOfferGrain
{
    public OfferGrain(IActionRuntime runtime, IOfferRepository db) : base(runtime, db) { }

    public async Task<Result> AcceptAsync(AcceptOfferCommand command, ActorContext actor)
    {
        var result = await InvokeActionAsync(new InvokeActionRequest(
            ActionId.Parse("lending.accept_offer"),
            command.ToDictionary(),
            actor.ActorId,
            actor.ActorType,
            actor.TenantId,
            actor.SpaceId
        ));

        return result.Status == ActionStatus.Completed
            ? Result.Success()
            : Result.Failure(result.Error);
    }
}

Architecture

┌─────────────────────────────────────────────────────────────┐
│  SaaS UI  │  Borrower Portal  │  Temporal Cron  │  Agent   │
└────┬────────────┬─────────────────┬───────────────┬─────────┘
     │            │                 │               │
     │  natural_person   external_system   system    agent
     │            │                 │               │
     ▼            ▼                 ▼               ▼
┌─────────────────────────────────────────────────────────────┐
│              API Layer (Host Application)                   │
│  • IActionRuntime.InvokeAsync                               │
│  • IActionRuntime.PreviewAsync                              │
└────────────────────────┬────────────────────────────────────┘
                         │
                         ▼
         ┌───────────────────────────────┐
         │  FabricOrg.Platform Runtime   │
         │  - Module entitlement check   │
         │  - Permission check (HITL)    │
         │  - Create ActionInvocation    │
         │  - Policy evaluation          │
         │  - State machine validation   │
         │  - Execute handler (TDb txn)  │
         │  - Append AssetEvent          │
         │  - Execute adapters           │
         └───────────────────────────────┘
                         │
                         ▼
         ┌───────────────────────────────┐
         │  Vertical Handlers (lending)  │
         │  e.g. acceptOfferHandler      │
         └───────────────────────────────┘

Governance Capabilities

  • Single Mutation Path — All domain writes flow through IActionRuntime.InvokeAsync. Boundary analyzers enforce this at compile time.
  • Policy Engine — Code policies (C# evaluators), data policies (declarative condition trees), and hybrid policies with full PolicyDispatchEvidence audit.
  • State Machines — Declarative transition graphs with guards. Invalid transitions are blocked before handlers run.
  • Audit Trail — Immutable ActionInvocation, PolicyEvaluation, and AssetEvent records with correlation IDs.
  • Adapter Orchestration — Retry, circuit breaker, and dead-letter queue for external service calls.
  • Agent HITL — Human-in-the-loop policy routing for AI agents (auto-execute, needs-approval, escalate, rejected).
  • Durable Host — FabricOrg.Platform.Host provides the canonical invocation ledger, PostgreSQL persistence, worker recovery, idempotency, redaction, exact HITL approval resume, external mutation footprints, delegated principals, policy obligations, execution attestations, and reconciliation evidence used by vertical applications.
  • Privacy & Redaction — Field-level redaction rules, data classification, retention policies, and anonymization.
  • Evidence Packets — Curated compliance bundles linking actions, events, policies, and external documents.
  • Projections — Deterministic event replay with snapshot support.
  • Telemetry — System.Diagnostics.ActivitySource spans for distributed tracing.

Durable agent approval

The .NET runtime uses the same HITL route and risk vocabulary as @fabricorg/platform. Per-action rules stay in an IAgentActionPolicyRegistry; the runtime owns stage placement and durable lifecycle semantics:

  • Agent decisions run after validation and authorization, before ordinary policies and handlers.
  • needs-approval and escalate park the invocation as WaitingForApproval without side effects.
  • rejected terminates as Failed; auto-execute continues through the governed pipeline.
  • IApprovalActionInvocationRecorder<TDb> durably stores route/risk evidence and atomically applies an approval decision. Existing IActionInvocationRecorder<TDb> implementations remain compatible.
  • IApprovalActionRuntime.ResumeApprovedInvocationAsync(...) resumes after the HITL checkpoint, so workflow adapters do not bypass policy, state-machine, handler, event, or adapter stages.
var result = await approvalRuntime.ResumeApprovedInvocationAsync(
    actionInvocationId,
    tenantId,
    spaceId,
    new ActionApprovalDecision(
        approverId: userId,
        approverType: ActorType.NaturalPerson,
        approved: true,
        reason: "Reviewed"),
    db,
    cancellationToken);

Approval replay is terminal-safe, and tenant/space mismatches cannot resume an invocation. Hosts that support approval must persist the original validated execution input and implement the atomic waiting-to-pending/failed transition defined by IApprovalActionInvocationRecorder<TDb>.


Repository Structure

FabricOrg.Platform/
├── src/
│   ├── FabricOrg.Platform/                        # Core runtime
│   ├── FabricOrg.Platform.Abstractions/           # Contracts
│   ├── FabricOrg.Platform.DependencyInjection/    # DI extensions
│   ├── FabricOrg.Platform.FluentValidation/       # Validation bridge
│   ├── FabricOrg.Platform.Orleans/                # Orleans integration
│   ├── FabricOrg.Platform.Polly/                  # Resilience
│   ├── FabricOrg.Platform.Policies.OpenPolicyAgent/ # OPA
│   └── FabricOrg.Platform.Sdk/                    # HTTP SDK
├── analyzers/
│   └── FabricOrg.Platform.Analyzers/              # Roslyn analyzers
├── tests/
│   ├── FabricOrg.Platform.Tests/
│   ├── FabricOrg.Platform.IntegrationTests/
│   ├── FabricOrg.Platform.Orleans.Tests/
│   └── FabricOrg.Platform.Sdk.Tests/
├── samples/
│   ├── MinimalVertical/                           # Console app demo
│   ├── OrleansVertical/                           # Orleans silo demo
│   └── AgentSdkSample/                            # External agent demo
├── docs/
│   ├── architecture/
│   ├── api/
│   └── migration-from-typescript.md
└── PLAN.md                                         # Implementation plan

Building

dotnet build

Testing

dotnet test

Samples

See the samples/ directory for working examples:

  • MinimalVertical — Console application with EF Core + in-memory database
  • OrleansVertical — Orleans silo with governed grains
  • AgentSdkSample — External agent using the HTTP SDK

License

MIT

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.4.0 117 7/21/2026
1.3.0 114 7/20/2026
1.2.0 109 7/20/2026
1.1.0 118 7/20/2026
1.0.0 128 5/18/2026