feat(v2): m009 + models — split fee fractions by direction (#38 1/5)

Adds the schema delta + Pydantic mirror for per-direction fee
configuration:

- super_config gains super_cash_in_fee_fraction / super_cash_out_fee_fraction
  (backfilled from the deprecated singleton on migrate-up so live config
  preserves intent).
- dca_machines gains operator_cash_in_fee_fraction / operator_cash_out_fee_fraction
  (default 0; operator-settable per machine via the upcoming UI).
- dca_settlements gains fee_mismatch_sats BIGINT NULL — Phase-1 observability
  column per coord-log §2026-06-01T07:00Z (lnbits) + option A locked.
- MAX_FEE_FRACTION_PER_DIRECTION = 0.15 lives in calculations.py as the
  single source of truth (defense-in-depth cap, mirrored on the consumer
  side per aiolabs/lamassu-next#57).

Pydantic validators on the new fields keep [0, 1] range checks; the
per-direction cap validation lives on the CRUD path in the next commit
(needs cross-row context: super-config change must validate against all
machines, machine change against current super-config).

Closes one step of #38 (Layer 1 of the operator-configurable fee
architecture, parent #37). Subsequent commits add CRUD, principal-based
split math (fixes the load-bearing super under-payment bug), and the
UI surface.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-06-01 10:18:37 +02:00
commit d87d0db324
3 changed files with 132 additions and 3 deletions

View file

@ -16,6 +16,14 @@ What's intentionally NOT here (deleted 2026-05-26):
from typing import Dict, Tuple
# Per-direction fee cap (super + operator) for any single direction.
# Locked at 15% per coord-log §2026-06-01T07:22Z (bitspire) — defense in
# depth: producer (this side) refuses to publish/persist > cap; consumer
# (bitspire) refuses to apply > cap. See aiolabs/satmachineadmin#37,#38
# and aiolabs/lamassu-next#57.
MAX_FEE_FRACTION_PER_DIRECTION = 0.15
def calculate_distribution(
base_amount_sats: int,
client_balances: Dict[str, float],