Fuaran.UI.Ops.CleanRoom
0.30.0
Prefix Reserved
See the version list below for details.
dotnet add package Fuaran.UI.Ops.CleanRoom --version 0.30.0
NuGet\Install-Package Fuaran.UI.Ops.CleanRoom -Version 0.30.0
<PackageReference Include="Fuaran.UI.Ops.CleanRoom" Version="0.30.0" />
<PackageVersion Include="Fuaran.UI.Ops.CleanRoom" Version="0.30.0" />
<PackageReference Include="Fuaran.UI.Ops.CleanRoom" />
paket add Fuaran.UI.Ops.CleanRoom --version 0.30.0
#r "nuget: Fuaran.UI.Ops.CleanRoom, 0.30.0"
#:package Fuaran.UI.Ops.CleanRoom@0.30.0
#addin nuget:?package=Fuaran.UI.Ops.CleanRoom&version=0.30.0
#tool nuget:?package=Fuaran.UI.Ops.CleanRoom&version=0.30.0
Fuaran.UI.Ops.CleanRoom
A structure-only clean room for Fuaran.UI.Ops: let an untrusted party (a model
provider, a cloud function, a counterparty) reorganise a Node<'Msg> tree without
receiving its content.
Because the Fuaran wire artefact is a TreeOp stream over id-referenced nodes — ops
reference NodeIds, content lives in leaf nodes — the content/structure split is native:
a content-free skeleton can cross a clean-room divide, the untrusted side emits structural
ops by id, and the trusted side replays them against the real tree. The privileged prose
never serialises across the wire.
Three pieces, all pure and Fable-clean:
| Surface | Role |
|---|---|
Skeleton.project : Node<'Msg> -> Skeleton |
Content-free shadow of a tree — per node: NodeId, structural Kind, a bounded StructuralDescriptor (role + coarsened child-count / content-length buckets). No content field exists on the Skeleton type — the projection cannot leak prose. |
Broker.StructuralOpBroker (IStructuralOpBroker) |
The structure-only gate. Enforce validates an inbound TreeOp against the issued skeleton and returns Released op / Withheld reason. Withholds any op that references an unknown NodeId, authors / carries content, or falls off the move/reorder/reparent/delete allowlist. Pure, stateless. |
Audit (ICleanRoomAuditSink) |
Content-free audit of every issued skeleton + every gate decision. issue / enforceAudited compose projection + enforcement with emission while keeping the gate pure. |
Shape
open Fuaran.UI.Ops.CleanRoom
// Trusted side — inside the perimeter:
let sink = Audit.InMemoryCleanRoomAuditSink()
let broker = Broker.StructuralOpBroker.create ()
let skeleton = Audit.issue sink realTree // project + audit issuance; this crosses the divide
// Untrusted side authors id-referenced structural ops against `skeleton`, e.g.
// TreeOp.ReorderChildren (parentId, newOrder)
// Trusted side gates every inbound op before replay:
match Audit.enforceAudited sink broker skeleton inboundOp with
| Broker.StructuralGateDecision.Released op -> Apply.apply op realTree // safe to replay
| Broker.StructuralGateDecision.Withheld reason -> // record + reject
A surviving op is, by construction, a content-free id-referenced rearrangement: applying it
to the real tree re-derives the same canonical-JSON document as a content-reattach round-trip
(the determinism proof in the test suite, via CanonicalJson).
Abstraction, not redaction
Structure leaks content — a heading's text is often itself sensitive, and child counts,
ordering, and text lengths are side-channels. So the skeleton abstracts (a bounded role
tag + coarsened magnitude buckets) rather than redacts (blank the text). This package ships
the mechanism; the domain-specific tag vocabulary + classifier that decides which richer
descriptor a node gets is the consuming domain's, layered on via the projectWith /
issueWith classifier seam. See docs/STRUCTURE-ONLY-CLEAN-ROOM.md.
Additive — a simple-tree app references nothing and pays nothing.
| 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
- Fable.Core (>= 5.0.0)
- FSharp.Core (>= 10.1.300)
- Fuaran.Core.Column (>= 0.6.0)
- Fuaran.Core.DataFrame (>= 0.6.0)
- Fuaran.Core.Ops (>= 0.6.0)
- Fuaran.Core.Tree (>= 0.6.0)
- Fuaran.Core.Validator (>= 0.6.0)
- Fuaran.Core.Wire (>= 0.6.0)
- Fuaran.UI.Ops (>= 0.30.0)
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.81.0 | 33 | 9/12/2026 |
| 0.80.0 | 84 | 9/9/2026 |
| 0.79.0 | 82 | 9/9/2026 |
| 0.78.1 | 89 | 9/8/2026 |
| 0.78.0 | 96 | 9/7/2026 |
| 0.77.0 | 96 | 9/6/2026 |
| 0.76.0 | 97 | 9/6/2026 |
| 0.75.0 | 97 | 9/4/2026 |
| 0.71.0 | 85 | 9/4/2026 |
| 0.70.0 | 90 | 9/4/2026 |
| 0.46.0 | 95 | 8/28/2026 |
| 0.39.0 | 92 | 8/27/2026 |
| 0.35.0 | 97 | 8/24/2026 |
| 0.32.0 | 96 | 8/23/2026 |
| 0.31.0 | 94 | 8/21/2026 |
| 0.30.0 | 98 | 8/21/2026 |
| 0.29.0 | 96 | 8/19/2026 |
| 0.28.0 | 94 | 8/18/2026 |
| 0.27.0 | 97 | 8/18/2026 |
| 0.26.0 | 102 | 8/18/2026 |