README.md (10819B)
1 # radroots_trade 2 3 `radroots_trade` is the portable domain-algorithm layer for Radroots trades. 4 It validates canonical trade inputs, represents reducer evidence, derives 5 deterministic conflict-aware projections, and prepares side-effect-free 6 workflow plans over the canonical `radroots_event` trade model. 7 8 The crate is pre-release and its Cargo version is frozen at `0.1.0-alpha` 9 until explicitly changed. Versioned trade schemas, reducer contracts, and 10 conformance vectors evolve independently from the Cargo package version. 11 12 ## Canonical surface 13 14 New code should enter through these modules: 15 16 | Module | Responsibility | 17 | --- | --- | 18 | `evidence` | Immutable mutation, private-term, and attestation observations plus bounded evidence-manifest and RHI report models. | 19 | `model` | Trade projection state and validated business identifiers. | 20 | `reducer` | Deterministic reduction, evidence precedence, and conflict reporting. | 21 | `validation` | Validation-error ownership for canonical trade inputs. | 22 | `workflow` | Validated plans describing host actions without executing them. | 23 24 The curated root exports are `Projection`, `ReductionInput`, `ReducerIssue`, 25 `WorkflowPlan`, `ValidationError`, and `Error`. The canonical protocol 26 `TradeId` remains owned by `radroots_event`; `model::OrderId` is a distinct 27 human or business-workflow identifier and has no conversion to or from 28 `TradeId`. 29 30 Operational-listing host planning and binding-generation machinery are outside 31 this algorithm package. The reviewed Rust surface is recorded in the 32 [public API baseline](../../contracts/api_baselines/radroots_trade.txt). 33 34 ## Deterministic reduction 35 36 `reducer::reduce_trade_records` is a pure projection function. It accepts a 37 `ReductionInput` containing the canonical trade ID plus explicitly supplied 38 mutation, private-term, attestation, and observation evidence. It normalizes 39 input order, handles duplicates deterministically, isolates unsupported 40 contract versions, reports conflicts as typed `ReducerIssue` values, and 41 computes a canonical projection digest. 42 43 ```rust 44 use radroots_event::trade::TradeId; 45 use radroots_trade::{ReductionInput, reducer::reduce_trade_records}; 46 47 let trade_id = TradeId::parse("0123456789abcdef".repeat(2))?; 48 let projection = reduce_trade_records(ReductionInput::new(trade_id)); 49 50 assert_eq!(projection.trade_id(), &trade_id); 51 # Ok::<(), Box<dyn std::error::Error>>(()) 52 ``` 53 54 A runnable version is available at 55 [`examples/reduce_trade.rs`](examples/reduce_trade.rs). 56 57 Reduction does not retrieve missing records or attestations. A projection's 58 evidence state and issues describe only the supplied input, not the existence 59 of additional records elsewhere. 60 61 ## Evidence coverage and outcome 62 63 `evidence::classify_trade_evidence_coverage_v1` evaluates at most sixteen 64 explicit source results using the fixed `Unsupported`, `ScopeSatisfied`, 65 `Partial`, then `Missing` precedence. A required unsupported source is 66 `Unsupported`; every required source plus the required scope prerequisites is 67 `ScopeSatisfied`; any other completed source or admitted evidence is `Partial`; 68 otherwise the result is `Missing`. At least one required source is mandatory, 69 and one source can represent at most 4,096 admitted events. 70 71 Coverage never defaults to completeness. `Valid` and `Invalid` outcomes are 72 permitted only for `ScopeSatisfied`; `Missing`, `Partial`, and `Unsupported` 73 permit only `Indeterminate`. These portable values classify caller-supplied 74 facts and perform no source query, policy lookup, clock read, persistence, 75 signing, or publication. 76 77 ## Immutable evidence manifests 78 79 `evidence::RadrootsTradeEvidenceManifestV1` freezes one nonzero trade 80 generation, policy digest, explicit observation time, scope prerequisites, 81 bounded source results, and the exact accepted mutation/event/provenance 82 inventory. Canonical ordering is independent of caller order. Mutation IDs 83 bind canonical mutation content, while semantically distinct SHA-256 types 84 bind the exact caller-supplied canonical policy, signed-event, provenance, and 85 complete source-result record bytes without allowing those authorities to be 86 interchanged. The manifest commits to those separately retained records; it 87 does not contain or independently validate them. 88 89 The manifest uses a versioned, domain-separated, length-framed binary encoding 90 and exposes its canonical bytes plus a distinct manifest digest. Parsing caps 91 the input at 16 MiB before allocation and accepts only the byte-exact canonical 92 form. Source and observation iterators are bounded before normalization; 93 source IDs are lowercase stable identifiers, observations must name a retained 94 source, exact duplicates reject, and per-source admitted counts must match the 95 frozen inventory. Building or parsing a manifest performs no I/O, source 96 query, reduction, signing, persistence, or publication. 97 98 ## Immutable evidence reports 99 100 `evidence::RadrootsRhiEvidenceReportV1` binds one immutable report to an 101 issuer, claim mutation, outcome and sorted stable reason codes, the exact 102 reducer contract, a typed projection digest, and the policy, manifest, 103 observation time, trade, and nonzero generation frozen by an accepted evidence 104 manifest. Definitive Valid or Invalid reports require `ScopeSatisfied` 105 coverage; all other coverage states permit only Indeterminate. 106 107 The report freezes the exact RFC 8785 JSON statement payload reserved by the 108 service-event contract. Its statement digest is SHA-256 over the fixed 109 `radroots:rhi-evidence-attestation-statement:v1` NUL-terminated domain followed 110 by those canonical bytes. The final canonical content adds equal `report_id` 111 and `statement_digest` fields without making the digest self-referential. 112 Supersession is a sealed both-or-neither report/event pair. Strict parsing caps 113 input at 16 KiB, rejects unknown, duplicate, missing, null, noncanonical, and 114 fixed-field drift, and reproduces the two governed current and superseding 115 vectors exactly. 116 117 The report commits to a separately retained projection and evidence manifest; 118 it does not independently prove either record, the claim's existence, issuer 119 authority, a signature, or a Nostr event. Event construction, structural tags, 120 signature validation, storage, and publication remain outside this model-only 121 boundary. 122 123 ## Workflow planning 124 125 `WorkflowPlan::prepare` validates a canonical proposal, decision, revision, 126 or cancellation mutation and returns its ordered required actions. Actions 127 describe private-term verification, signing, atomic persistence, and delivery; 128 the crate never performs those actions. Private-term plans expose only the 129 artifact identifier, schema identifier, commitment, and candidate needed by 130 the host to perform its own verification. 131 132 Creating or dropping a plan changes no external state. A successful plan is 133 not an authorization decision, signature, storage receipt, delivery receipt, 134 or proof that referenced private material exists. 135 136 ## Features 137 138 | Feature | Default | Effect | 139 | --- | --- | --- | 140 | `std` | yes | Standard-library integration for the portable model and errors. | 141 | `serde` | yes | Serialization support for native and versioned trade values. | 142 | `json` | yes | Executable JSON conformance vectors, deterministic projection and statement digests, and immutable evidence manifests/reports; enables `serde`. | 143 144 `--no-default-features` keeps the allocation-backed trade model, reducer, and 145 workflow planner available in `no_std` environments. Features are additive; 146 enabling one never selects a runtime, performs I/O, starts work, or weakens 147 validation. Code generation and implementation-assembly features are not part 148 of the Release V1 capability vocabulary. 149 150 ## Serialization and versioning 151 152 Serde represents validated values; deserialization does not perform actor 153 authorization, signature verification, record lookup, or delivery. Canonical 154 JSON stability applies only to the explicitly governed reducer, workflow, and 155 RHI evidence-report contracts. Rust data layout, 156 debug formatting, and the pre-release public API are not wire contracts. 157 158 Versioned `V1` names identify serialized or algorithm-contract generations. 159 They do not imply that the Cargo package is `1.0`, and changing a Cargo version 160 must not rewrite authenticated historical trade data. 161 162 ## Security and trust boundaries 163 164 All mutation, evidence, identifier, and serialized inputs are untrusted until 165 their owning constructors or validators accept them. Deterministic reduction 166 does not establish actor authority, validate a cryptographic signature, prove 167 referenced-event existence, decrypt private terms, or decide business policy. 168 Workflow preparation validates shape and required host actions but deliberately 169 does not acquire signers, keys, stores, transports, clocks, or executors. 170 171 The crate owns no secret material and must not log private-term plaintext. 172 Artifact identifiers and ciphertext commitments are references for a host to 173 verify through an explicit secure boundary; they are not proof of retrieval, 174 decryption, durability, or confidentiality by themselves. 175 176 ## Side effects, cancellation, and commit points 177 178 This crate performs no network, filesystem, database, keychain, signing, 179 outbox, scheduling, or process-global operations. Its public algorithms are 180 synchronous and deterministic for the same canonical inputs. 181 182 There is no asynchronous cancellation or deadline boundary and no durable 183 commit point. Abandoning reduction or dropping a workflow plan discards only 184 in-memory work. Storage, signing, transport, sync, SDK, RHI, and application 185 hosts own cancellation and must report success only after their own explicit 186 commit boundary succeeds. 187 188 ## Intended consumers 189 190 Direct consumers are `radroots_storage`, `radroots_sync`, `radroots_sdk`, RHI, 191 and applications that need the deterministic trade boundary. Ordinary 192 applications should normally use the `radroots` or `radroots_sdk` front door 193 and depend on this crate directly only when they need its native model, 194 reducer, evidence, or workflow-plan contracts. 195 196 This package must not acquire actor authorization, signers, event-store or 197 SQL access, files, transport delivery, outbox mutation, process scheduling, 198 or application state. Those responsibilities belong to host SPI, adapter, 199 storage, orchestration, and front-door packages. 200 201 ## Package charter 202 203 The authoritative Release V1 responsibility, dependency, feature, module, 204 root-export, and forbidden-scope contract is the 205 [Radroots crates Release V1 specification](../../contracts/crates/release_v1/radroots_crates_release_v1.toml). 206 The reviewed surface is the 207 [`radroots_trade` API baseline](../../contracts/api_baselines/radroots_trade.txt). 208 209 ## Copyright 210 211 Except as otherwise noted, all files in the `radroots_trade` distribution are 212 copyright (c) 2025 Tyson Lupul. See `LICENSE` for usage, redistribution, and 213 warranty terms.