feat(v2): record fee_mismatch_sats per settlement, Phase 1 (#38 4/5)
Phase-1 observability per coord-log §2026-06-01T07:00Z (option A locked: always record, no enforce_fee_match gate): fee_mismatch_sats = bitspire_fee_sats - (platform_fee_sats + operator_fee_sats) Positive = bitspire over-reported; negative = under-reported; zero = exact match. Recorded unconditionally on every settlement; WARN- logged via loguru only when |delta| > tolerance, where tolerance = max(1, int(principal_sats * 0.001)) — 1-sat floor with 0.1% relative ceiling. bitspire.py:parse_settlement: - Computes the delta after split_principal_based returns. - WARN log line carries bitspire_fee_sats / expected / delta / tolerance / principal / both fractions / tx_type / machine-npub prefix for triage queries. - Always stamps fee_mismatch_sats onto CreateDcaSettlementData. - Comment explains the pre-Layer-3 expectation: large deltas are expected while the ATM hardcodes 7.77% cash-out (aiolabs/lamassu- next#57); the data here will quiet once Layer 3 ships. crud.py:create_settlement_idempotent: extends the INSERT to persist the new column. Tests: - tests/conftest.py: `loguru_capture` fixture — loguru routes to a pre-bound stderr sink that pytest's caplog (stdlib only) misses and capsys can't see; the fixture adds a list-sink for the test's duration. Reusable for future log-behavior tests. - tests/test_fee_mismatch_recording.py: 8 cases covering exact-match zero delta, bitspire over- and under-reporting, the pre-Layer-3 large-delta scenario, within-tolerance silence, over-tolerance warning, diagnostic-fields presence in the WARN line, and the 1-sat floor on tiny-principal settlements. 164/164 tests green. Phase 2 (reject on out-of-tolerance) lands as a follow-up once observability data justifies the tighter posture. Refs: aiolabs/satmachineadmin#38 (Layer 1), coord-log §2026-06-01T07:00Z (lnbits advisory + option A lock). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
1babdfbf06
commit
d9e8a04b8b
4 changed files with 236 additions and 2 deletions
32
tests/conftest.py
Normal file
32
tests/conftest.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
"""
|
||||
Pytest configuration for the satmachineadmin extension test suite.
|
||||
|
||||
Provides a `loguru_capture` fixture for tests that need to verify
|
||||
loguru WARN/ERROR side-effects. Loguru attaches its default sink to
|
||||
sys.stderr at import time, before pytest's `capsys` wraps stderr, so
|
||||
neither `caplog` (stdlib logging only) nor `capsys` reliably sees
|
||||
loguru output. The fixture adds a list-sink for the test's duration
|
||||
and removes it on teardown.
|
||||
"""
|
||||
|
||||
from typing import Generator, List
|
||||
|
||||
import pytest
|
||||
from loguru import logger
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def loguru_capture() -> Generator[List[str], None, None]:
|
||||
"""Capture loguru log records into a list for the test's duration.
|
||||
|
||||
Usage:
|
||||
def test_warns_on_X(loguru_capture):
|
||||
do_thing_that_warns()
|
||||
assert any("expected message" in msg for msg in loguru_capture)
|
||||
"""
|
||||
captured: List[str] = []
|
||||
handler_id = logger.add(
|
||||
captured.append, level="WARNING", format="{level} {message}"
|
||||
)
|
||||
yield captured
|
||||
logger.remove(handler_id)
|
||||
Loading…
Add table
Add a link
Reference in a new issue