Optima.Net.NegotiatR
2.0.0
Prefix Reserved
dotnet add package Optima.Net.NegotiatR --version 2.0.0
NuGet\Install-Package Optima.Net.NegotiatR -Version 2.0.0
<PackageReference Include="Optima.Net.NegotiatR" Version="2.0.0" />
<PackageVersion Include="Optima.Net.NegotiatR" Version="2.0.0" />
<PackageReference Include="Optima.Net.NegotiatR" />
paket add Optima.Net.NegotiatR --version 2.0.0
#r "nuget: Optima.Net.NegotiatR, 2.0.0"
#:package Optima.Net.NegotiatR@2.0.0
#addin nuget:?package=Optima.Net.NegotiatR&version=2.0.0
#tool nuget:?package=Optima.Net.NegotiatR&version=2.0.0
Optima.Net.NegotiatR
Optima.Net.NegotiatR is a deterministic, single-pass negotiation engine.
It answers exactly one question:
�Given these policy failures, may we propose an alternative intent?�
Nothing more. Nothing less.
TL;DR (for people who hate READMEs)
If you don�t want to read this document and would rather see NegotiatR actually doing something,
clone and run the test harness instead:
https://github.com/snamretsuek/Optima.Net.TestHarnesses
It�s contains a console apps that:
wire everything together properly,
show real negotiation flows (password ? biometrics, etc.),
and let you step through the code in a debugger like a normal human.
If you still have questions after running the harness� then yes, you�ll have to come back and read the README.
Companion Package (Important)
NegotiatR is designed to be used together with:
?? Optima.Net.Domain
That package provides:
IPolicy<T>andISpecification<T>IPolicyJustification<T>PolicyDiagnosticEvaluatorPolicyFailureandPolicyFailureSemantics
Recommended flow
Build Proposal
?
Evaluate policies using PolicyDiagnosticEvaluator (Optima.Net.Domain)
?
Collect PolicyFailure results
?
Pass Proposal + Failures to NegotiatR
?
Apply NegotiatROutcome
NegotiatR does not evaluate policies itself.
It only consumes the failures produced elsewhere.
Table of Contents
- What Problem NegotiatR Solves
- How NegotiatR Fits With Optima.Net.Domain
- Core Concepts
- Negotiation Flow
- Policy Failure Semantics
- Authentication Example
- Password Creation Example
- End-to-End Authentication Negotiation
- FinTech Credit Decision Example
- Design Rules You Must Not Break
- Summary
What Problem NegotiatR Solves
In real systems, policies fail.
When they do, teams often:
- throw exceptions
- retry automatically
- hardcode fallbacks
- silently change behavior
This creates implicit decision flows that are:
- hard to reason about
- impossible to audit
- dangerous in regulated systems
NegotiatR forces you to answer a single explicit question:
If this intent failed, are we allowed to suggest another intent?
How NegotiatR Fits With Optima.Net.Domain
Optima.Net.Domain answers:
�Is this proposal acceptable?�
It does this by:
- evaluating policies
- executing specifications
- producing structured diagnostics
NegotiatR answers a different question:
�If it is not acceptable, may we propose something else?�
These two responsibilities must never be mixed.
Core Concepts
Proposal
A proposal represents intent, not execution.
public interface IProposal
{
ProposalId Id { get; }
}
Examples:
- Authenticate using Biometrics
- Authenticate using Password
- Create a Password
- Grant Credit
- Offer Secured Credit
A proposal does not prove success.
It only states what is being attempted.
Policy Failure
NegotiatR consumes policy failures produced by
PolicyDiagnosticEvaluator (Optima.Net.Domain).
public sealed record PolicyFailure(
PolicyType policyType,
Code code,
PolicyFailureSemantics Semantics,
IReadOnlyDictionary<string, object> Data);
NegotiatR trusts these failures to be correct.
Negotiation Rules
Rules decide whether an alternative intent may be proposed.
They:
- inspect the proposal
- inspect policy failures
- may propose alternatives
They never:
- evaluate policies
- validate correctness
- mutate proposals
- orchestrate workflows
Negotiation Flow
No failures
?NegotiatRAcceptedFailures exist
? rules evaluated deterministicallyFirst valid alternative proposed
?NegotiatRCounterProposedNo alternatives
?NegotiatRRejected
There is:
- no recursion
- no re-entry
- no retry
- no state mutation
Policy Failure Semantics
| Semantics | Meaning |
|---|---|
| Terminal | No alternative is allowed |
| Correctable | User may fix and retry |
| Replaceable | Alternative intent may be proposed |
NegotiatR enforces nothing.
Rules decide how to react to semantics.
Authentication Example
AuthenticationProposal
public sealed class AuthenticationProposal : IProposal
{
public ProposalId Id { get; }
public CredentialType Type { get; }
private AuthenticationProposal(
ProposalId id,
CredentialType type)
{
Id = id;
Type = type;
}
public static AuthenticationProposal Password()
=> new AuthenticationProposal(ProposalId.New(), CredentialType.Password);
public static AuthenticationProposal Biometrics()
=> new AuthenticationProposal(ProposalId.New(), CredentialType.Biometrics);
}
Why this exists
Authentication is about intent:
�Which authentication method should we try?�
Execution, validation, and matching are handled elsewhere.
Password Creation Example
Password creation is not authentication.
It has its own proposal, policies, and specifications.
public sealed class PasswordCreationProposal : IProposal
{
public ProposalId Id { get; }
public PasswordCreationContext Context { get; }
public PasswordCreationProposal(
ProposalId id,
PasswordCreationContext context)
{
Id = id;
Context = context;
}
}
Why this exists
- Password quality rules do not apply to authentication
- Authentication availability rules do not apply to creation
- Mixing the two creates subtle bugs
End-to-End Authentication Negotiation
Scenario
- User attempts biometric authentication
- User is not enrolled
- System may offer password authentication instead
Inputs
var proposal = AuthenticationProposal.Biometrics();
// Failures are produced by PolicyDiagnosticEvaluator (Optima.Net.Domain)
// The following is illustrative only � in real systems you consume diagnostics
new Dictionary<string, object?>())
};
Rule
public sealed class BiometricsToPasswordRule : INegotiatRRule
{
public int Priority => 0;
public Optional<RuleExecutionPhase> Group => Optional<RuleExecutionPhase>.None();
public bool CanApply(
IProposal proposal,
IReadOnlyCollection<PolicyFailure> failures)
=> proposal is AuthenticationProposal a
&& a.Type == CredentialType.Biometrics
&& failures.Any(f => f.Semantics.HasFlag(PolicyFailureSemantics.Replaceable));
public IEnumerable<IProposal> ProposeAlternatives(
IProposal proposal,
IReadOnlyCollection<PolicyFailure> failures)
{
yield return AuthenticationProposal.Password();
}
}
Why this matters
- No hidden fallbacks
- No workflow logic
- Explicit, auditable intent change
FinTech Credit Decision Example
Scenario
- Customer applies for unsecured credit
- Risk policy fails
- System may offer secured credit instead
Proposal
public sealed class CreditApplicationProposal : IProposal
{
public ProposalId Id { get; }
public CreditType Type { get; }
private CreditApplicationProposal(ProposalId id, CreditType type)
{
Id = id;
Type = type;
}
public static CreditApplicationProposal Unsecured()
=> new CreditApplicationProposal(ProposalId.New(), CreditType.Unsecured);
public static CreditApplicationProposal Secured()
=> new CreditApplicationProposal(ProposalId.New(), CreditType.Secured);
}
Rule
public sealed class UnsecuredToSecuredCreditRule : INegotiatRRule
{
public int Priority => 0;
public Optional<RuleExecutionPhase> Group => Optional<RuleExecutionPhase>.None();
public bool CanApply(
IProposal proposal,
IReadOnlyCollection<PolicyFailure> failures)
=> proposal is CreditApplicationProposal p
&& p.Type == CreditType.Unsecured
&& failures.Any(f => f.Semantics == PolicyFailureSemantics.Replaceable);
public IEnumerable<IProposal> ProposeAlternatives(
IProposal proposal,
IReadOnlyCollection<PolicyFailure> failures)
{
yield return CreditApplicationProposal.Secured();
}
}
Real-world usage
Banks do this every day.
NegotiatR makes the decision explicit instead of implicit.
Design Rules You Must Not Break
- NegotiatR never evaluates policies
- NegotiatR never mutates proposals
- NegotiatR never retries or loops
- Rules never perform execution
- Specifications evaluate proposals only
- Execution happens outside NegotiatR
If you break these rules, stop and rethink.
About PolicyFailureFactory (Read This)
You will notice references to PolicyFailureFactory in some test code and examples.
Important:
You do not need to use PolicyFailureFactory in real application code.
Why it exists
PolicyFailureFactory is a testing and convenience utility.
It exists to:
- construct failures in unit tests
- simplify examples
- avoid verbose diagnostic setup when illustrating concepts
What you should do in real systems
In production code, failures should come from:
PolicyDiagnosticResult<IProposal> result =
evaluator.EvaluateAll(policies, proposal);
// Extract immutable policy failures
IReadOnlyCollection<PolicyFailure> failures = result.GetFailures();
Those failures are then passed directly into NegotiatR.
NegotiatR expects failures to be authoritative and does not care how they were produced.
If you find yourself using PolicyFailureFactory in application logic, you are doing it wrong.
Contexts, Attempts, Policies, Specifications (Read This Carefully)
This section fills the most important conceptual gaps.
If you misunderstand these concepts, you will build the wrong system.
What Is a Context?
A context is structured, immutable data attached to a proposal.
A context:
- contains facts
- does not contain behavior
- does not make decisions
- exists to give specifications something to evaluate
Contexts are not proposals.
Contexts are data carried by proposals.
Example: PasswordAuthenticationContext
public sealed record PasswordAuthenticationContext
{
public bool IsEnabled { get; }
public bool HasPassword { get; }
public bool IsLocked { get; }
public bool IsTemporarilyBlocked { get; }
public PasswordAuthenticationContext(
bool isEnabled,
bool hasPassword,
bool isLocked,
bool isTemporarilyBlocked)
{
IsEnabled = isEnabled;
HasPassword = hasPassword;
IsLocked = isLocked;
IsTemporarilyBlocked = isTemporarilyBlocked;
}
}
This context answers:
- May password authentication be attempted?
It does not answer:
- Did authentication succeed?
- Is the password correct?
Those belong elsewhere.
What Is an Attempt?
An attempt represents ephemeral, per-try data.
Attempts:
- may be missing (
Optional<T>) - represent what was tried
- do not represent system state
Example: BiometricAuthenticationAttempt
public sealed record BiometricAuthenticationAttempt
{
public BiometricModality Modality { get; }
public DateTime AttemptedAt { get; }
public BiometricAuthenticationAttempt(
BiometricModality modality,
DateTime attemptedAt)
{
Modality = modality;
AttemptedAt = attemptedAt;
}
}
Attempts are consumed by:
- specifications
- execution logic
Attempts are never stored as long-term truth.
What Is a Specification?
A specification is a pure boolean predicate.
It answers:
Is this proposal acceptable with respect to one rule?
Specifications:
- evaluate proposals
- read contexts
- are deterministic
- never mutate anything
Example: PasswordExistsSpec
public sealed class PasswordExistsSpec
: ISpecification<IProposal>
{
public bool IsSatisfiedBy(IProposal proposal)
{
if (proposal is not AuthenticationProposal auth)
throw new InvalidOperationException();
if (auth.Type != CredentialType.Password)
return true;
return auth.PasswordAuthenticationContext
.ValueOrThrow()
.HasPassword;
}
}
What Is a Policy?
A policy defines when specifications apply and how failures are classified.
Policies:
- do not evaluate specifications
- do not contain rules
- exist to declare scope and semantics
public sealed class PasswordAuthenticationPolicy
: IPolicy<IProposal>
{
public bool IsSatisfiedBy(IProposal proposal)
=> proposal is AuthenticationProposal a
&& a.Type == CredentialType.Password;
public PolicyFailureSemantics FailureSemantics
=> PolicyFailureSemantics.Correctable;
}
What Is a PolicyJustification?
A PolicyJustification is the marriage between:
- a policy
- the specifications that justify it
This is intentional and explicit.
public sealed class PasswordAuthenticationPolicyJustification
: IPolicyJustification<IProposal>
{
public string PolicyName => nameof(PasswordAuthenticationPolicy);
public IReadOnlyCollection<ISpecification<IProposal>> Specifications { get; }
public PasswordAuthenticationPolicyJustification(
PasswordExistsSpec exists,
PasswordNotLockedSpec notLocked,
PasswordNotThrottledSpec notThrottled)
{
Specifications = new ISpecification<IProposal>[]
{
exists,
notLocked,
notThrottled
};
}
}
Why this exists:
- policies alone are meaningless
- specs alone have no semantics
- justification binds intent to evidence
How Everything Fits Together
Proposal
??? Contexts (facts)
??? Attempts (optional, ephemeral)
Policy
??? PolicyJustification
??? Specifications
PolicyDiagnosticEvaluator
??? Produces PolicyFailure[]
NegotiatR
??? Consumes failures
??? Proposes alternative intent
If you violate this structure, stop.
Summary
- Optima.Net.Domain decides acceptability
- Optima.Net.NegotiatR decides alternatives
- Intent is explicit
- Decisions are auditable
- Behavior is deterministic
This separation is the entire point.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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
- Optima.Net (>= 2.0.0)
- Optima.Net.Domain (>= 4.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
RELEASENOTES.md