# RoyaltyWaterfall 1.0.0 Exact allocation arithmetic on buyer-supplied receipts, costs, opening balances and ordered rules. Outputs are draft statements for customer review. No contract interpretation, rights determination, tax calculation, invoice, sending, recovery of past payments, or money movement occurs. A PASS is a bounded computation, not professional sign-off. Run `python3 product.py samples/valid.json OUTPUT_DIR`; PASS exits 0, invalid FAIL 2 and missing-observation UNKNOWN 3. `bash SMOKE.sh` runs the fixed manager gate. Standard library only. `demo`, `run`, `run_json`, `bundle`, and `files_to_payload` form the browser ABI. CPython acceptance is recorded; actual Pyodide/browser integration must be checked separately. Synthetic examples contain no customer data. ## Exact payload The versioned schema is `royaltywaterfall/v1`. Single-period fields are `schema`, `currency`, `project_id` (default `default`), `period`, `opening_balances` (pool→nonnegative integer minor units), `receipts`, `waterfall`, optional `costs`, `allowed_sources`, `currency_precision`, `rounding_policy`, `residual_policy`, and a plain `note`. Each receipt has unique `event_id`, integer `amount_minor`, `source` (default `receipts`), optional exact `currency`, `period`, `project_id`, and optional `reverses_event_id`. Supplied scope must match the enclosing project/period. Identical duplicate events are idempotent; conflicting duplicates refuse. If `allowed_sources` is supplied, every source must be in it. Missing receipts are UNKNOWN; an observed zero-valued receipt is a known zero. For a batch use `{schema,projects:[{project_id,currency,opening_balances,waterfall,periods:[{period,receipts,costs?}, ...]}]}`. Project IDs and per-project period names are unique. The **period array is explicit chronology**; labels are not dates guessed by the program. Each project has its own currency, pools and event IDs. A failed or unknown earlier period cannot establish a later opening balance. Currency totals are never combined. At most 100 projects, 1,000 periods per project, 100,000 combined receipts, 1,000 nodes/splits, 5 MB JSON, depth 24, integer magnitude 10^15. Rational strings are limited to 64 characters, numerator magnitude 10^15 and denominator 10^12. No float rates, boolean numbers, JSON duplicate keys or nonfinite values. Supported currency precisions: USD/EUR/GBP/CAD/AUD/NZD/CHF=2, JPY=0, KWD=3. Other codes or inconsistent explicit precision refuse. All inputs/outputs use integer minor units; no exchange rates, rounding to decimal display, or tax treatment is inferred. ## Ordered rule program Nodes have unique `id`, `type`, optional integer `priority` (strictly increasing in array order), optional `after` dependency IDs, and the type-specific fields below. Dependencies must be acyclic and precede their node. Array order is the default explicit priority. Arbitrary graph syntax is rejected; this edition is a priority DAG, not a general expression language. Recipient names are data, never paths or code. Reserved recipient `__unallocated__` refuses. - `fee`: `to`, exact rational `rate` within 0..1, `basis` gross or remaining (default remaining). - `recoup`: `to`, `pool`, exact `share` within 0..1 (default 1), basis gross/remaining (default remaining). Pool opening balance is required, and one node owns each pool. Available recoupment is capped by remaining cash and the outstanding pool. **Fractional available recoupment is floored to whole minor units at this node**, keeping carryforward an exact reusable integer. - `tier`: `to`, basis (default gross), `mode` marginal or whole_pot (schema default marginal), `thresholds:[{upto:positive integer,rate:rational},...,{upto:null,rate:rational}]`. Finite thresholds strictly increase; the final open band is required. Marginal applies each rate only to its band; whole_pot applies the containing band's rate to the whole selected basis. Trace and provenance name the policy. - `share`: `splits:[{to,share:rational},...]`, nonnegative shares summing at most 1, basis (default remaining). A gross-basis claim that exceeds remaining funds refuses; it is never silently clamped into fabricated conservation. Fees, tiers and distributions retain exact fractions until each period's final settlement. Largest remainder assigns whole minor units, with recipient ID ascending breaking ties; `__unallocated__` participates as a residual bucket. The only accepted rounding policy is `largest_remainder_recipient_id`, residual policy `unallocated` (both schema defaults). Period boundaries can change rounding and are retained. Every period conserves receipts into recipients plus residual; recoupment is a recipient payment, not an additional amount counted twice. Each optional cost is `{cost_id,amount_minor,recoupment_pool,project_id?,period?,currency?}`. Nonnegative costs increase a pool with an explicitly supplied opening balance before that period. Identical costs deduplicate, conflicting costs refuse; negative costs are unsupported. Costs do not become additional receipt cash. ## Reversals and replay An adjustment may be negative only when `reverses_event_id` names a positive original event and the amount exactly negates it. One full reversal is supported per original; partial, repeated, unreferenced, cross-project and before-original reversals refuse. The engine restates the original receipt to zero and replays all period history and opening balances. The reversal row itself contributes observed zero cash to the restated period. `reversals.csv` records this policy. This produces revised drafts; it does not book a current cash refund or recover offline money already paid. Supply the complete affected history. ## Actual CSV ingestion `files_to_payload` accepts basenames only, each `{encoding:"utf8",content:string}`. A sole `input.json` always supports the exact single/batch schema. Otherwise supply `rules.json` (the payload without receipt/cost rows), plus `receipts.csv` (`revenue.csv` is an exclusive alias). Exact supported headers: `event_id,project_id,period,currency,amount_minor` or the extended form: `event_id,project_id,period,currency,amount_minor,source,reverses_event_id` Amounts are integer text; ordinary CSV quoting is supported. Empty extended reversal references mean none. Optional `costs.csv` uses `cost_id,project_id,period,currency,amount_minor,recoupment_pool`. Optional single-project `opening-state.json` is the pool→integer object and refuses when balances are also in rules. Batch rules carry their own project opening state and ordered period stubs; unknown CSV project/period rows refuse. Rules may contain `csv_mappings` keyed by `receipts.csv`/`costs.csv`: each value maps **every extended canonical header** to one unique source header. Source columns must match that exact mapping order; no ignored extra columns, implicit amounts or executed expressions. This is a reusable explicit rename mapping, not a universal distributor importer. `samples/file-input/` contains actual supported CSV and JSON files. Duplicate headers, ambiguous sets, unknown filenames and paths refuse. ## Package and local review The deterministic ZIP contains exact input/report, SHA256 manifest, rules, inputs manifest, period balances, allocations, exact node trace, carryforward, residuals and reversal evidence. Every recipient gets CSV and escaped HTML under a SHA256-derived opaque filename. Aggregate and per-recipient statements remain drafts. Spreadsheet-leading formulas including whitespace prefixes are neutralized without converting numeric amounts to text formulas. `index.html` is a static local statement viewer using the canonical USTA feeds shell and shared `styles.css`. No customer JavaScript or network executes. The canonical remote Satoshi face is blocked by the offline CSP; a local Satoshi installation or the standard fallback renders instead. Files are individually atomically replaced; two output files are not a transactional filesystem commit. Manifest hashes expose interrupted copy corruption. No customer emails are stored or needed.