open-standards/openpay/crates/op-revrec/src/error.rs
Transaction Science 781c331288 ingest batch 5 (salvage): 2 crates from 9-agent dispatch (session-limit hit mid-batch)
OpenPay (1 crate)
  op-revrec      ASC 606 / IFRS 15 revenue recognition (5-step model,
                 multi-element allocation, deferred revenue ledger,
                 variable consideration with constraint, principal vs agent,
                 contract modifications, multi-currency translation)
                 27 tests across 6 FASB worked examples + SaaS lifecycle.

EOC (1 crate)
  eoc-carbon     Carbon intensity → joules → gCO2e accounting.
                 Electricity Maps, WattTime, CO2 Signal adapters; IEA
                 baseline fallback; PUE tables (AWS/GCP/Azure); region-aware
                 scheduling + demand shifting; SCI-for-AI bridge into eoc-eval.
                 21 tests passing.

Seven other crates (op-dispute-evidence, op-ewallets-asia, smart-byte-zk,
smart-byte-atproto, smart-byte-edv, eoc-agent, eoc-rag) were scoped in this
batch but the parallel agents hit session-limit before completing. They are
deferred to a follow-up batch.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-24 09:28:38 -04:00

86 lines
3.2 KiB
Rust

//! Error type for `op-revrec`. One sealed enum, exhaustive `match` at the callsite.
use thiserror::Error;
/// Result alias for `op-revrec`.
pub type Result<T> = core::result::Result<T, Error>;
/// All possible failure modes inside `op-revrec`.
///
/// The variant set is intentionally narrow: revenue-recognition math
/// either succeeds or it produces a precise, auditable failure that the
/// caller has to handle. There are no "unknown" or "soft" errors — every
/// failure has a one-to-one mapping to an ASC 606 / IFRS 15 concept.
#[derive(Debug, Error)]
pub enum Error {
/// A performance obligation referenced by id does not exist on the
/// contract.
#[error("unknown performance obligation: {0}")]
UnknownObligation(String),
/// The sum of standalone selling prices on a contract is zero —
/// allocation by relative SSP is undefined.
#[error("transaction price allocation requires non-zero total SSP")]
ZeroStandaloneSellingPrice,
/// Currency of a performance obligation does not match the contract
/// transaction-price currency.
#[error("currency mismatch between obligation and contract transaction price")]
CurrencyMismatch,
/// Money arithmetic in `op-core` overflowed or otherwise rejected the
/// operation.
#[error("money error: {0}")]
Money(#[from] op_core::Error),
/// Variable-consideration estimate exceeds the constrained ceiling
/// — recognition would book revenue that is not "highly probable"
/// of not reversing (ASC 606-10-32-11).
#[error("variable consideration estimate {estimate} exceeds constraint ceiling {ceiling}")]
VariableConstraintBreached {
/// The unconstrained estimate, in minor units of the contract currency.
estimate: i64,
/// The constraint ceiling, in minor units of the contract currency.
ceiling: i64,
},
/// A refund or reversal exceeds the amount previously recognized.
#[error("refund {refund} exceeds recognized revenue {recognized}")]
RefundExceedsRecognized {
/// Refund amount in minor units.
refund: i64,
/// Previously recognized amount in minor units.
recognized: i64,
},
/// A recognition schedule was asked to produce a period with
/// `end < start`, or zero-length where positive length is required.
#[error("invalid schedule period: start={start}, end={end}")]
InvalidPeriod {
/// Period start (ISO-8601 date).
start: String,
/// Period end (ISO-8601 date).
end: String,
},
/// Contract-modification handling rejected the change.
#[error("contract modification rejected: {0}")]
ModificationRejected(String),
/// FX translation failed because no rate was supplied for the
/// recognition date.
#[error("no FX rate for {from}/{to} on {date}")]
MissingFxRate {
/// Source currency code.
from: String,
/// Target currency code.
to: String,
/// Recognition date (ISO-8601).
date: String,
},
/// Generic invariant violation. Carries a description for the audit
/// trail; reachable only from defensive checks.
#[error("invariant violated: {0}")]
Invariant(String),
}