Rulealize.RuleSet.Exchange 1.0.0

dotnet add package Rulealize.RuleSet.Exchange --version 1.0.0
                    
NuGet\Install-Package Rulealize.RuleSet.Exchange -Version 1.0.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="Rulealize.RuleSet.Exchange" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Rulealize.RuleSet.Exchange" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Rulealize.RuleSet.Exchange" />
                    
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 Rulealize.RuleSet.Exchange --version 1.0.0
                    
#r "nuget: Rulealize.RuleSet.Exchange, 1.0.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 Rulealize.RuleSet.Exchange@1.0.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=Rulealize.RuleSet.Exchange&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Rulealize.RuleSet.Exchange&version=1.0.0
                    
Install as a Cake Tool

Rulealize.RuleSet.Exchange

Two parties, each offering something, and neither committed until both are — a Rulealize rule set, shipped with the half it is built from.

Rule set id Rulealize.RuleSet.Exchange
Package Rulealize.RuleSet.Exchange
Ships with Rulealize.RuleSet.Exchange.Side
Inputs none of its own — ours.* and theirs.*
Draws on State, Comparison, Record, Logic (and TypeSchema, Binding inside Side)
"uses": [
  { "ruleSet": "Rulealize.RuleSet.Exchange", "version": "^1.0", "as": "swap" }
]

rulealize restore fetches this package and gets both documents, because the entry point holds the other and fetching only the entry point would fetch something that cannot compile. as is not optional — an alias defaults to the identifier and may not contain a ..

One package, two documents

Exchange.Side is one party's half: what they may offer, what they did, and whether they have committed. Exchange holds two of them and adds the guards that neither half can express.

Rulealize.RuleSet.Exchange.1.0.0.nupkg
└── ruleset/
    ├── exchange.json   ← "id": "Rulealize.RuleSet.Exchange"
    └── side.json       ← "id": "Rulealize.RuleSet.Exchange.Side"

Side is not published separately, and should not be. It is meaningless on its own — a side of nothing — so a package of its own would be a permanent public name for an implementation detail. It ships here instead, named under the package that ships it, which is what keeps two packages from ever shipping one identifier.

That is the same arrangement a library has: the type you call is the package's name, and the types it is built from come along without being products.

The guards

Neither half knows the other exists. Side has never heard of a counterparty; it can say I have offered and I have committed and nothing about anybody else. Everything below is in Exchange, over both states at once:

Nobody commits alone confirm waits for the other side to have offered something
Nobody is left holding it once one side has confirmed, the other may no longer withdraw
"held": {
  "ours": {
    "confirm":  { "when": { "op": "cmp.ne", "right": "empty",
                            "left": { "op": "rec.at", "record": "$theirs", "key": "stage" } } },
    "withdraw": { "when": { "op": "cmp.ne", "right": "confirmed",
                            "left": { "op": "rec.at", "record": "$theirs", "key": "stage" } } }
  },
  "theirs": { … the same, mirrored … }
}

Walking it

nothing offered      ours.offer(item: deed)   ours.offer(item: keys)
                     theirs.offer(item: payment)
                     ← no confirm anywhere

we have offered      ours.withdraw   theirs.offer(item: payment)
                     ← still no ours.confirm: they have offered nothing

both offered         ours.withdraw   ours.confirm
                     theirs.withdraw theirs.confirm

we confirmed         theirs.confirm
                     ← theirs.withdraw is gone, and so is ours

both confirmed       terminal (exchanged)

The third and fourth steps are the whole point. Until somebody commits, either side may walk away; after somebody commits, the other cannot leave them holding it.

The instance

Both sides' state is a field of this one's, so a case is still one document:

{
  "$schema": "rulealize/state/v1",
  "ruleSet": "Rulealize.RuleSet.Exchange@1.0.0",

  "data": {
    "ours":   { "data": { "offers": ["deed", "keys"], "offered": null, "stage": "empty" } },
    "theirs": { "data": { "offers": ["payment"],      "offered": null, "stage": "empty" } }
  }
}

What either side may offer is here and in neither rule set. A conveyance, a trade, a swap of signed documents, a prisoner exchange — same documents, different state.

Where it fits

The sides are and the exchange is
a seller and a buyer deed against payment
two teams a handover neither wants to do first
two systems a two-phase commit somebody has to model
two parties to a settlement signatures against release

Trying it

Needs Rulealize.Cli 0.9.0 or later:

dotnet tool install -g Rulealize.Cli
rulealize restore src/Rulealize.RuleSet.Exchange/ruleset/exchange.json
rulealize play    src/Rulealize.RuleSet.Exchange/ruleset/exchange.json --state state/example.json

Nothing is fetched: both documents are here, and Side is found beside the one that holds it. A component/ folder appears only when a document holds something published elsewhere.

Building the package

dotnet pack src/Rulealize.RuleSet.Exchange -c Release

The project file globs ruleset/*.json, which is safe here because both documents are ours and restore writes fetched ones into component/ instead. A repository whose rule set holds something published elsewhere should name what it packs rather than glob it — see what to build.

License

Apache-2.0, and it covers both documents as much as everything else here.

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

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.0.0 152 8/31/2026