qualia_core_db/modalities/value_flow.rs
1//! Value-flow & compensation (§23, legal_logic.md) — the Permissive Commons.
2//!
3//! Shifts economic obligation from infinite linear consumption to **threshold-based discharge**
4//! to prevent extraction: a work's cost is its audited production cost plus a *legally capped*
5//! ROI; usage by an agent triggers a royalty scaled by the agent's category; payments accumulate
6//! into a pool; once the pool meets the cost, the obligation is **discharged and the use is freed
7//! globally**. Integer arithmetic throughout (deterministic, zero-heap) — units are abstract
8//! minor units (e.g. cents).
9
10/// Total economic obligation for a work: `production_cost × (1 + roi_cap)`, with the ROI margin
11/// **capped** (the `sh:maxInclusive` cap — extraction guard). `roi_cap_percent` is clamped to
12/// `max_roi_percent` before applying. Saturating.
13pub fn commons_cost(production_cost: u64, roi_cap_percent: u64, max_roi_percent: u64) -> u64 {
14 let roi = roi_cap_percent.min(max_roi_percent);
15 let margin = production_cost.saturating_mul(roi) / 100;
16 production_cost.saturating_add(margin)
17}
18
19/// The royalty a use incurs: `base × multiplier%`, where the multiplier scales by agent
20/// category (e.g. a corporate user pays a higher multiple than a non-profit). Saturating.
21#[inline]
22pub fn royalty(base: u64, agent_multiplier_percent: u64) -> u64 {
23 base.saturating_mul(agent_multiplier_percent) / 100
24}
25
26/// Accumulate a payment into the compensation pool (saturating).
27#[inline]
28pub fn pool_after(pool: u64, payment: u64) -> u64 {
29 pool.saturating_add(payment)
30}
31
32/// The obligation is **discharged** once accumulated compensation meets the cost — the use is
33/// then obligation-free (freed globally). `Active(Outstanding) → Discharged(ObligationFree)`.
34#[inline]
35pub fn is_commons_discharged(pool: u64, cost: u64) -> bool {
36 pool >= cost && cost > 0
37}
38
39/// Outstanding balance still owed before discharge (0 once met). Saturating.
40#[inline]
41pub fn outstanding(pool: u64, cost: u64) -> u64 {
42 cost.saturating_sub(pool)
43}
44
45// ─── Thermodynamic cost caps (E-ROI) ──────────────────────────────────────────────
46
47/// **Energy Return On Investment** = `energy_returned / energy_invested`. `0.0` if nothing was
48/// invested. The physics-bound viability ratio of a value flow.
49pub fn eroi(energy_returned: u64, energy_invested: u64) -> f32 {
50 if energy_invested == 0 {
51 0.0
52 } else {
53 energy_returned as f32 / energy_invested as f32
54 }
55}
56
57/// Is a value flow thermodynamically viable — E-ROI at or above `min_ratio`? Below this floor the
58/// flow is net-extractive (spends more energy than it recovers) and is refused — the physics-bound
59/// cost cap.
60#[inline]
61pub fn eroi_viable(energy_returned: u64, energy_invested: u64, min_ratio: f32) -> bool {
62 eroi(energy_returned, energy_invested) >= min_ratio
63}
64
65// ─── Recursive royalty trees (derivative-work attribution) ────────────────────────
66
67/// The royalty owed to an ancestor `generation` levels up a derivation chain: a geometric split
68/// where each level takes `share_percent` of what reaches it —
69/// `total × (share_percent/100)^(generation+1)`. Generation 0 = the immediate parent. Saturating
70/// integer arithmetic; zero-heap. (Recursive commons attribution for derivative works.)
71pub fn ancestor_royalty(total_royalty: u64, generation: u32, share_percent: u64) -> u64 {
72 let mut amount = total_royalty;
73 for _ in 0..=generation {
74 amount = amount.saturating_mul(share_percent) / 100;
75 }
76 amount
77}
78
79/// Total royalty distributed up a chain of `generations` ancestors (the sum of each generation's
80/// geometric share) — what leaves the deriving work as upstream attribution.
81pub fn royalty_tree_total(total_royalty: u64, generations: u32, share_percent: u64) -> u64 {
82 let mut sum = 0u64;
83 for g in 0..generations {
84 sum = sum.saturating_add(ancestor_royalty(total_royalty, g, share_percent));
85 }
86 sum
87}
88
89// ─── Multi-currency & cross-jurisdictional tax shunting ───────────────────────────
90
91/// Convert `amount` at `rate_micros` (target units per source unit, in millionths — e.g.
92/// `1_500_000` = ×1.5). Saturating (u128 intermediate).
93pub fn convert_currency(amount: u64, rate_micros: u64) -> u64 {
94 ((amount as u128).saturating_mul(rate_micros as u128) / 1_000_000u128) as u64
95}
96
97/// The tax owed on `amount` at `tax_basis_points` (1 bp = 0.01%) — the automated cross-
98/// jurisdictional tax-schema shunt. Saturating (u128 intermediate).
99pub fn apply_tax(amount: u64, tax_basis_points: u64) -> u64 {
100 ((amount as u128).saturating_mul(tax_basis_points as u128) / 10_000u128) as u64
101}
102
103// ─── Liquidity-pool ODE (drainage + replenishment) ────────────────────────────────
104
105/// One discrete Euler step of the liquidity ODE `dL/dt = inflow − drain·L`: constant `inflow`
106/// replenishment minus drainage proportional to the current pool (`drain_percent`% per step).
107/// Saturating; zero-heap. The steady state is `L* = inflow / drain`.
108pub fn liquidity_step(pool: u64, inflow: u64, drain_percent: u64) -> u64 {
109 let drained = pool.saturating_mul(drain_percent.min(100)) / 100;
110 pool.saturating_sub(drained).saturating_add(inflow)
111}
112
113/// Evolve liquidity over `steps` of the ODE (constant `inflow`, proportional `drain_percent`) —
114/// converges toward the steady state `inflow / (drain_percent/100)`.
115pub fn liquidity_after(initial: u64, inflow: u64, drain_percent: u64, steps: u32) -> u64 {
116 let mut pool = initial;
117 for _ in 0..steps {
118 pool = liquidity_step(pool, inflow, drain_percent);
119 }
120 pool
121}
122
123// ─── Usury circuit-breaker (multi-agent token ceiling) ────────────────────────────
124//
125// MULTI_AGENT_PROTOCOL.md's resource-governance guard: an agent's projected spend may
126// run up to — but not past — an agreed budget plus a small overage; breaching the
127// ceiling is *usurious* and the operation is refused (`ERROR_USURY_LIMIT_EXCEEDED`).
128// A hard anti-extraction cap in the same family as the capped ROI and the E-ROI floor
129// above, not a soft warning. Deterministic saturating integer arithmetic.
130
131/// Default permitted overage above an agreed budget, in percent — the spec's **110%**
132/// token ceiling is `budget × (1 + 10/100)`.
133pub const USURY_OVERAGE_PERCENT_DEFAULT: u64 = 10;
134
135/// Maximum spend permitted before the usury breaker trips: `budget × (1 + overage/100)`
136/// (saturating). With the default 10% overage this is the 110% ceiling.
137#[inline]
138pub fn usury_ceiling(budget: u64, overage_percent: u64) -> u64 {
139 let margin = budget.saturating_mul(overage_percent) / 100;
140 budget.saturating_add(margin)
141}
142
143/// Has `projected_spend` breached the usury ceiling for `budget`? Spending *up to and
144/// including* the ceiling is permitted; only a strictly greater spend is usurious.
145#[inline]
146pub fn is_usurious(projected_spend: u64, budget: u64, overage_percent: u64) -> bool {
147 projected_spend > usury_ceiling(budget, overage_percent)
148}
149
150/// `ERROR_USURY_LIMIT_EXCEEDED` — a projected spend breached the agreed budget's
151/// ceiling. Carries the `budget`, the computed `ceiling`, and the offending
152/// `projected` spend so the caller can write a faithful conduct-violation record.
153#[derive(Debug, Clone, Copy, PartialEq, Eq)]
154pub struct UsuryError {
155 pub budget: u64,
156 pub ceiling: u64,
157 pub projected: u64,
158}
159
160/// Gate a projected spend against the usury ceiling — `Ok(())` while at/under the
161/// ceiling, `Err(UsuryError)` once it is breached. The fiduciary circuit-breaker an
162/// agent's resource declaration is checked through before the spend is admitted.
163#[inline]
164pub fn check_usury(
165 projected_spend: u64,
166 budget: u64,
167 overage_percent: u64,
168) -> Result<(), UsuryError> {
169 let ceiling = usury_ceiling(budget, overage_percent);
170 if projected_spend > ceiling {
171 Err(UsuryError {
172 budget,
173 ceiling,
174 projected: projected_spend,
175 })
176 } else {
177 Ok(())
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184
185 #[test]
186 fn eroi_gates_thermodynamic_viability() {
187 assert!((eroi(300, 100) - 3.0).abs() < 1e-6);
188 assert_eq!(eroi(5, 0), 0.0);
189 // Viable iff E-ROI ≥ floor.
190 assert!(eroi_viable(300, 100, 2.0));
191 assert!(!eroi_viable(150, 100, 2.0), "net-extractive → refused");
192 }
193
194 #[test]
195 fn recursive_royalty_tree() {
196 // 50% per generation: parent gets 50, grandparent 25, great-grandparent 12.
197 assert_eq!(ancestor_royalty(100, 0, 50), 50);
198 assert_eq!(ancestor_royalty(100, 1, 50), 25);
199 assert_eq!(ancestor_royalty(100, 2, 50), 12); // 100*.5*.5*.5 = 12.5 → 12 (integer)
200 // The chain total over 3 generations: 50 + 25 + 12 = 87.
201 assert_eq!(royalty_tree_total(100, 3, 50), 87);
202 }
203
204 #[test]
205 fn multi_currency_and_tax() {
206 assert_eq!(convert_currency(100, 1_500_000), 150); // ×1.5
207 assert_eq!(convert_currency(100, 500_000), 50); // ×0.5
208 assert_eq!(apply_tax(10_000, 250), 250); // 2.5% of 10000
209 }
210
211 #[test]
212 fn liquidity_ode_converges_to_steady_state() {
213 // inflow 100, drain 10%/step → steady state L* = 100 / 0.10 = 1000.
214 let one = liquidity_step(0, 100, 10);
215 assert_eq!(one, 100); // 0 drained + 100 inflow
216 let settled = liquidity_after(0, 100, 10, 500);
217 assert!(
218 (settled as i64 - 1000).abs() <= 1,
219 "converges to inflow/drain = 1000, got {settled}"
220 );
221 // Draining a full pool with no inflow shrinks it.
222 assert!(liquidity_after(1000, 0, 50, 5) < 1000);
223 }
224
225 #[test]
226 fn roi_is_capped() {
227 // 1000 cost, asked-for 50% ROI but cap is 20% → cost = 1000 + 200 = 1200.
228 assert_eq!(commons_cost(1000, 50, 20), 1200);
229 // Within cap → applied as-is.
230 assert_eq!(commons_cost(1000, 10, 20), 1100);
231 }
232
233 #[test]
234 fn royalty_scales_by_agent_category() {
235 // corporate 300% vs non-profit 50% of the same base.
236 assert_eq!(royalty(100, 300), 300);
237 assert_eq!(royalty(100, 50), 50);
238 }
239
240 #[test]
241 fn usury_breaker_trips_past_the_110_percent_ceiling() {
242 // A 1000-token budget admits spend up to the 110% ceiling (1100); past it is usurious.
243 assert_eq!(usury_ceiling(1000, USURY_OVERAGE_PERCENT_DEFAULT), 1100);
244 assert!(check_usury(1000, 1000, USURY_OVERAGE_PERCENT_DEFAULT).is_ok());
245 assert!(
246 check_usury(1100, 1000, USURY_OVERAGE_PERCENT_DEFAULT).is_ok(),
247 "exactly at ceiling is permitted"
248 );
249 assert!(!is_usurious(1100, 1000, USURY_OVERAGE_PERCENT_DEFAULT));
250 let err = check_usury(1101, 1000, USURY_OVERAGE_PERCENT_DEFAULT).unwrap_err();
251 assert_eq!(err.ceiling, 1100);
252 assert_eq!(err.projected, 1101);
253 assert!(is_usurious(1101, 1000, USURY_OVERAGE_PERCENT_DEFAULT));
254 // A zero budget permits no positive spend.
255 assert!(check_usury(1, 0, USURY_OVERAGE_PERCENT_DEFAULT).is_err());
256 assert!(check_usury(0, 0, USURY_OVERAGE_PERCENT_DEFAULT).is_ok());
257 // The overage is a policy knob: a stricter 0% overage caps exactly at budget.
258 assert_eq!(usury_ceiling(1000, 0), 1000);
259 assert!(check_usury(1001, 1000, 0).is_err());
260 }
261
262 #[test]
263 fn pool_discharges_at_threshold() {
264 let cost = commons_cost(1000, 20, 20); // 1200
265 let mut pool = 0u64;
266 pool = pool_after(pool, royalty(400, 300)); // corporate use: 1200
267 assert!(
268 is_commons_discharged(pool, cost),
269 "pool met cost → discharged + freed globally"
270 );
271 assert_eq!(outstanding(pool, cost), 0);
272 // Before that payment the obligation was outstanding.
273 assert!(!is_commons_discharged(500, cost));
274 assert_eq!(outstanding(500, cost), 700);
275 }
276}