Goldpath.Approvals
0.1.0-preview.8
dotnet add package Goldpath.Approvals --version 0.1.0-preview.8
NuGet\Install-Package Goldpath.Approvals -Version 0.1.0-preview.8
<PackageReference Include="Goldpath.Approvals" Version="0.1.0-preview.8" />
<PackageVersion Include="Goldpath.Approvals" Version="0.1.0-preview.8" />
<PackageReference Include="Goldpath.Approvals" />
paket add Goldpath.Approvals --version 0.1.0-preview.8
#r "nuget: Goldpath.Approvals, 0.1.0-preview.8"
#:package Goldpath.Approvals@0.1.0-preview.8
#addin nuget:?package=Goldpath.Approvals&version=0.1.0-preview.8&prerelease
#tool nuget:?package=Goldpath.Approvals&version=0.1.0-preview.8&prerelease
Goldpath.Approvals
Human approval workflows as a composable Ring B module: amount-laddered authority chains declared as data, four-eyes and maker-checker enforcement, bounded delegation, deadline escalation, and the worklist — with every lifecycle step audited and published as integration events. This module replaces the e-mail approval thread, not the humans in it.
builder.AddGoldpathApprovals(approvals => approvals
.AddLadder("credit-limit", ladder => ladder
.Rung("expert", upToInclusive: 1_000_000m, escalateAfter: TimeSpan.FromHours(8))
.Rung("deputy-manager", 5_000_000m, TimeSpan.FromHours(8))
.Rung("manager", 15_000_000m, TimeSpan.FromHours(8), requiredApprovals: 2)
.TopRung("general-manager", TimeSpan.FromHours(24))));
- Request —
engine.RequestAsync("credit-limit", subject, amount, requestedBy)routes the amount to its rung and starts the trail. - Decide —
engine.DecideAsync(id, decidedBy, deciderRole, granted, reason)enforces four-eyes (the requester may never decide their own request) and the rung's role. Refusals are values (GoldpathApprovalDecisionOutcome), not exceptions. - Quorum — a rung may demand N DISTINCT grants (
requiredApprovals); each grant is a signature toward the rung, and distinct-eyes holds across the WHOLE chain: one identity signs at most once per request, even after escalation (AlreadySigned). - Rejection — terminal at any point, and its reason is MANDATORY: a blank reason is
refused (
ReasonRequired) — a bare "no" teaches the requester nothing. - Withdraw —
WithdrawAsync(id, requestedBy)takes back a pending request; only its requester may (NotRequesterotherwise), and the step lands in the trail. - Resubmit —
ResubmitAsync(rejectedId, requestedBy)reworks a rejected request as a fresh one, linked bySupersedesIdwith both trails cross-referenced — the audit reads request → reject → rework as one story. - Delegate — bounded window, depth one (a delegate cannot re-delegate; the cycle guard is structural).
- Escalate —
EscalateOverdueAsync()moves overdue requests one rung up; overdue at the top rung expires. Schedule it withjobs.AddGoldpathApprovalsJobs()(a five-minute sweep by default — rung deadlines are measured in hours, so the granularity never moves an SLA), or call it from your own loop. - Worklist —
WorklistAsync(identity, role): what this person may decide, oldest first.
Events (GoldpathApprovalRequested/Granted/Rejected/Escalated/Expired) carry the
IIntegrationEvent marker and publish through the messaging seam when a broker is
composed — and stay silent when not.
State lives behind IGoldpathApprovalStore; the in-memory store ships for tests and
single-node hosts, a database-backed store composes through the seam.
- Console —
MapGoldpathApprovalsAdmin()mounts the admin surface (/goldpath/admin/approvals, contract §7.1) and the operations console federates on it: the worklist with the quorum said as a number, the trail, and decide verbs that run the ENGINE unchanged — a refusal answers the rule's name. - Metrics — the
Goldpath.Approvalsmeter counts every lifecycle step per ladder; the Grafana board ships inops/grafana-approvals-dashboard.json.
This is a saga's counterpart, not its competitor: a compensating flow orchestrates SYSTEMS and may request an approval as one of its steps; Approvals never drives system steps itself (RFC D3).
| Product | Versions 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 is compatible. 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. |
-
net10.0
- Goldpath.Abstractions (>= 0.1.0-preview.8)
- Goldpath.Jobs (>= 0.1.0-preview.8)
- Goldpath.Messaging (>= 0.1.0-preview.8)
- Goldpath.Sdk (>= 0.1.0-preview.8)
- Microsoft.EntityFrameworkCore.Relational (>= 10.0.9)
-
net8.0
- Goldpath.Abstractions (>= 0.1.0-preview.8)
- Goldpath.Jobs (>= 0.1.0-preview.8)
- Goldpath.Messaging (>= 0.1.0-preview.8)
- Goldpath.Sdk (>= 0.1.0-preview.8)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.11)
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 |
|---|---|---|
| 0.1.0-preview.8 | 61 | 9/7/2026 |
| 0.1.0-preview.7 | 69 | 9/1/2026 |